Changeset 540
- Timestamp:
- 08/04/06 18:10:34 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/mokhet/htmlarea.js
r539 r540 73 73 // browser identification 74 74 HTMLArea.agt = navigator.userAgent.toLowerCase(); 75 HTMLArea.is_ie = ((HTMLArea.agt.indexOf("msie") != -1) && (HTMLArea.agt.indexOf("opera") == -1)); 75 //HTMLArea.is_ie = ((HTMLArea.agt.indexOf("msie") != -1) && (HTMLArea.agt.indexOf("opera") == -1)); 76 // it is better to use a conditional comment to detect IE instead of relying on the useragent which can not be trusted 77 HTMLArea.is_ie = false; 78 /*@cc_on HTMLArea.is_ie = true; @*/ 76 79 HTMLArea.is_opera = (HTMLArea.agt.indexOf("opera") != -1); 77 80 HTMLArea.is_mac = (HTMLArea.agt.indexOf("mac") != -1); … … 199 202 panels[i].div = panels[i].container; // legacy 200 203 panels[i].container.className = 'panels ' + i; 201 HTMLArea.freeLater(panels[i], 'container');202 HTMLArea.freeLater(panels[i], 'div');204 // HTMLArea.freeLater(panels[i], 'container'); 205 // HTMLArea.freeLater(panels[i], 'div'); 203 206 } 204 207 // finally store the variable 205 208 this._panels = panels; 206 209 207 HTMLArea.freeLater(this, '_textArea');210 // HTMLArea.freeLater(this, '_textArea'); 208 211 } 209 212 } … … 871 874 toolbar.unselectable = "1"; 872 875 873 HTMLArea.freeLater(this, '_toolBar');874 HTMLArea.freeLater(this, '_toolbar');876 // HTMLArea.freeLater(this, '_toolBar'); 877 // HTMLArea.freeLater(this, '_toolbar'); 875 878 876 879 var tb_row = null; … … 1061 1064 }; 1062 1065 1063 HTMLArea.freeLater(obj);1066 // HTMLArea.freeLater(obj); 1064 1067 1065 1068 tb_objects[txt] = obj; … … 1120 1123 }; 1121 1124 1122 HTMLArea.freeLater(obj);1125 // HTMLArea.freeLater(obj); 1123 1126 1124 1127 tb_objects[txt] = obj; … … 1149 1152 context : btn[4] || null // enabled in a certain context? 1150 1153 }; 1151 HTMLArea.freeLater(el);1152 HTMLArea.freeLater(obj);1154 // HTMLArea.freeLater(el); 1155 // HTMLArea.freeLater(obj); 1153 1156 1154 1157 tb_objects[txt] = obj; … … 1270 1273 { 1271 1274 doc._htmlareaImgCache = {}; 1272 HTMLArea.freeLater(doc._htmlareaImgCache);1275 // HTMLArea.freeLater(doc._htmlareaImgCache); 1273 1276 } 1274 1277 … … 1340 1343 statusbar.className = "statusBar"; 1341 1344 this._statusBar = statusbar; 1342 HTMLArea.freeLater(this, '_statusBar');1345 // HTMLArea.freeLater(this, '_statusBar'); 1343 1346 1344 1347 // statusbar.appendChild(document.createTextNode(HTMLArea._lc("Path") + ": ")); … … 1348 1351 div.innerHTML = HTMLArea._lc("Path") + ": "; 1349 1352 this._statusBarTree = div; 1350 HTMLArea.freeLater(this, '_statusBarTree');1353 // HTMLArea.freeLater(this, '_statusBarTree'); 1351 1354 this._statusBar.appendChild(div); 1352 1355 … … 1355 1358 div.style.display = "none"; 1356 1359 this._statusBarTextMode = div; 1357 HTMLArea.freeLater(this, '_statusBarTextMode');1360 // HTMLArea.freeLater(this, '_statusBarTextMode'); 1358 1361 this._statusBar.appendChild(div); 1359 1362 … … 1473 1476 1474 1477 }; 1475 HTMLArea.freeLater(this._framework);1478 // HTMLArea.freeLater(this._framework); 1476 1479 1477 1480 var fw = this._framework; … … 1520 1523 var htmlarea = this._framework.table; 1521 1524 this._htmlArea = htmlarea; 1522 HTMLArea.freeLater(this, '_htmlArea');1525 // HTMLArea.freeLater(this, '_htmlArea'); 1523 1526 htmlarea.className = "htmlarea"; 1524 1527 … … 1532 1535 this._iframe = iframe; 1533 1536 this._iframe.className = 'xinha_iframe'; 1534 HTMLArea.freeLater(this, '_iframe');1537 // HTMLArea.freeLater(this, '_iframe'); 1535 1538 1536 1539 // creates & appends the status bar … … 2079 2082 } 2080 2083 2081 HTMLArea.freeLater(this, '_doc');2084 // HTMLArea.freeLater(this, '_doc'); 2082 2085 2083 2086 doc.open(); … … 2891 2894 if ( this.config.statusBar && !noStatus ) 2892 2895 { 2893 this.statusBarDispose( );2896 this.statusBarDispose(true); 2894 2897 for ( var i = ancestors.length; --i >= 0; ) 2895 2898 { … … 3156 3159 }; 3157 3160 3158 /**3159 * Dispose the elements in the statusbar3160 * @private3161 */3162 HTMLArea.prototype.statusBarDispose = function()3163 {3164 for ( var i = 0, m = this._statusElements.length; i < m; i++ )3165 {3166 var a = this._statusElements[i];3167 HTMLArea.Events.remove(a, 'click', HTMLArea.onclick_status_updateToolbar);3168 HTMLArea.Events.remove(a, 'contextmenu', HTMLArea.oncontextmenu_status);3169 }3170 this._statusElements = [];3171 this._statusBarTree.innerHTML = HTMLArea._lc("Path") + ": "; // clear3172 };3173 3161 /** Returns a node after which we can insert other nodes, in the current 3174 3162 * selection. The selection is removed. It splits a text node, if needed. … … 5246 5234 } 5247 5235 5248 // event handling 5249 5250 /** Event Flushing 5251 * To try and work around memory leaks in the rather broken 5252 * garbage collector in IE, HTMLArea.flushEvents can be called 5253 * onunload, it will remove any event listeners (that were added 5254 * through _addEvent(s)) and clear any DOM-0 events. 5255 */ 5256 HTMLArea._eventFlushers = []; 5257 HTMLArea.flushEvents = function() 5258 { 5259 var x = 0; 5260 // @todo : check if Array.prototype.pop exists for every supported browsers 5261 var e = HTMLArea._eventFlushers.pop(); 5262 while ( e ) 5263 { 5264 try 5265 { 5266 if ( e.length == 3 ) 5267 { 5268 HTMLArea._removeEvent(e[0], e[1], e[2]); 5269 x++; 5270 } 5271 else if ( e.length == 2 ) 5272 { 5273 e[0]['on' + e[1]] = null; 5274 e[0]._xinha_dom0Events[e[1]] = null; 5275 x++; 5276 } 5277 } 5278 catch(ex) 5279 { 5280 // Do Nothing 5281 } 5282 e = HTMLArea._eventFlushers.pop(); 5283 } 5284 5285 /* 5286 // This code is very agressive, and incredibly slow in IE, so I've disabled it. 5287 5288 if(document.all) 5289 { 5290 for(var i = 0; i < document.all.length; i++) 5291 { 5292 for(var j in document.all[i]) 5293 { 5294 if(/^on/.test(j) && typeof document.all[i][j] == 'function') 5295 { 5296 document.all[i][j] = null; 5297 x++; 5298 } 5299 } 5300 } 5301 } 5302 */ 5303 5304 // alert('Flushed ' + x + ' events.'); 5305 }; 5306 5307 if ( document.addEventListener ) 5308 { 5309 HTMLArea._addEvent = function(el, evname, func) 5310 { 5311 el.addEventListener(evname, func, true); 5312 HTMLArea._eventFlushers.push([el, evname, func]); 5313 }; 5314 HTMLArea._removeEvent = function(el, evname, func) 5315 { 5316 el.removeEventListener(evname, func, true); 5317 }; 5318 HTMLArea._stopEvent = function(ev) 5319 { 5320 ev.preventDefault(); 5321 ev.stopPropagation(); 5322 }; 5323 } 5324 else if ( document.attachEvent ) 5325 { 5326 HTMLArea._addEvent = function(el, evname, func) 5327 { 5328 el.attachEvent("on" + evname, func); 5329 HTMLArea._eventFlushers.push([el, evname, func]); 5330 }; 5331 HTMLArea._removeEvent = function(el, evname, func) 5332 { 5333 el.detachEvent("on" + evname, func); 5334 }; 5335 HTMLArea._stopEvent = function(ev) 5336 { 5337 try 5338 { 5339 ev.cancelBubble = true; 5340 ev.returnValue = false; 5341 } 5342 catch (ex) 5343 { 5344 // Perhaps we could try here to stop the window.event 5345 // window.event.cancelBubble = true; 5346 // window.event.returnValue = false; 5347 } 5348 }; 5349 } 5350 else 5351 { 5352 HTMLArea._addEvent = function(el, evname, func) 5353 { 5354 alert('_addEvent is not supported'); 5355 }; 5356 HTMLArea._removeEvent = function(el, evname, func) 5357 { 5358 alert('_removeEvent is not supported'); 5359 }; 5360 HTMLArea._stopEvent = function(ev) 5361 { 5362 alert('_stopEvent is not supported'); 5363 }; 5364 } 5365 5366 HTMLArea._addEvents = function(el, evs, func) 5367 { 5368 for ( var i = evs.length; --i >= 0; ) 5369 { 5370 HTMLArea._addEvent(el, evs[i], func); 5371 } 5372 }; 5373 5374 HTMLArea._removeEvents = function(el, evs, func) 5375 { 5376 for ( var i = evs.length; --i >= 0; ) 5377 { 5378 HTMLArea._removeEvent(el, evs[i], func); 5379 } 5380 }; 5381 5382 /** 5383 * Adds a standard "DOM-0" event listener to an element. 5384 * The DOM-0 events are those applied directly as attributes to 5385 * an element - eg element.onclick = stuff; 5386 * 5387 * By using this function instead of simply overwriting any existing 5388 * DOM-0 event by the same name on the element it will trigger as well 5389 * as the existing ones. Handlers are triggered one after the other 5390 * in the order they are added. 5391 * 5392 * Remember to return true/false from your handler, this will determine 5393 * whether subsequent handlers will be triggered (ie that the event will 5394 * continue or be canceled). 5395 * 5396 */ 5397 5398 HTMLArea.addDom0Event = function(el, ev, fn) 5399 { 5400 HTMLArea._prepareForDom0Events(el, ev); 5401 el._xinha_dom0Events[ev].unshift(fn); 5402 }; 5403 5404 5405 /** 5406 * See addDom0Event, the difference is that handlers registered using 5407 * prependDom0Event will be triggered before existing DOM-0 events of the 5408 * same name on the same element. 5409 */ 5410 5411 HTMLArea.prependDom0Event = function(el, ev, fn) 5412 { 5413 HTMLArea._prepareForDom0Events(el, ev); 5414 el._xinha_dom0Events[ev].push(fn); 5415 }; 5416 5417 /** 5418 * Prepares an element to receive more than one DOM-0 event handler 5419 * when handlers are added via addDom0Event and prependDom0Event. 5420 */ 5421 HTMLArea._prepareForDom0Events = function(el, ev) 5422 { 5423 // Create a structure to hold our lists of event handlers 5424 if ( typeof el._xinha_dom0Events == 'undefined' ) 5425 { 5426 el._xinha_dom0Events = {}; 5427 HTMLArea.freeLater(el, '_xinha_dom0Events'); 5428 } 5429 5430 // Create a list of handlers for this event type 5431 if ( typeof el._xinha_dom0Events[ev] == 'undefined' ) 5432 { 5433 el._xinha_dom0Events[ev] = [ ]; 5434 if ( typeof el['on'+ev] == 'function' ) 5435 { 5436 el._xinha_dom0Events[ev].push(el['on'+ev]); 5437 } 5438 5439 // Make the actual event handler, which runs through 5440 // each of the handlers in the list and executes them 5441 // in the correct context. 5442 el['on'+ev] = function(event) 5443 { 5444 var a = el._xinha_dom0Events[ev]; 5445 // call previous submit methods if they were there. 5446 var allOK = true; 5447 for ( var i = a.length; --i >= 0; ) 5448 { 5449 // We want the handler to be a member of the form, not the array, so that "this" will work correctly 5450 el._xinha_tempEventHandler = a[i]; 5451 if ( el._xinha_tempEventHandler(event) === false ) 5452 { 5453 el._xinha_tempEventHandler = null; 5454 allOK = false; 5455 break; 5456 } 5457 el._xinha_tempEventHandler = null; 5458 } 5459 return allOK; 5460 }; 5461 5462 HTMLArea._eventFlushers.push([el, ev]); 5463 } 5464 }; 5236 /* 5237 --------------------------------------------------------------------------- 5238 NOTIFIERS 5239 --------------------------------------------------------------------------- 5240 */ 5465 5241 5466 5242 HTMLArea.prototype.notifyOn = function(ev, fn) … … 5469 5245 { 5470 5246 this._notifyListeners[ev] = []; 5471 HTMLArea.freeLater(this, '_notifyListeners');5247 // HTMLArea.freeLater(this, '_notifyListeners'); 5472 5248 } 5473 5249 this._notifyListeners[ev].push(fn); … … 5485 5261 }; 5486 5262 5263 /* 5264 --------------------------------------------------------------------------- 5265 CLASSNAME MANIPULATION 5266 --------------------------------------------------------------------------- 5267 */ 5487 5268 HTMLArea._removeClass = function(el, className) 5488 5269 { … … 5526 5307 return false; 5527 5308 }; 5309 5310 /* 5311 --------------------------------------------------------------------------- 5312 5313 --------------------------------------------------------------------------- 5314 */ 5528 5315 5529 5316 HTMLArea._blockTags = " body form textarea fieldset ul ol dl li div " + … … 6617 6404 HTMLArea.freeLater = function(obj,prop) 6618 6405 { 6619 HTMLArea.toFree.push({o:obj,p:prop});6406 // HTMLArea.toFree.push({o:obj,p:prop}); 6620 6407 }; 6621 6408 … … 6628 6415 HTMLArea.free = function(O, P) 6629 6416 { 6417 /* 6630 6418 if ( O && !P ) 6631 6419 { … … 6652 6440 } catch(x) {} 6653 6441 } 6654 }; 6655 6656 /** IE's Garbage Collector is broken very badly. We will do our best to 6657 * do it's job for it, but we can't be perfect. 6658 */ 6659 6660 HTMLArea.collectGarbageForIE = function() 6661 { 6662 HTMLArea.flushEvents(); 6663 for ( var x = 0; x < HTMLArea.toFree.length; x++ ) 6664 { 6665 if ( !HTMLArea.toFree[x].o ) 6666 { 6667 alert("What is " + x + ' ' + HTMLArea.toFree[x].o); 6668 } 6669 HTMLArea.free(HTMLArea.toFree[x].o, HTMLArea.toFree[x].p); 6670 HTMLArea.toFree[x].o = null; 6671 } 6442 */ 6672 6443 }; 6673 6444 … … 7007 6778 var L, i, m; 7008 6779 7009 // remove ourDOM0 handlers6780 // remove remaining DOM0 handlers 7010 6781 for ( i = 0, m = HTMLArea.Events.DOM0Handlers.length; i < m; i++ ) 7011 6782 { … … 7029 6800 } 7030 6801 } 7031 7032 for ( i = __htmlareas.length; i--; )7033 {7034 // this should be in every Xinha instance disposer method instead of here7035 __htmlareas[i].statusBarDispose();7036 // we should instead do this7037 //__htmlareas[i].dispose();7038 }7039 7040 // garbage IE7041 HTMLArea.collectGarbageForIE();7042 6802 } 7043 6803 … … 7286 7046 7287 7047 7048 /* 7049 --------------------------------------------------------------------------- 7050 HELPERS METHODS 7051 --------------------------------------------------------------------------- 7052 */ 7053 7054 /** 7055 * Get the Xinha reference from the id, the name or the HTMLElement reference of the textarea 7056 * @param {string|HTMLElement} ref The id, the name or the HTMLElement reference of the textarea 7057 * @return {object} Return the Xinha reference or null if none could be found 7058 * @public 7059 */ 7060 HTMLArea.getEditor = function(ref) 7061 { 7062 for ( var i = __htmlareas.length; i--; ) 7063 { 7064 var editor = __htmlareas[i]; 7065 if ( editor && ( editor._textArea.id == ref || editor._textArea.name == ref || editor._textArea == ref ) ) 7066 { 7067 return editor; 7068 } 7069 } 7070 return null; 7071 }; 7072 7073 /* 7074 --------------------------------------------------------------------------- 7075 DISPOSERS 7076 --------------------------------------------------------------------------- 7077 */ 7078 7079 /** 7080 * Specific disposer, similar to _onGenerate. 7081 * But instead of testing if the function exist before calling it, 7082 * we create an empty one and then the user can surcharge it 7083 * @public 7084 */ 7085 HTMLArea.prototype._onDispose = function(){}; 7086 7087 /** 7088 * Dispose the editor UI and bring back the textarea 7089 * @public 7090 */ 7091 HTMLArea.prototype.dispose = function() 7092 { 7093 var i, parentNode, Element; 7094 7095 // specific disposer set by the user 7096 this._onDispose(); 7097 7098 // call the plugins disposer 7099 for ( i in this.plugins ) 7100 { 7101 var plugin = this.plugins[i].instance; 7102 if ( plugin && typeof plugin.dispose == "function" ) 7103 { 7104 plugin.dispose(); 7105 } 7106 } 7107 7108 // remove the events 7109 HTMLArea.Events.remove(this._doc, 'mousedown', this.activateEditor); 7110 HTMLArea.Events.remove(this._doc, ["keydown", "keypress", "mousedown", "mouseup", "drag"], HTMLArea.keymousedrag_doc); 7111 HTMLArea.Events.remove(window, 'resize', this.sizeEditor); 7112 if ( this._textArea.form ) 7113 { 7114 HTMLArea.Events.remove(this._textArea.form, 'submit', HTMLArea.onsubmit_form); 7115 HTMLArea.Events.remove(this._textArea.form, 'reset', HTMLArea.onreset_form); 7116 } 7117 HTMLArea.Events.remove(window, 'unload', HTMLArea.onunload_backforward); 7118 HTMLArea.Events.remove(this._iframe, 'load', HTMLArea.onload_iframe); 7119 7120 // dispose the statusbar 7121 this.statusBarDispose(false); 7122 7123 // remove the panels elements 7124 for ( i in this._panels ) 7125 { 7126 // since they are TD cells, we must show them or they will leak in IE 7127 // but i cant remember where i have found that, so until i find more information, this part is commented out 7128 /* 7129 if ( HTMLArea.is_ie ) 7130 { 7131 this._panels[i].container.style.display = ''; 7132 } 7133 */ 7134 this._panels[i].container = null; 7135 this._panels[i].div = null; 7136 this._panels[i] = null; 7137 } 7138 7139 // remove the iframe 7140 this._iframe.parentNode.removeChild(this._iframe); 7141 this._iframe = null; 7142 7143 // reinsert the textarea in it's original parent 7144 HTMLArea.removeFromParent(this._textArea); 7145 this._framework.table.parentNode.insertBefore(this._textArea, this._framework.table); 7146 7147 // remove the framework 7148 /* 7149 for ( i in this._framework ) 7150 { 7151 Element = this._framework[i]; 7152 parentNode = Element ? Element.parentNode : null; 7153 if ( Element && parentNode ) 7154 { 7155 parentNode.removeChild(Element); 7156 } 7157 this._framework[i] = null; 7158 } 7159 */ 7160 this._framework.table.parentNode.removeChild(this._framework.table); 7161 this._framework = null; 7162 7163 // remove the reference to the document 7164 this._mdoc = null; 7165 7166 // remove the reference to the HTMLElement textarea 7167 // if the original size failed, we fall off to 100px 7168 try { this._textArea.style.width = this._initial_ta_size.w; } catch(x) { this._textArea.style.width = '100px'; } 7169 try { this._textArea.style.height = this._initial_ta_size.h; } catch(x) { this._textArea.style.height = '100px'; } 7170 this._textArea.style.display = ''; 7171 7172 this._textArea = null; 7173 7174 // remove reference in the global array 7175 __htmlareas[this.__htmlarea_id_num] = null; 7176 }; 7177 7178 /** 7179 * Dispose the elements in the statusbar 7180 * @param {boolean} showPath true if "Path: " must be show, false if the content must be emptied 7181 * @private 7182 */ 7183 HTMLArea.prototype.statusBarDispose = function(showPath) 7184 { 7185 for ( var i = this._statusElements.length; i--; ) 7186 { 7187 var a = this._statusElements[i]; 7188 HTMLArea.Events.remove(a, 'click', HTMLArea.onclick_status_updateToolbar); 7189 HTMLArea.Events.remove(a, 'contextmenu', HTMLArea.oncontextmenu_status); 7190 } 7191 this._statusElements = []; 7192 this._statusBarTree.innerHTML = showPath ? HTMLArea._lc("Path") + ": " : ''; // clear 7193 }; 7194 7195 /** 7196 * Generic disposer called onunload. 7197 * @private 7198 */ 7199 HTMLArea.dispose = function() 7200 { 7201 // Remove every Xinha instances 7202 for ( var i = __htmlareas.length; i--; ) 7203 { 7204 if ( __htmlareas[i] ) 7205 { 7206 __htmlareas[i].dispose(); 7207 } 7208 } 7209 // call the event flusher 7210 HTMLArea.Events.flusher(); 7211 }; 7288 7212 7289 7213 /* … … 7293 7217 */ 7294 7218 HTMLArea.init(); 7295 HTMLArea.Events.add(window,'unload',HTMLArea. Events.flusher);7219 HTMLArea.Events.add(window,'unload',HTMLArea.dispose);
Note: See TracChangeset
for help on using the changeset viewer.