Changeset 172
- Timestamp:
- 05/18/05 21:15:06 (8 years ago)
- Location:
- branches/unified_backend
- Files:
-
- 17 modified
-
RELEASE_NOTES.txt (modified) (1 diff)
-
ddt/ddt.js (modified) (4 diffs)
-
ddt/ddt.php (modified) (1 diff)
-
examples/full_example-body.php (modified) (3 diffs)
-
examples/full_example-menu.html (modified) (3 diffs)
-
examples/simple_example.php (modified) (3 diffs)
-
htmlarea.js (modified) (72 diffs)
-
index.html (modified) (2 diffs)
-
plugins/EnterParagraphs/enter-paragraphs.js (modified) (3 diffs)
-
plugins/ImageManager/backend.php (modified) (1 diff)
-
plugins/ImageManager/config.inc.php (modified) (2 diffs)
-
plugins/ImageManager/image-manager.js (modified) (7 diffs)
-
plugins/ImageManager/images.php (modified) (7 diffs)
-
plugins/ImageManager/manager.php (modified) (2 diffs)
-
plugins/Linker/linker.js (modified) (3 diffs)
-
plugins/Linker/scan.php (modified) (1 diff)
-
popups/about.html (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
branches/unified_backend/RELEASE_NOTES.txt
r121 r172 3 3 by: Yermo Lamers of DTLink, LLC 4 4 http://www.formvista.com/contact.html 5 6 --------------------------------------------------------------------- 7 2005-05-17: dev snapshot change summary 8 9 examples/simple_sample.php 10 11 . removed styllist. There is some exception problem I haven't tracked 12 down yet. 13 14 ddt/ddt.js 15 16 . Should now work under MSIE. 17 18 htmlarea.js 19 20 . added workaround fix for NASTY FIREFOX BUG resulting in the infamous 21 uneditable area problem (exception on designMode="on" issue - 22 refer to bug: 23 24 https://bugzilla.mozilla.org/show_bug.cgi?id=207842 25 26 and this thread: 27 28 http://xinha.gogo.co.nz/punbb/viewtopic.php?id=229 29 30 . trailing <BR>'s are no longer stripped out of the document. This 31 was wreaking havoc on EnterParagraphs. It's not clear whether or not 32 this is going to have unanticipated side-effects. 33 34 plugins/EnterParagraphs/enter-paragraphs.js 35 36 NOT FULLY FUNCTIONAL YET - DOESN'T HANDLE ALL CASES CORRECTLY, 37 but it's much better than it was I think. 38 39 . largely reworked. 40 . changed obfuscated variables names to make it more readable. 41 . expanded out nested (x ? y : z) constructs to make it more readable. 42 . added alot of comments. 43 . fixed a serious bug in findEachNodeUnder() that was not correctly 44 handling beginning and end node conditions. 45 . fixed design flaw that selected a non-existent insertion point for 46 placing the cursor. 47 . fixed several exceptions. 48 . now correctly handles lists by passing the back back to the Gecko 49 engine if we are in a list with the exception of being at the 50 first position in the first element in which case we insert 51 a paragraph before the list and move the cursor back to the first 52 item on the list. 53 54 --------------------------------------------------------------------- 55 2005-05-09: dev snapshot change summary 56 57 plugins/linker/scan.php 58 59 . fixed misformed debug message. 5 60 6 61 --------------------------------------------------------------------- -
branches/unified_backend/ddt/ddt.js
r121 r172 52 52 // Error: uncaught exception: Permission denied to get property Window.DDT_STATUS 53 53 // . setting the title of the debug window so you can tell which domain it refers to. 54 // 55 // 2005-05-12 YmL: 56 // . added _ddtDumpNode() to dump node details along with message. 57 // 54 58 // ----------------------------- 59 60 61 62 /** 63 * browser identification 64 */ 65 66 DDT.agt = navigator.userAgent.toLowerCase(); 67 DDT.is_ie = ((DDT.agt.indexOf("msie") != -1) && (DDT.agt.indexOf("opera") == -1)); 68 DDT.is_opera = (DDT.agt.indexOf("opera") != -1); 69 DDT.is_mac = (DDT.agt.indexOf("mac") != -1); 70 DDT.is_mac_ie = (DDT.is_ie && DDT.is_mac); 71 DDT.is_win_ie = (DDT.is_ie && !DDT.is_mac); 72 DDT.is_gecko = (navigator.product == "Gecko"); 55 73 56 74 /** … … 121 139 // 122 140 // We'll just use the hostname here to make the window name unique. 123 124 this.popup = window.open( "", "ddt_popup_" + location.host, 141 // 142 // Something to note, MSIE 6 (at least under win98) throws an exception 143 // if there are any "."'s in the window name, so we replace them with underscores here. 144 145 var window_name = "ddt_popup_" + location.hostname.replace( /[.]/g, "_" ); 146 147 if (DDT.is_gecko) 148 { 149 this.popup = window.open( "", "ddt_popup_" + location.host, 125 150 "toolbar=no,menubar=no,personalbar=no,width=800,height=450," + 126 151 "scrollbars=no,resizable=yes,modal=yes,dependable=yes"); 152 } 153 else 154 { 155 156 this.popup = window.open("", window_name, 157 "toolbar=no,location=no,directories=no,status=no,menubar=no," + 158 "scrollbars=no,resizable=yes,width=800,height=450"); 159 160 } 161 162 // did we manage to open a window? 163 164 if (( typeof this.popup == 'undefined' ) || ( this.popup == null )) 165 { 166 alert( "FAILED TO OPEN DEBUGGING TRACE WINDOW" ); 167 168 return false; 169 } 127 170 128 171 // it's possible that the window was left open or we are another object 129 172 // sharing the same window. 130 173 131 if ( typeof this.popup.DDT_STATUS == 'undefined')174 if (( this.popup != null ) && ( typeof this.popup.DDT_STATUS == 'undefined' )) 132 175 { 133 176 … … 207 250 } 208 251 209 } 252 } // end of _ddt() 253 254 // -------------------------------- 255 256 /** 257 * dumps key properties from a node. 258 */ 259 260 DDT.prototype._ddtDumpNode = function( file, line, msg, node ) 261 { 262 263 if ( typeof node == 'undefined' ) 264 { 265 this._ddt( 266 file, line, msg + " -- Node is undefined!" ); 267 268 return; 269 } 270 271 if ( node == null ) 272 { 273 this._ddt( 274 file, line, msg + " -- Node is null!" ); 275 } 276 277 this._ddt( 278 file, line, msg + "<br>" + this.FragmentToString( node, 0 ) ); 279 280 } // end of _ddtDumpNode() 210 281 211 282 // -------------------------------- … … 255 326 256 327 /** 257 * dumps an object tree258 * 259 * displays a tree of html elements. Design based on method from htmlarea.js328 * generates a string description of a document fragment. 329 * 330 * returns a tree of html elements. Design based on method from htmlarea.js 260 331 * 261 332 * @see ddtpreproc.php 262 * @param root top of tree to display333 * @param root top of tree to generate 263 334 * @param level depth level. 264 335 */ 265 336 266 DDT.prototype. _ddtDumpTree= function(root, level)337 DDT.prototype.FragmentToString = function(root, level) 267 338 { 268 var tag = root.tagName.toLowerCase(), i; 269 var ns = HTMLArea.is_ie ? root.scopeName : root.prefix; 270 271 // FIXME: separated on multiple lines to avoid being picked 272 // up by ddtpreproc.php 273 274 this._ddt( 275 ":","0", level + "- " + tag + " [" + ns + "]" 276 ); 277 278 for (i = root.firstChild; i; i = i.nextSibling) 279 if (i.nodeType == 1) 280 this._ddtDumpTree(i, level + 2); 339 340 var retval = ""; 341 342 if ( typeof root == 'undefined' ) 343 return " root undefined "; 344 345 if ( root == null ) 346 return " root is null "; 347 348 // it may be a mozilla range object: 349 350 if ( typeof root.cloneRange != 'undefined' ) 351 { 352 // we have a range object. 353 354 retval = "RANGE OBJECT - start offset '" + root.startOffset + "' end offset '" + root.endOffset + "'<br>"; 355 retval += "RANGE START:<br>" + this.FragmentToString( root.startContainer, level ); 356 retval += "RANGE END:<br>" + this.FragmentToString( root.endContainer, level ); 357 358 return retval; 359 } 360 361 if ( typeof root.childNodes == 'undefined' ) 362 return " root is not a node"; 363 364 var childretval = ""; 365 366 // interestingly if you do not declare a local var for the iterator 367 // it seems to become a static variable which mucks up the recursion 368 369 var i = 0; 370 371 for (i = 0; i < root.childNodes.length; i++) 372 { 373 childretval += this.FragmentToString( root.childNodes[i], level + 2); 374 } 375 376 retval = this.indent( level ) + this._ddtGetNodeType( root ) + " - " + root.childNodes.length + " children <br>" + childretval; 377 378 return retval; 379 281 380 }; 282 381 382 // ------------------------------------------------- 383 384 /** 385 * indent by level 386 */ 387 388 DDT.prototype.indent = function( level ) 389 { 390 391 var retval = ""; 392 393 for (i = 0; i<level; i++ ) 394 { 395 retval += " "; 396 } 397 398 return retval; 399 400 } 401 // ----------------------------------------- 402 403 /** 404 * displays node type 405 */ 406 407 DDT.prototype._ddtGetNodeType = function( node ) 408 { 409 410 var retval = ""; 411 412 if ( typeof node == 'undefined' ) 413 { 414 return "TYPE_IS_UNDEFINED"; 415 } 416 417 if ( node == null ) 418 { 419 return "TYPE_IS_NULL!"; 420 } 421 422 if ( typeof node.nodeType == 'undefined' ) 423 { 424 return "NOT_A_NODE_OBJECT - type is '" + typeof node + "'"; 425 } 426 427 switch ( node.nodeType ) 428 { 429 430 case 1: 431 retval = "ELEMENT_NODE - tag '" + node.nodeName + "'"; 432 return retval; 433 break; 434 435 case 2: 436 return "ATTRIBUTE_NODE"; 437 break; 438 439 case 3: 440 retval = "TEXT_NODE"; 441 retval = retval + " contents '" + node.nodeValue + "'"; 442 return retval; 443 444 break; 445 446 case 4: 447 return "CDATA_SECTION_NODE"; 448 break; 449 450 case 5: 451 return "ENTITY_REFERENCE_NODE"; 452 break; 453 454 case 6: 455 return "ENTITY_NODE"; 456 break; 457 458 case 7: 459 return "PROCESSING_INSTRUCTION_NODE"; 460 break; 461 462 case 8: 463 return "COMMENT_NODE"; 464 break; 465 466 case 9: 467 return "DOCUMENT_NODE"; 468 break; 469 470 case 10: 471 return "DOCUMENT_TYPE_NODE"; 472 break; 473 474 case 11: 475 retval = "DOCUMENT_FRAGMENT_NODE"; 476 477 return retval; 478 break; 479 480 case 12: 481 return "NOTATION_NODE"; 482 break; 483 484 default: 485 return "UNKNOWN_NODE!"; 486 break; 487 488 } // end of switch 489 490 }; // end of _ddtDumpNode() 491 492 // ---------------------------------------------------------- 493 494 /** 495 * getHTMLSource() - returns HTML source for display in a browser window. 496 */ 497 498 DDT.prototype.getHTMLSource = function( html ) 499 { 500 501 html = html.replace( /</ig, "<" ); 502 html = html.replace( />/ig, ">" ); 503 html = html.replace( /&/ig, "&" ); 504 html = html.replace(/\xA0/g, " "); 505 html = html.replace(/\x22/g, """); 506 507 return html; 508 509 } // end of showHTML() 510 283 511 // END 284 512 -
branches/unified_backend/ddt/ddt.php
r121 r172 89 89 } 90 90 91 f puts( $fvDEBUG[ "logfile_fp" ], "$msgline");91 fwrite( $fvDEBUG[ "logfile_fp" ], $msgline ); 92 92 fflush( $fvDEBUG[ "logfile_fp" ] ); 93 93 -
branches/unified_backend/examples/full_example-body.php
r121 r172 180 180 } 181 181 182 window.onload = xinha_init; 182 // calling xinha_init twice can cause a nasty little exception. 183 // window.onload = xinha_init; 184 183 185 </script> 184 186 </head> … … 204 206 ---------------------------------------------------------------------------> 205 207 206 <div id="lipsum" style="display:none"> 208 <div id="lipsum" style="display:none"><h1>TEST</h1></div> 209 210 <div id="lipsumx" style="display:none"> 207 211 <p>This is an example of a Xinha editor with extensive trace messages 208 212 turned on. To turn off trace messages, assuming you have the source, just … … 228 232 file from the Xinha_ub branch.</p> 229 233 </div> 234 230 235 <script src="full_example.js"></script> 231 236 -
branches/unified_backend/examples/full_example-menu.html
r121 r172 37 37 <legend>Plugins</legend> 38 38 <label> 39 <input type="checkbox" name="plugins" value="EnterParagraphs" /> EnterParagraphs 40 </label> 41 <label> 39 42 <input type="checkbox" name="plugins" value="CSS" /> CSS 40 43 </label> … … 46 49 </label> 47 50 <label> 48 <input type="checkbox" name="plugins" value="FullScreen" checked/> FullScreen51 <input type="checkbox" name="plugins" value="FullScreen" /> FullScreen 49 52 </label> 50 53 <label> 51 <input type="checkbox" name="plugins" value="CharacterMap" checked/> CharacterMap54 <input type="checkbox" name="plugins" value="CharacterMap" /> CharacterMap 52 55 </label> 53 56 <label> … … 55 58 </label> 56 59 <label> 57 <input type="checkbox" name="plugins" value="ListType" checked/> ListType60 <input type="checkbox" name="plugins" value="ListType" /> ListType 58 61 </label> 59 62 60 63 <label> 61 <input type="checkbox" name="plugins" value="Stylist" checked/> Stylist64 <input type="checkbox" name="plugins" value="Stylist" /> Stylist 62 65 </label> 63 66 64 67 <label> 65 <input type="checkbox" name="plugins" value="TableOperations" checked/> TableOperations68 <input type="checkbox" name="plugins" value="TableOperations" /> TableOperations 66 69 </label> 67 70 68 71 <label> 69 <input type="checkbox" name="plugins" value="InsertAnchor" checked/> InsertAnchor72 <input type="checkbox" name="plugins" value="InsertAnchor" /> InsertAnchor 70 73 </label> 71 74 </fieldset> -
branches/unified_backend/examples/simple_example.php
r121 r172 30 30 // eg: _editor_url = "../"; 31 31 // in this example we do a little regular expression to find the absolute path. 32 _editor_url = document.location.href.replace(/examples\/simple_example\. html.*/, '')32 _editor_url = document.location.href.replace(/examples\/simple_example\.php.*/, '') 33 33 _editor_lang = "en"; // And the language we need to use in the editor. 34 34 </script> … … 190 190 191 191 <textarea id="TextArea1" name="TextArea1" rows="10" cols="80" style="width:100%"> 192 This is the content of TextArea1 from xinha_ub/examples/simple_example. html.<br>192 This is the content of TextArea1 from xinha_ub/examples/simple_example.php.<br> 193 193 In order to see the new debugging trace messages you will need to turn off 194 194 popup blockers for this site.<br> … … 196 196 commenting out or uncomments the _ddtOn() line. The same applies to the trace 197 197 messages inside the HTMLArea object in htmlarea.js. 198 The version of EnterParagraphs in this editor should be largely fixed. If you notice 199 any problems please report them in the forums. 198 200 </textarea> 199 201 -
branches/unified_backend/htmlarea.js
r121 r172 273 273 * 274 274 * set to 'built-in', 'dirty' or 'best' 275 * built-in: will (may) use 'br' instead of 'p' tags 275 * built-in: will (may) use 'br' instead of 'p' tags (passes it off to the brower builtin handler) 276 276 * dirty : will use p and work good enough for the majority of cases, 277 277 * best : works the best, but it's about 12kb worth of javascript … … 280 280 */ 281 281 282 this.mozParaHandler = 'b est';282 this.mozParaHandler = 'built-in'; 283 283 284 284 /** … … 2139 2139 /** 2140 2140 * getHTMLWrapper() 2141 * 2142 * Called, for instance, when switching from wysiwyg to text mode. 2141 2143 */ 2142 2144 … … 2190 2192 var i; 2191 2193 var root_tag = (root.nodeType == 1) ? root.tagName.toLowerCase() : ''; 2194 2195 // removes br tags from the end of root level. 2196 2197 /* yml: Temporarily disabling. 2198 2192 2199 if (root_tag == 'br' && !root.nextSibling) 2200 { 2201 HTMLArea._ddt( "htmlarea.js","2146", "getHTMLWrapper(): skipping (removing) terminating root level BR tag." ); 2193 2202 break; 2203 } 2204 */ 2194 2205 2195 2206 if (outputRoot) 2207 { 2196 2208 outputRoot = !(editor.config.htmlRemoveTags && editor.config.htmlRemoveTags.test(root_tag)); 2209 } 2197 2210 2198 2211 if (HTMLArea.is_ie && root_tag == "head") 2199 {2212 { 2200 2213 if (outputRoot) 2214 { 2201 2215 html += "<head>"; 2216 } 2217 2202 2218 // lowercasize 2219 2203 2220 var save_multiline = RegExp.multiline; 2204 2221 RegExp.multiline = true; 2205 var txt = root.innerHTML.replace(HTMLArea.RE_tagName, function(str, p1, p2) 2206 { 2207 return p1 + p2.toLowerCase(); 2208 }); 2222 var txt = root.innerHTML.replace(HTMLArea.RE_tagName, 2223 function(str, p1, p2) 2224 { 2225 return p1 + p2.toLowerCase(); 2226 }); 2209 2227 2210 2228 RegExp.multiline = save_multiline; 2211 2229 html += txt; 2230 2212 2231 if (outputRoot) 2232 { 2213 2233 html += "</head>"; 2234 } 2235 2214 2236 break; 2215 2237 } … … 2220 2242 var attrs = root.attributes; 2221 2243 for (i = 0; i < attrs.length; ++i) 2222 {2244 { 2223 2245 var a = attrs.item(i); 2224 2246 if (!a.specified) 2225 {2247 { 2226 2248 continue; 2227 2249 } … … 2229 2251 var name = a.nodeName.toLowerCase(); 2230 2252 if (/_moz_editor_bogus_node/.test(name)) 2231 {2253 { 2232 2254 html = ""; 2233 2255 break; … … 2243 2265 2244 2266 if (name != "style") 2245 {2267 { 2246 2268 2247 2269 // IE5.5 reports 25 when cellSpacing is … … 2257 2279 2258 2280 if (typeof root[a.nodeName] != "undefined" && name != "href" && name != "src" && !/^on/.test(name)) 2259 {2281 { 2260 2282 value = root[a.nodeName]; 2261 2283 } 2262 else2263 {2284 else 2285 { 2264 2286 value = a.nodeValue; 2265 2287 … … 2269 2291 2270 2292 if (HTMLArea.is_ie && (name == "href" || name == "src")) 2271 { 2293 { 2294 2295 HTMLArea._ddt( "htmlarea.js", "2292", "getHTMLWrapper(): because we are ie and have an href or src attribute we are calling stripBaseUrl" ); 2296 2272 2297 value = editor.stripBaseURL(value); 2273 2298 } 2274 2299 } 2275 2300 } 2276 else2277 {2301 else 2302 { 2278 2303 2279 // IE fails to put style in attributes list2304 // IE fails to put style in attributes list 2280 2305 // FIXME: cssText reported by IE is UPPERCASE 2281 2306 … … 2284 2309 2285 2310 if (/^(_moz)?$/.test(value)) 2286 {2311 { 2287 2312 // Mozilla reports some special tags 2288 2313 // here; we don't need them. … … 2295 2320 2296 2321 if (html != "") 2297 {2322 { 2298 2323 html += closed ? " />" : ">"; 2299 2324 } … … 2302 2327 2303 2328 for (i = root.firstChild; i; i = i.nextSibling) 2304 {2329 { 2305 2330 html += HTMLArea.getHTMLWrapper(i, true, editor); 2306 2331 } 2307 2332 2308 2333 if (outputRoot && !closed) 2309 {2334 { 2310 2335 html += "</" + root.tagName.toLowerCase() + ">"; 2311 2336 } … … 3084 3109 3085 3110 obj.swapImage = function(newimg) 3086 {3087 if(typeof newimg != 'string')3088 {3089 img.src = newimg[0];3090 img.style.position = 'relative';3091 img.style.top = newimg[2] ? ('-' + (18 * (newimg[2] + 1)) + 'px') : '-18px';3092 img.style.left = newimg[1] ? ('-' + (18 * (newimg[1] + 1)) + 'px') : '-18px';3093 }3094 else3095 {3096 obj.imgel.src = newimg;3097 img.style.top = '0px';3098 img.style.left = '0px';3099 }3100 } 3111 { 3112 if(typeof newimg != 'string') 3113 { 3114 img.src = newimg[0]; 3115 img.style.position = 'relative'; 3116 img.style.top = newimg[2] ? ('-' + (18 * (newimg[2] + 1)) + 'px') : '-18px'; 3117 img.style.left = newimg[1] ? ('-' + (18 * (newimg[1] + 1)) + 'px') : '-18px'; 3118 } 3119 else 3120 { 3121 obj.imgel.src = newimg; 3122 img.style.top = '0px'; 3123 img.style.left = '0px'; 3124 } 3125 } // end of function definition. 3101 3126 3102 3127 } … … 3209 3234 */ 3210 3235 3211 HTMLArea.prototype.generate = function ()3236 HTMLArea.prototype.generate = function() 3212 3237 { 3213 3238 3214 3239 this.ddt._ddt( "htmlarea.js","3214", "generate(): top" ); 3215 3240 3216 var editor = this; // we'll need "this" in some nested functions 3241 // we need "this" in some nested functions (i.e. closures) so a local 3242 // variable is used to "transmit" it to the enclosed function. Weird 3243 // javascript enclosure concept. 3244 3245 var editor = this; 3217 3246 3218 3247 // If this is gecko, set up the paragraph handling now … … 3227 3256 { 3228 3257 3229 this.ddt._ddt( "htmlarea.js","3229", "generate(): mozParaHandler config set to 'best'. Loading EnterParagraphs" );3258 this.ddt._ddt( "htmlarea.js","3229", "generate(): mozParaHandler config set to 'best'. Loading EnterParagraphs" ); 3230 3259 3231 3260 EnterParagraphs = 'null'; 3232 HTMLArea._loadback 3233 (_editor_url + 'plugins/EnterParagraphs/enter-paragraphs.js', function() { editor.registerPlugin('EnterParagraphs'); editor.generate(); } ); 3261 HTMLArea._loadback(_editor_url + 'plugins/EnterParagraphs/enter-paragraphs.js', 3262 function() 3263 { 3264 editor.generate(); 3265 return true; 3266 } ); 3267 3234 3268 return false; 3269 3235 3270 } 3271 3272 editor.registerPlugin(eval('EnterParagraphs')); 3273 3236 3274 } 3237 3275 … … 3342 3380 { 3343 3381 3344 this.ddt._ddt( "htmlarea.js","3344", "generate(): f.onsubmit(): top" );3382 this.ddt._ddt( "htmlarea.js","3344", "generate(): f.onsubmit(): top" ); 3345 3383 3346 3384 var a = this.__msh_prevOnSubmit; … … 3459 3497 this.notifyOn('panel_change',function(){editor.setInnerSize();}); 3460 3498 3461 this.ddt._ddt( "htmlarea.js","3461", "generate(): bottom before timeout call to initIframe()" ); 3462 3463 // IMPORTANT: we have to allow Mozilla a short time to recognize the 3464 // new frame. Otherwise we get a stupid exception. 3465 3466 setTimeout(function() { editor.initIframe()}, 50); 3499 this.ddt._ddt( "htmlarea.js","3461", "generate(): bottom before event call to initIframe()" ); 3500 3501 // instead of using a timeout which by definition produces an occassional race condition 3502 // depending on performance, we tie calling initFrame to the frame being completely 3503 // loaded. 3504 // 3505 // See: 3506 // 3507 // https://bugzilla.mozilla.org/show_bug.cgi?id=207842 3508 // 3509 // notably the link to: 3510 // 3511 // http://derekdev.com/mozilla/iframeworky.html 3512 // 3513 // So far I can't seem to get this EventListener to "turn off" but this does 3514 // seem to fix the exceptions problem we've been seeing and it's alot 3515 // cleaner than "waiting". Under some circumstances I'm noticing quite a long 3516 // delay here depending on how long FireFox has been running. 3517 3518 if ( HTMLArea.is_gecko ) 3519 { 3520 3521 // need to get a var into the closure below. 3522 3523 editor.isGenerated = false; 3524 3525 this._iframe.addEventListener("load", 3526 function(e) 3527 { 3528 3529 if ( !editor.isGenerated ) 3530 { 3531 editor.isGenerated = true; 3532 editor.initIframe(); 3533 } 3534 3535 return true; 3536 3537 }, 3538 false); 3539 } 3540 else 3541 { 3542 3543 // MSIE uses a different method to attach events. MSIE does not 3544 // suffer from the bug which forces us to wait for the iFrame in 3545 // firefox but it seems like a good idea to do it the same way 3546 // instead of calling initframe directly. Both seem to work equally 3547 // as well ... 3548 3549 this._iframe.attachEvent("onload", 3550 function(e) 3551 { 3552 3553 if ( !editor.isGenerated ) 3554 { 3555 editor.isGenerated = true; 3556 editor.initIframe(); 3557 } 3558 3559 return true; 3560 3561 }); 3562 } 3563 3564 return true; 3467 3565 3468 3566 }; // end of HTMLArea.prototype.generate() … … 3488 3586 3489 3587 if (!doc) 3490 {3588 { 3491 3589 // Try again.. 3492 3590 // FIXME: don't know what else to do here. Normally … … 3494 3592 3495 3593 if (HTMLArea.is_gecko) 3496 {3594 { 3497 3595 setTimeout(function() { editor.initIframe()}, 50); 3498 3596 return false; 3499 3597 } 3500 else3501 {3598 else 3599 { 3502 3600 alert("ERROR: IFRAME can't be initialized."); 3503 3601 } … … 3506 3604 catch(e) 3507 3605 { 3606 3607 alert("EXCEPTION: couldn't get doc in initFrame - delaying and returning."); 3608 3508 3609 setTimeout(function() { editor.initIframe()}, 50); 3610 3611 return false; 3509 3612 } 3510 3613 … … 3516 3619 html += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=" + editor.config.charSet + "\">\n"; 3517 3620 3518 if (typeof editor.config.baseHref != 'undefined' && editor.config.baseHref != null)3621 if ( typeof editor.config.baseHref != 'undefined' && editor.config.baseHref != null) 3519 3622 { 3520 3623 html += "<base href=\"" + editor.config.baseHref + "\"/>\n"; … … 3552 3655 { 3553 3656 var html = editor.inwardHtml(editor._textArea.value); 3657 3554 3658 if (html.match(HTMLArea.RE_doctype)) 3555 {3659 { 3556 3660 editor.setDoctype(RegExp.$1); 3557 3661 html = html.replace(HTMLArea.RE_doctype, ""); 3558 3662 } 3663 3559 3664 doc.open(); 3560 3665 doc.write(html); … … 3907 4012 { 3908 4013 3909 try{HTMLArea.last_on.designMode = 'off';} catch(e) { } 4014 // if this is the first time here last_on has not been set so this will 4015 // generate an exception. 4016 4017 try 4018 { 4019 HTMLArea.last_on.designMode = 'off'; 4020 } 4021 catch(e) 4022 { 4023 this.ddt._ddt( "htmlarea.js","3904", "activateEditor(): exception trying to set last_on.designMode to off. First time here?" ); 4024 } 3910 4025 3911 4026 this.ddt._ddt( "htmlarea.js","3911", "activateEditor(): _iframe.style.display is '" + this._iframe.style.display + "'" ); 3912 4027 3913 if (this._iframe.style.display == 'none')4028 if ( this._iframe.style.display == 'none' ) 3914 4029 { 3915 4030 this._iframe.style.display = ''; … … 3919 4034 else 3920 4035 { 3921 3922 this.ddt._ddt( "htmlarea.js","3922", "activateEditor(): setting designMode to on" ); 3923 3924 this._doc.designMode = 'on'; 3925 } 3926 } 3927 else 3928 { 3929 3930 this.ddt._ddt( "htmlarea.js","3930", "activateEditor(): Setting contentEditable to true" ); 4036 this.ddt._ddt( "htmlarea.js","3922", "activateEditor(): setting designMode to on" ); 4037 4038 // under FireFox we're endlessly getting exceptions here. 4039 4040 try 4041 { 4042 this._doc.designMode = 'on'; 4043 } 4044 catch( e ) 4045 { 4046 alert( "EXCEPTION - failed to turn design mode on in activateEditor() - " + e + "'" ); 4047 } 4048 } 4049 } 4050 else if ( HTMLArea.is_ie ) 4051 { 4052 4053 this.ddt._ddt( "htmlarea.js","3930", "activateEditor(): Setting contentEditable to true" ); 3931 4054 3932 4055 this._doc.body.contentEditable = true; 3933 4056 } 4057 else 4058 { 4059 this.ddt._ddt( "htmlarea.js","3930", "activateEditor(): UNHANDLED CASE." ); 4060 4061 // alert( "INTERNAL ERROR - activateEditor - unhandled case" ); 4062 } 3934 4063 3935 4064 HTMLArea.last_on = this._doc; … … 3973 4102 { 3974 4103 4104 if (typeof mode == "undefined") 4105 { 4106 mode = ((this._editMode == "textmode") ? "wysiwyg" : "textmode"); 4107 } 4108 3975 4109 this.ddt._ddt( "htmlarea.js","3975", "setMode(): setting mode to '" + mode + "'" ); 3976 4110 3977 if (typeof mode == "undefined")3978 {3979 mode = ((this._editMode == "textmode") ? "wysiwyg" : "textmode");3980 }3981 3982 4111 switch (mode) 3983 4112 { 3984 4113 case "textmode": 3985 4114 { 4115 3986 4116 var html = this.outwardHtml(this.getHTML()); 3987 4117 this._textArea.value = html; 4118 4119 this.ddt._ddt( "htmlarea.js", "3986", "setMode(): textmode. called getHTML composed into outwardHTML and set the textarea value. html set was '" + this.ddt.getHTMLSource(html) + "'" ); 3988 4120 3989 4121 // Hide the iframe … … 4002 4134 case "wysiwyg": 4003 4135 { 4136 4137 this.ddt._ddt( "htmlarea.js", "3986", "setMode(): textmode. calling getHTML composed into inwardHTML and setting the innerHTML or fullpage value." ); 4138 4004 4139 var html = this.inwardHtml(this.getHTML()); 4005 4140 this.deactivateEditor(); … … 4007 4142 { 4008 4143 this._doc.body.innerHTML = html; 4144 4145 this.ddt._ddtDumpNode( "htmlarea.js", "3986", "setMode(): wysiwyg. after setting innerHTML body contents are:", this._doc.body ); 4146 4009 4147 } 4010 4148 else … … 4012 4150 this.setFullHTML(html); 4013 4151 } 4152 4014 4153 this._iframe.style.display = ''; 4015 4154 this._textArea.style.display = "none"; … … 4036 4175 // this.focusEditor(); 4037 4176 4177 this.ddt._ddt( "htmlarea.js", "4044", "setMode(): informing any plugins that interested of the mode change" ); 4178 4038 4179 for (var i in this.plugins) 4039 4180 { 4040 4181 var plugin = this.plugins[i].instance; 4041 if (typeof plugin.onMode == "function") plugin.onMode(mode); 4182 if (typeof plugin.onMode == "function") 4183 { 4184 this.ddt._ddt( "htmlarea.js", "4044", "setMode(): calling onMode in plugin '" + plugin.name + "'" ); 4185 plugin.onMode(mode); 4186 } 4042 4187 } 4043 4188 }; // end of setMode() … … 4099 4244 { 4100 4245 4101 this.ddt._ddt( "htmlarea.js","4101", "registerPlugin(): top" );4102 4103 4246 var plugin = arguments[0]; 4247 4248 this.ddt._ddt( "htmlarea.js","4101", "registerPlugin(): top with plugin '" + plugin + "'" ); 4249 4104 4250 var args = []; 4105 4251 for (var i = 1; i < arguments.length; ++i) … … 4108 4254 return this.registerPlugin2(plugin, args); 4109 4255 }; 4256 4257 // ----------------------------------------------------------------- 4110 4258 4111 4259 /** … … 4124 4272 4125 4273 if (typeof plugin == "string") 4274 { 4275 this.ddt._ddt( "htmlarea.js","4123", "registerPlugin2(): plugin '" + plugin + "' is a string." ); 4126 4276 plugin = eval(plugin); 4127 4128 if (typeof plugin == "undefined") 4129 { 4130 4131 this.ddt._ddt( "htmlarea.js","4131", "registerPlugin2(): INTERNAL ERROR: plugin is undefined. " ); 4277 } 4278 4279 if ((typeof plugin == "undefined") || ( plugin == null )) 4280 { 4281 4282 this.ddt._ddt( "htmlarea.js","4131", "registerPlugin2(): INTERNAL ERROR: plugin is undefined. " ); 4132 4283 4133 4284 /* FIXME: This should never happen. But why does it do? */ … … 4135 4286 } 4136 4287 4137 var obj = new plugin(this, args); 4288 // FIXME: in the multiple editor on a page case we sometimes get a null plugin 4289 // here ... why? 4290 4291 try 4292 { 4293 var obj = new plugin(this, args); 4294 4295 this.ddt._ddt( "htmlarea.js","4131", "registerPlugin2(): after successfully creating the plugin. " ); 4296 4297 } 4298 catch(e) 4299 { 4300 this.ddt._ddt( "htmlarea.js","4131", "registerPlugin2(): unable to create the plugin. '" + e + "'" ); 4301 4302 alert( "INTERNAL ERROR - registerPlugin2(): UNABLE TO CONSTRUCT PLUGIN '" + plugin + "' - '" + e + "'" ); 4303 4304 return false; 4305 } 4138 4306 4139 4307 if (obj) … … 4151 4319 } 4152 4320 else 4321 { 4153 4322 alert("Can't register plugin " + plugin.toString() + "."); 4323 } 4154 4324 4155 4325 }; // end of registerPlugin2 … … 4419 4589 // We don't want to focus the field unless at least one field has been activated. 4420 4590 4421 if (HTMLArea.last_on)4591 if ( HTMLArea.last_on ) 4422 4592 { 4423 4593 this.activateEditor(); … … 4583 4753 ancestors = this.getAllAncestors(); 4584 4754 if (this.config.statusBar && !noStatus) 4585 {4755 { 4586 4756 this._statusBarTree.innerHTML = HTMLArea._lc("Path") + ": "; // clear 4587 4757 for (var i = ancestors.length; --i >= 0;) 4588 {4758 { 4589 4759 var el = ancestors[i]; 4590 4760 if (!el) 4591 {4592 4593 this.ddt._ddt( "htmlarea.js","4593", "updateToolbar(): INTERNAL ERROR" );4761 { 4762 4763 this.ddt._ddt( "htmlarea.js","4593", "updateToolbar(): INTERNAL ERROR" ); 4594 4764 4595 4765 // hell knows why we get here; this … … 4606 4776 4607 4777 a.onclick = function() 4608 {4609 this.blur();4610 this.editor.selectNodeContents(this.el);4611 this.editor.updateToolbar(true);4612 return false;4613 };4778 { 4779 this.blur(); 4780 this.editor.selectNodeContents(this.el); 4781 this.editor.updateToolbar(true); 4782 return false; 4783 }; 4614 4784 4615 4785 a.oncontextmenu = function() 4616 {4617 4618 // TODO: add context menu here4619 4620 this.blur();4621 var info = "Inline style:\n\n";4622 info += this.el.style.cssText.split(/;\s*/).join(";\n");4623 alert(info);4624 return false;4625 };4786 { 4787 4788 // TODO: add context menu here 4789 4790 this.blur(); 4791 var info = "Inline style:\n\n"; 4792 info += this.el.style.cssText.split(/;\s*/).join(";\n"); 4793 alert(info); 4794 return false; 4795 }; 4626 4796 4627 4797 var txt = el.tagName.toLowerCase(); 4628 4798 a.title = el.style.cssText; 4629 4799 if (el.id) 4630 {4800 { 4631 4801 txt += "#" + el.id; 4632 4802 } 4633 4803 4634 4804 if (el.className) 4635 {4805 { 4636 4806 txt += "." + el.className; 4637 4807 } … … 4640 4810 this._statusBarTree.appendChild(a); 4641 4811 if (i != 0) 4642 {4812 { 4643 4813 this._statusBarTree.appendChild(document.createTextNode(String.fromCharCode(0xbb))); 4644 4814 } … … 4655 4825 4656 4826 if (btn.context && !text) 4657 {4827 { 4658 4828 inContext = false; 4659 4829 var context = btn.context; … … 4661 4831 4662 4832 if (/(.*)\[(.*?)\]/.test(context)) 4663 {4833 { 4664 4834 context = RegExp.$1; 4665 4835 attrs = RegExp.$2.split(","); … … 4669 4839 var match = (context == "*"); 4670 4840 for (var k = 0; k < ancestors.length; ++k) 4671 {4841 { 4672 4842 if (!ancestors[k]) 4673 {4674 4675 this.ddt._ddt( "htmlarea.js","4675", "updateToolbar(): INTERNAL ERROR" );4843 { 4844 4845 this.ddt._ddt( "htmlarea.js","4675", "updateToolbar(): INTERNAL ERROR" ); 4676 4846 4677 4847 // the impossible really happens. … … 4680 4850 4681 4851 if (match || (ancestors[k].tagName.toLowerCase() == context)) 4682 {4852 { 4683 4853 inContext = true; 4684 4854 for (var ka = 0; ka < attrs.length; ++ka) 4685 {4855 { 4686 4856 if (!eval("ancestors[k]." + attrs[ka])) 4687 {4857 { 4688 4858 inContext = false; 4689 4859 break; … … 4692 4862 4693 4863 if (inContext) 4694 {4864 { 4695 4865 break; 4696 4866 } … … 4701 4871 btn.state("enabled", (!text || btn.text) && inContext); 4702 4872 if (typeof cmd == "function") 4703 {4873 { 4704 4874 continue; 4705 4875 } … … 4709 4879 var dropdown = this.config.customSelects[cmd]; 4710 4880 if ((!text || btn.text) && (typeof dropdown != "undefined")) 4711 {4881 { 4712 4882 dropdown.refresh(this); 4713 4883 continue; … … 4720 4890 { 4721 4891 if (!text) try 4722 {4892 { 4723 4893 var value = ("" + doc.queryCommandValue(cmd)).toLowerCase(); 4724 4894 4725 4895 if (!value) 4726 {4896 { 4727 4897 btn.element.selectedIndex = 0; 4728 4898 break; … … 4747 4917 } 4748 4918 btn.element.selectedIndex = 0; 4749 } catch(e) {}; 4919 } 4920 catch(e) 4921 {}; 4750 4922 } 4751 break; 4923 4924 break; 4752 4925 4753 4926 // It's better to search for the format block by tag name from the … … 4784 4957 case "textindicator": 4785 4958 if (!text) 4786 { 4787 try {with (btn.element.style) 4788 { 4789 backgroundColor = HTMLArea._makeColor( 4790 doc.queryCommandValue(HTMLArea.is_ie ? "backcolor" : "hilitecolor")); 4791 4792 if (/transparent/i.test(backgroundColor)) 4793 { 4794 // Mozilla 4795 backgroundColor = HTMLArea._makeColor(doc.queryCommandValue("backcolor")); 4796 } 4797 4798 color = HTMLArea._makeColor(doc.queryCommandValue("forecolor")); 4799 fontFamily = doc.queryCommandValue("fontname"); 4800 fontWeight = doc.queryCommandState("bold") ? "bold" : "normal"; 4801 fontStyle = doc.queryCommandState("italic") ? "italic" : "normal"; 4802 }} catch (e) 4803 { 4959 { 4960 try 4961 { 4962 with (btn.element.style) 4963 { 4964 backgroundColor = HTMLArea._makeColor( 4965 doc.queryCommandValue(HTMLArea.is_ie ? "backcolor" : "hilitecolor")); 4966 4967 if (/transparent/i.test(backgroundColor)) 4968 { 4969 // Mozilla 4970 backgroundColor = HTMLArea._makeColor(doc.queryCommandValue("backcolor")); 4971 } 4972 4973 color = HTMLArea._makeColor(doc.queryCommandValue("forecolor")); 4974 fontFamily = doc.queryCommandValue("fontname"); 4975 fontWeight = doc.queryCommandState("bold") ? "bold" : "normal"; 4976 fontStyle = doc.queryCommandState("italic") ? "italic" : "normal"; 4977 } 4978 } 4979 catch (e) 4980 { 4804 4981 // alert(e + "\n\n" + cmd); 4805 4982 } … … 4807 4984 break; 4808 4985 4809 case "htmlmode": btn.state("active", text); break; 4986 case "htmlmode": 4987 4988 btn.state("active", text); 4989 break; 4990 4810 4991 case "lefttoright": 4811 4992 case "righttoleft": … … 4822 5003 cmd = cmd.replace(/(un)?orderedlist/i, "insert$1orderedlist"); 4823 5004 try 4824 {5005 { 4825 5006 btn.state("active", (!text && doc.queryCommandState(cmd))); 4826 } catch (e) {} 4827 } 5007 } 5008 catch (e) 5009 {} 5010 5011 break; 5012 5013 } // end of switch 4828 5014 4829 5015 } // end of for loop over toolbar objects … … 4836 5022 var editor = this; 4837 5023 this._timerUndo = setTimeout(function() 4838 {5024 { 4839 5025 editor._timerUndo = null; 4840 5026 }, this.config.undoTimeout); … … 5754 5940 5755 5941 this._popupDialog(editor.config.URIs["insert_image"], function(param) 5756 {5942 { 5757 5943 if (!param) 5758 { // user must have pressed Cancel5944 { // user must have pressed Cancel 5759 5945 return false; 5760 5946 } 5761 5947 5762 5948 var img = image; 5949 5763 5950 if (!img) 5764 {5951 { 5765 5952 var sel = editor._getSelection(); 5766 5953 var range = editor._createRange(sel); 5954 5767 5955 editor._doc.execCommand("insertimage", false, param.f_url); 5956 5768 5957 if (HTMLArea.is_ie) 5769 {5958 { 5770 5959 img = range.parentElement(); 5960 5771 5961 // wonder if this works... 5962 5772 5963 if (img.tagName.toLowerCase() != "img") 5773 {5774 img = img.previousSibling;5964 { 5965 img = img.previousSibling; 5775 5966 } 5776 5967 } 5777 else5778 {5968 else 5969 { 5779 5970 img = range.startContainer.previousSibling; 5780 5971 } 5781 5972 } 5782 else5783 {5973 else 5974 { 5784 5975 img.src = param.f_url; 5785 5976 } 5786 5977 5787 for (var field in param)5788 {5978 for (var field in param) 5979 { 5789 5980 var value = param[field]; 5790 5981 switch (field) … … 5954 6145 switch (cmdID) 5955 6146 { 5956 case "htmlmode" : this.setMode(); break; 6147 case "htmlmode" : 6148 6149 this.ddt._ddtDumpNode( "htmlarea.js", "5978", "execCommand(): htmlmode command. Switching modes. Current document is:", this._doc.body ); 6150 this.setMode(); 6151 6152 this.ddt._ddtDumpNode( "htmlarea.js", "5978", "execCommand(): htmlmode command. after switch. Document is:", this._doc.body ); 6153 6154 break; 6155 5957 6156 case "hilitecolor": 5958 6157 (HTMLArea.is_ie) && (cmdID = "backcolor"); … … 5962 6161 { 5963 6162 if (color) 5964 { // selection not canceled6163 { // selection not canceled 5965 6164 editor._doc.execCommand(cmdID, false, "#" + color); 5966 6165 } … … 5977 6176 var win; 5978 6177 if (HTMLArea.is_ie) 5979 {6178 { 5980 6179 { 5981 6180 win = window.open(this.popupURL(editor.config.URIs["fullscreen"]), "ha_fullscreen", 5982 6181 "toolbar=no,location=no,directories=no,status=no,menubar=no," + 5983 6182 "scrollbars=no,resizable=yes,width=640,height=480"); 5984 }6183 } 5985 6184 } 5986 else5987 {6185 else 6186 { 5988 6187 win = window.open(this.popupURL(editor.config.URIs["fullscreen"]), "ha_fullscreen", 5989 6188 "toolbar=no,menubar=no,personalbar=no,width=640,height=480," + 5990 6189 "scrollbars=no,resizable=yes"); 5991 6190 } 6191 5992 6192 win.focus() 5993 6193 … … 6013 6213 case "paste": 6014 6214 try 6015 {6215 { 6016 6216 this._doc.execCommand(cmdID, UI, param); 6017 6217 if (this.config.killWordOnPaste) 6018 6218 this._wordClean(); 6019 6219 } 6020 catch (e)6021 {6022 if (HTMLArea.is_gecko)6023 {6024 alert(HTMLArea._lc("The Paste button does not work in Mozilla based web browsers (technical security reasons). Press CTRL-V on your keyboard to paste directly."));6025 }6026 }6220 catch (e) 6221 { 6222 if (HTMLArea.is_gecko) 6223 { 6224 alert(HTMLArea._lc("The Paste button does not work in Mozilla based web browsers (technical security reasons). Press CTRL-V on your keyboard to paste directly.")); 6225 } 6226 } 6027 6227 break; 6028 6228 … … 6036 6236 6037 6237 if (el) 6038 {6238 { 6039 6239 if (el.style.direction == dir) 6040 6240 el.style.direction = ""; … … 6046 6246 6047 6247 default: 6048 try 6049 { 6050 this._doc.execCommand(cmdID, UI, param); 6051 } 6248 6249 this.ddt._ddt( "htmlarea.js","6119", "execCommand(): passing '" + cmdID + "' to internal browser command handler." ); 6250 6251 try 6252 { 6253 this._doc.execCommand(cmdID, UI, param); 6254 } 6052 6255 catch(e) 6053 {6054 if (this.config.debug) { alert(e + "\n\nby execCommand(" + cmdID + ");"); }6055 }6256 { 6257 if (this.config.debug) { alert(e + "\n\nby execCommand(" + cmdID + ");"); } 6258 } 6056 6259 6057 6260 } // end of switch. … … 6066 6269 6067 6270 /** 6068 * _edito Event()6271 * _editorEvent() 6069 6272 * 6070 6273 * A generic event handler for things that happen in the IFRAME's document. … … 6097 6300 } 6098 6301 6099 if (keyEvent)6100 {6302 if (keyEvent) 6303 { 6101 6304 6102 6305 this.ddt._ddt( "htmlarea.js","6102", "_editorEvent(): keyEvent" ); 6103 6306 6104 // loop over all the plugins and pass this event to any that have6105 // an onKeyPress() method.6307 // loop over all the plugins and pass this event to any that have 6308 // an onKeyPress() method. 6106 6309 6107 6310 for (var i in editor.plugins) … … 6109 6312 var plugin = editor.plugins[i].instance; 6110 6313 6111 // to make it easier to figure out what kind of object we're talking to 6112 // I've added a name member. This change has not yet been applied to 6113 // all plugins. 6114 6115 this.ddt._ddtDumpObject( "htmlarea.js","5994", "_editorEvent(): plugin '" + ( plugin.name ? plugin.name : "unknown" ) + "' has members:", plugin ); 6314 // to make it easier to figure out what kind of object we're talking to 6315 // I've added a name member. This change has not yet been applied to 6316 // all plugins. 6317 6318 // this.ddt._ddtDumpObject( "htmlarea.js","5994", "_editorEvent(): plugin '" + ( plugin.name ? plugin.name : "unknown" ) + "' has members:", plugin ); 6319 6320 this.ddt._ddt( "htmlarea.js","5994", "_editorEvent(): plugin '" + ( plugin.name ? plugin.name : "unknown" ) + "'" ); 6116 6321 6117 6322 if (typeof plugin.onKeyPress == "function") 6118 {6119 6120 this.ddt._ddt( "htmlarea.js","6120", "_editorEvent(): keyEvent - invoking onKeyPress method in plugin '" + ( plugin.name ? plugin.name : "unknown" ) + "'" );6323 { 6324 6325 this.ddt._ddt( "htmlarea.js","6120", "_editorEvent(): keyEvent - invoking onKeyPress method in plugin '" + ( plugin.name ? plugin.name : "unknown" ) + "'" ); 6121 6326 6122 6327 if (plugin.onKeyPress(ev)) 6123 6328 { 6124 6329 6125 this.ddt._ddt( "htmlarea.js","6125", "_editorEvent(): keyEvent - onKeyPress() returned false. Returning false" );6330 this.ddt._ddt( "htmlarea.js","6125", "_editorEvent(): keyEvent - onKeyPress() returned false. Returning false" ); 6126 6331 return false; 6127 }6332 } 6128 6333 6129 6334 } // end of if this plugin had a KeyPress handler. … … 6328 6533 { 6329 6534 6330 this.ddt._ddt( "htmlarea.js","6330", "_editorEvent(): entered a space" );6535 this.ddt._ddt( "htmlarea.js","6330", "_editorEvent(): entered a space" ); 6331 6536 6332 6537 if(s && s.isCollapsed && s.anchorNode.nodeType == 3 && s.anchorNode.data.length > 3 && s.anchorNode.data.indexOf('.') >= 0) … … 6371 6576 { 6372 6577 6373 this.ddt._ddt( "htmlarea.js","6373", "_editorEvent(): keycode is '" + ev.keyCode + "' which (normal key) is '" + ev.which + "'" );6374 6375 // is it an escape character or ...6578 this.ddt._ddt( "htmlarea.js","6373", "_editorEvent(): keycode is '" + ev.keyCode + "' which (normal key) is '" + ev.which + "'" ); 6579 6580 // is it an escape character or ... 6376 6581 6377 6582 if(ev.keyCode == 27 || (this._unlinkOnUndo && ev.ctrlKey && ev.which == 122) ) … … 6387 6592 { 6388 6593 6389 // backspace or period?6594 // backspace or period? 6390 6595 6391 6596 this.ddt._ddt( "htmlarea.js","6391", "_editorEvent(): normal key or backspace or period" ); … … 6395 6600 if(s.anchorNode && s.anchorNode.nodeType == 3) 6396 6601 { 6602 6397 6603 // See if we might be changing a link 6398 6604 var a = this._getFirstAncestor(s, 'a'); 6399 6605 6400 6606 if (!a) 6401 {6402 this.ddt._ddt( "htmlarea.js","6402", "_editorEvent(): not an anchor" );6403 break; // not an anchor6404 }6607 { 6608 this.ddt._ddt( "htmlarea.js","6402", "_editorEvent(): not an anchor" ); 6609 break; // not an anchor 6610 } 6405 6611 6406 6612 if(!a._updateAnchTimeout) … … 6450 6656 case 13: // KEY enter 6451 6657 6452 this.ddt._ddt( "htmlarea.js","6452", "_editorEvent(): enter key handling" );6658 this.ddt._ddt( "htmlarea.js","6452", "_editorEvent(): enter key handling" ); 6453 6659 6454 6660 if (HTMLArea.is_gecko && !ev.shiftKey && this.config.mozParaHandler == 'dirty' ) … … 6462 6668 case 46: // KEY delete 6463 6669 6464 this.ddt._ddt( "htmlarea.js","6464", "_editorEvent(): delete or backspace handling" );6670 this.ddt._ddt( "htmlarea.js","6464", "_editorEvent(): delete or backspace handling" ); 6465 6671 6466 6672 if (HTMLArea.is_gecko && !ev.shiftKey) 6467 {6673 { 6468 6674 if (this.dom_checkBackspace()) 6469 6675 HTMLArea._stopEvent(ev); 6470 6676 } 6471 else if (HTMLArea.is_ie)6472 {6677 else if (HTMLArea.is_ie) 6678 { 6473 6679 if (this.ie_checkBackspace()) 6474 6680 HTMLArea._stopEvent(ev); 6475 6681 } 6476 6682 break; 6683 6477 6684 } // end of switch 6478 6685 } … … 6609 6816 6610 6817 // Get the insertion point, we'll scrub any highlighted text the user wants rid of while we are there. 6818 6611 6819 var sel = this._getSelection(); 6612 6820 var range = this._createRange(sel); … … 6615 6823 { 6616 6824 range.deleteContents(); 6617 } 6618 6825 } 6619 6826 this.deactivateEditor(); 6620 6827 … … 6858 7065 case "wysiwyg" : 6859 7066 { 7067 6860 7068 if (!this.config.fullPage) 7069 { 6861 7070 html = HTMLArea.getHTML(this._doc.body, false, this); 7071 } 6862 7072 else 7073 { 6863 7074 html = this.doctype + "\n" + HTMLArea.getHTML(this._doc.documentElement, true, this); 7075 } 7076 6864 7077 break; 6865 7078 } … … 7234 7447 HTMLArea.prototype._getSelection = function() 7235 7448 { 7449 7450 this.ddt._ddt( "htmlarea.js", "7242", "_getSelection(): top" ); 7451 7236 7452 if (HTMLArea.is_ie) 7237 7453 { … … 7263 7479 else 7264 7480 { 7481 7265 7482 this.activateEditor(); 7483 7266 7484 if (typeof sel != "undefined") 7267 {7485 { 7268 7486 try 7269 { 7487 { 7488 7489 this.ddt._ddt( "htmlarea.js","7277", "_createRange(): attempting to create a range using getRangeAt(0) on current selection." ); 7270 7490 return sel.getRangeAt(0); 7271 7491 } 7272 catch(e) 7273 { 7492 catch(e) 7493 { 7494 this.ddt._ddt( "htmlarea.js","7282", "_createRange(): getRangeAt(0) failed, using createRange" ); 7274 7495 return this._doc.createRange(); 7275 7496 } 7276 7497 } 7277 7498 else 7278 { 7499 { 7500 this.ddt._ddt( "htmlarea.js","7292", "_createRange(): creating a new range." ); 7501 7279 7502 return this._doc.createRange(); 7280 7503 } -
branches/unified_backend/index.html
r124 r172 66 66 67 67 </p> 68 <h2>Unified Backend Branch - snapshot of 2005-0 4-24</h2>68 <h2>Unified Backend Branch - snapshot of 2005-05-17</h2> 69 69 70 70 <p> … … 101 101 <ul><li><a href="./docs/index.html">Programmers Documentation</a></li></ul> 102 102 103 <h2>Status - only partially functional.</h2>103 <h2>Status - core is now mostly functional.</h2> 104 104 <ul> 105 <li>Debug trace messages included in htmlarea.js .</li>105 <li>Debug trace messages included in htmlarea.js, linker, imagemanager and enterparagraphs </li> 106 106 <li>Beginnings of code-generated documentation using JSDoc and PHPDoc.</li> 107 107 <li>Beginnings of Configure.php to set up server side environment.</li> 108 108 <li>devutils/ directory containing various scripts</li> 109 <li>EnterParagraphs should now largely work</li> 109 110 </ul> 110 111 111 112 <h2>TODO</h2> 112 113 <ul> 113 <li>The unified backend.</li>114 114 <li>JSDoc/PHPDoc headers in all plugins</li> 115 <li>trace messages in plugins</li>116 <li>debug trace message panel - to turn trace messages on/off on a plugin by plugin basis</li>117 115 <li>buildruntime.php script to strip out comments and trace messages</li> 118 <li>fix enterparagraph</li>119 116 </ul> 120 117 -
branches/unified_backend/plugins/EnterParagraphs/enter-paragraphs.js
r84 r172 1 // By Adam Wright, for The University of Western Australia 2 // 3 // Distributed under the same terms as HTMLArea itself. 4 // This notice MUST stay intact for use (see license.txt). 5 6 function EnterParagraphs(editor) { 7 this.editor = editor; 8 // Activate only if we're talking to Gecko 9 if (HTMLArea.is_gecko) 10 this.onKeyPress = this.__onKeyPress; 11 }; 12 13 EnterParagraphs._pluginInfo = { 1 // tabs 2 2 3 /** 4 * @fileoverview By Adam Wright, for The University of Western Australia 5 * 6 * Distributed under the same terms as HTMLArea itself. 7 * This notice MUST stay intact for use (see license.txt). 8 * 9 * Heavily modified by Yermo Lamers of DTLink, LLC, College Park, Md., USA. 10 * For more info see http://www.areaedit.com 11 */ 12 13 /** 14 * plugin Info 15 */ 16 17 EnterParagraphs._pluginInfo = 18 { 14 19 name : "EnterParagraphs", 15 20 version : "1.0", … … 19 24 sponsor_url : "http://www.uwa.edu.au/", 20 25 license : "htmlArea" 21 }; 26 }; 27 28 // ------------------------------------------------------------------ 29 30 // "constants" 31 32 /** 33 * Whitespace Regex 34 */ 35 36 EnterParagraphs.prototype._whiteSpace = /^\s*$/; 37 38 /** 39 * The pragmatic list of which elements a paragraph may not contain 40 */ 41 42 EnterParagraphs.prototype._pExclusions = /^(address|blockquote|body|dd|div|dl|dt|fieldset|form|h1|h2|h3|h4|h5|h6|hr|li|noscript|ol|p|pre|table|ul)$/i; 43 44 /** 45 * elements which may contain a paragraph 46 */ 47 48 EnterParagraphs.prototype._pContainers = /^(body|del|div|fieldset|form|ins|map|noscript|object|td|th)$/i; 49 50 /** 51 * Elements which may not contain paragraphs, and would prefer a break to being split 52 */ 53 54 EnterParagraphs.prototype._pBreak = /^(address|pre|blockquote)$/i; 55 56 /** 57 * Elements which may not contain children 58 */ 59 60 EnterParagraphs.prototype._permEmpty = /^(area|base|basefont|br|col|frame|hr|img|input|isindex|link|meta|param)$/i; 61 62 /** 63 * Elements which count as content, as distinct from whitespace or containers 64 */ 65 66 EnterParagraphs.prototype._elemSolid = /^(applet|br|button|hr|img|input|table)$/i; 67 68 /** 69 * Elements which should get a new P, before or after, when enter is pressed at either end 70 */ 71 72 EnterParagraphs.prototype._pifySibling = /^(address|blockquote|del|div|dl|fieldset|form|h1|h2|h3|h4|h5|h6|hr|ins|map|noscript|object|ol|p|pre|table|ul|)$/i; 73 EnterParagraphs.prototype._pifyForced = /^(ul|ol|dl|table)$/i; 74 75 /** 76 * Elements which should get a new P, before or after a close parent, when enter is pressed at either end 77 */ 78 79 EnterParagraphs.prototype._pifyParent = /^(dd|dt|li|td|th|tr)$/i; 80 81 // --------------------------------------------------------------------- 82 83 /** 84 * EnterParagraphs Constructor 85 */ 86 87 function EnterParagraphs(editor) 88 { 89 90 this.editor = editor; 91 92 // [STRIP 93 // create a ddt debug trace object. There may be multiple editors on 94 // the page each EnterParagraphs .. to distinguish which instance 95 // is generating the message we tack on the name of the textarea. 96 97 this.ddt = new DDT( editor._textArea + ":EnterParagraphs Plugin" ); 98 99 // uncomment to turn on debugging messages. 100 101 this.ddt._ddtOn(); 102 103 this.ddt._ddt( "enter-paragraphs.js","23", "EnterParagraphs(): constructor" ); 104 105 // STRIP] 106 107 // hook into the event handler to intercept key presses if we are using 108 // gecko (Mozilla/FireFox) 109 110 if (HTMLArea.is_gecko) 111 { 112 this.ddt._ddt( "enter-paragraphs.js","23", "EnterParagraphs(): we are gecko. Setting event handler." ); 113 this.onKeyPress = this.__onKeyPress; 114 } 115 116 }; // end of constructor. 117 118 // ------------------------------------------------------------------ 22 119 23 120 /** … … 30 127 EnterParagraphs.prototype.name = "EnterParagraphs"; 31 128 32 // Whitespace Regex 33 EnterParagraphs.prototype._whiteSpace = /^\s*$/; 34 // The pragmatic list of which elements a paragraph may not contain, and which may contain a paragraph 35 EnterParagraphs.prototype._pExclusions = /^(address|blockquote|body|dd|div|dl|dt|fieldset|form|h1|h2|h3|h4|h5|h6|hr|li|noscript|ol|p|pre|table|ul)$/i; 36 EnterParagraphs.prototype._pContainers = /^(body|del|div|fieldset|form|ins|map|noscript|object|td|th)$/i; 37 // Elements which may not contain paragraphs, and would prefer a break to being split 38 EnterParagraphs.prototype._pBreak = /^(address|pre|blockquote)$/i; 39 // Elements which may not contain children 40 EnterParagraphs.prototype._permEmpty = /^(area|base|basefont|br|col|frame|hr|img|input|isindex|link|meta|param)$/i; 41 // Elements which count as content, as distinct from whitespace or containers 42 EnterParagraphs.prototype._elemSolid = /^(applet|br|button|hr|img|input|table)$/i; 43 // Elements which should get a new P, before or after, when enter is pressed at either end 44 EnterParagraphs.prototype._pifySibling = /^(address|blockquote|del|div|dl|fieldset|form|h1|h2|h3|h4|h5|h6|hr|ins|map|noscript|object|ol|p|pre|table|ul|)$/i; 45 EnterParagraphs.prototype._pifyForced = /^(ul|ol|dl|table)$/i; 46 // Elements which should get a new P, before or after a close parent, when enter is pressed at either end 47 EnterParagraphs.prototype._pifyParent = /^(dd|dt|li|td|th|tr)$/i; 48 49 // Gecko's a bit lacking in some odd ways... 50 EnterParagraphs.prototype.insertAdjacentElement = function(ref,pos,el) { 51 52 if ( pos == 'BeforeBegin' ) ref.parentNode.insertBefore(el,ref); 53 else if ( pos == 'AfterEnd' ) ref.nextSibling ? ref.parentNode.insertBefore(el,ref.nextSibling) : ref.parentNode.appendChild(el); 54 else if ( pos == 'AfterBegin' && ref.firstChild ) ref.insertBefore(el,ref.firstChild); 55 else if ( pos == 'BeforeEnd' || pos == 'AfterBegin' ) ref.appendChild(el); 56 }; 57 58 // Passes a global parent node or document fragment to forEachNode 59 EnterParagraphs.prototype.forEachNodeUnder = function (top, fn, ltr, init, parm) { 129 /** 130 * Gecko's a bit lacking in some odd ways... 131 */ 132 133 EnterParagraphs.prototype.insertAdjacentElement = function(ref,pos,el) 134 { 135 136 this.ddt._ddtDumpNode( "enter-paragraphs.js", "122", "insertAdjacentElement(): top with pos '" + pos + "' ref:", ref ); 137 this.ddt._ddtDumpNode( "enter-paragraphs.js", "122", "insertAdjacentElement(): top with el:", el ); 138 139 if ( pos == 'BeforeBegin' ) 140 { 141 ref.parentNode.insertBefore(el,ref); 142 } 143 else if ( pos == 'AfterEnd' ) 144 { 145 ref.nextSibling ? ref.parentNode.insertBefore(el,ref.nextSibling) : ref.parentNode.appendChild(el); 146 } 147 else if ( pos == 'AfterBegin' && ref.firstChild ) 148 { 149 ref.insertBefore(el,ref.firstChild); 150 } 151 else if ( pos == 'BeforeEnd' || pos == 'AfterBegin' ) 152 { 153 ref.appendChild(el); 154 } 155 156 this.ddt._ddtDumpNode( "enter-paragraphs.js", "122", "insertAdjacentElement(): bottom with ref:", ref ); 157 158 }; // end of insertAdjacentElement() 159 160 // ---------------------------------------------------------------- 161 162 /** 163 * Passes a global parent node or document fragment to forEachNode 164 * 165 * @param root node root node to start search from. 166 * @param mode string function to apply to each node. 167 * @param direction string traversal direction "ltr" (left to right) or "rtl" (right_to_left) 168 * @param init boolean 169 */ 170 171 EnterParagraphs.prototype.forEachNodeUnder = function ( root, mode, direction, init ) 172 { 173 174 this.ddt._ddtDumpNode( "enter-paragraphs.js", "144", "forEachNodeUnder(): top mode is '" + mode + "' direction is '" + direction + "' starting with root node:", root ); 60 175 61 176 // Identify the first and last nodes to deal with 177 62 178 var start, end; 63 if ( top.nodeType == 11 && top.firstChild ) { 64 start = top.firstChild; 65 end = top.lastChild; 66 } else start = end = top; 67 while ( end.lastChild ) end = end.lastChild; 68 69 // Pass onto forEachNode 70 return this.forEachNode(start, end, fn, ltr, init, parm); 71 }; 72 73 // Throws each node into a function 74 EnterParagraphs.prototype.forEachNode = function (left, right, fn, ltr, init, parm) { 75 76 var xBro = function(elem, ltr) { return ( ltr ? elem.nextSibling : elem.previousSibling ); }; 77 var xSon = function(elem, ltr) { return ( ltr ? elem.firstChild : elem.lastChild ); }; 78 var walk, lookup, fnVal, ping = init; 79 80 // Until we've hit the last node 81 while ( walk != ltr ? right : left ) { 82 83 // Progress to the next node 84 if ( !walk ) walk = ltr ? left : right; 85 else { 86 if ( xSon(walk,ltr) ) walk = xSon(walk,ltr); 87 else { 88 if ( xBro(walk,ltr) ) walk = xBro(walk,ltr); 89 else { 179 180 // nodeType 11 is DOCUMENT_FRAGMENT_NODE which is a container. 181 182 if ( root.nodeType == 11 && root.firstChild ) 183 { 184 start = root.firstChild; 185 end = root.lastChild; 186 } 187 else 188 { 189 start = end = root; 190 } 191 192 this.ddt._ddtDumpNode( "enter-paragraphs.js", "144", "forEachNodeUnder(): start node is:", start ); 193 this.ddt._ddtDumpNode( "enter-paragraphs.js", "144", "forEachNodeUnder(): initial end node is:", end ); 194 195 // traverse down the right hand side of the tree getting the last child of the last 196 // child in each level until we reach bottom. 197 while ( end.lastChild ) 198 end = end.lastChild; 199 200 this.ddt._ddtDumpNode( "enter-paragraphs.js", "144", "forEachNodeUnder(): end node after descent is:", end ); 201 202 return this.forEachNode( start, end, mode, direction, init); 203 204 }; // end of forEachNodeUnder() 205 206 // ----------------------------------------------------------------------- 207 208 /** 209 * perform a depth first descent in the direction requested. 210 * 211 * @param left_node node "start node" 212 * @param right_node node "end node" 213 * @param mode string function to apply to each node. cullids or emptyset. 214 * @param direction string traversal direction "ltr" (left to right) or "rtl" (right_to_left) 215 * @param init boolean or object. 216 */ 217 218 EnterParagraphs.prototype.forEachNode = function (left_node, right_node, mode, direction, init) 219 { 220 221 this.ddt._ddt( "enter-paragraphs.js", "175", "forEachNode(): top - mode is:" + mode + "' direction '" + direction + "'" ); 222 this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode(): top - left node is:", left_node ); 223 this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode(): top - right node is:", right_node ); 224 225 // returns "Brother" node either left or right. 226 227 var getSibling = function(elem, direction) 228 { 229 return ( direction == "ltr" ? elem.nextSibling : elem.previousSibling ); 230 }; 231 232 var getChild = function(elem, direction) 233 { 234 return ( direction == "ltr" ? elem.firstChild : elem.lastChild ); 235 }; 236 237 var walk, lookup, fnReturnVal; 238 239 // FIXME: init is a boolean in the emptyset case and an object in 240 // the cullids case. Used inconsistently. 241 242 var next_node = init; 243 244 // used to flag having reached the last node. 245 246 var done_flag = false; 247 248 // loop ntil we've hit the last node in the given direction. 249 // if we're going left to right that's the right_node and visa-versa. 250 251 while ( walk != direction == "ltr" ? right_node : left_node ) 252 { 253 254 // on first entry, walk here is null. So this is how 255 // we prime the loop with the first node. 256 257 if ( !walk ) 258 { 259 walk = direction == "ltr" ? left_node : right_node; 260 261 this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode(): !walk - current node is:", walk ); 262 } 263 else 264 { 265 266 // is there a child node? 267 268 if ( getChild(walk,direction) ) 269 { 270 271 // descend down into the child. 272 273 walk = getChild(walk,direction); 274 275 this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode():descending to child node:", walk ); 276 277 } 278 else 279 { 280 281 // is there a sibling node on this level? 282 283 if ( getSibling(walk,direction) ) 284 { 285 286 // move to the sibling. 287 288 walk = getSibling(walk,direction); 289 290 this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode(): moving to sibling node:", walk ); 291 292 } 293 else 294 { 90 295 lookup = walk; 91 while ( !xBro(lookup,ltr) && lookup != (ltr ? right : left) ) lookup = lookup.parentNode; 92 walk = ( lookup.nextSibling ? lookup.nextSibling : lookup ) ; 93 if ( walk == right ) break; 94 } } } 95 96 fnVal = fn(this, walk, ping, parm, (walk==(ltr?right:left))); // Throw this node at the wanted function 97 if ( fnVal[0] ) return fnVal[1]; // If this node wants us to return, return pong 98 if ( fnVal[1] ) ping = fnVal[1]; // Otherwise, set pong to ping, to pass to the next node 99 } 296 297 // climb back up the tree until we find a level where we are not the end 298 // node on the level (i.e. that we have a sibling in the direction 299 // we are searching) or until we reach the end. 300 301 while ( !getSibling(lookup,direction) && lookup != (direction == "ltr" ? right_node : left_node) ) 302 { 303 lookup = lookup.parentNode; 304 } 305 306 // did we find a level with a sibling? 307 308 // walk = ( lookup.nextSibling ? lookup.nextSibling : lookup ) ; 309 310 walk = ( getSibling(lookup,direction) ? getSibling(lookup,direction) : lookup ) ; 311 312 this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode(): climbed back up (or found right node):", walk ); 313 314 } 315 } 316 317 } // end of else walk. 318 319 // have we reached the end? either as a result of the top while loop or climbing 320 // back out above. 321 322 done_flag = (walk==( direction == "ltr" ? right_node : left_node)); 323 324 // call the requested function on the current node. Functions 325 // return an array. 326 // 327 // Possible functions are _fenCullIds, _fenEmptySet 328 // 329 // The situation is complicated by the fact that sometimes we want to 330 // return the base node and sometimes we do not. 331 // 332 // next_node can be an object (this.takenIds), a node (text, el, etc) or false. 333 334 this.ddt._ddt( "enter-paragraphs.js", "175", "forEachNode(): calling function" ); 335 336 switch( mode ) 337 { 338 339 case "cullids": 340 341 fnReturnVal = this._fenCullIds(walk, next_node ); 342 break; 343 344 case "find_fill": 345 346 fnReturnVal = this._fenEmptySet(walk, next_node, mode, done_flag); 347 break; 348 349 case "find_cursorpoint": 350 351 fnReturnVal = this._fenEmptySet(walk, next_node, mode, done_flag); 352 break; 353 354 } 355 356 // If this node wants us to return, return next_node 357 358 if ( fnReturnVal[0] ) 359 { 360 this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode(): returning node:", fnReturnVal[1] ); 361 362 return fnReturnVal[1]; 363 } 364 365 // are we done with the loop? 366 367 if ( done_flag ) 368 { 369 break; 370 } 371 372 // Otherwise, pass to the next node 373 374 if ( fnReturnVal[1] ) 375 { 376 next_node = fnReturnVal[1]; 377 } 378 379 } // end of while loop 380 381 this.ddt._ddt( "enter-paragraphs.js", "175", "forEachNode(): returning false." ); 382 100 383 return false; 101 }; 102 103 // forEachNode fn: Find a post-insertion node, only if all nodes are empty, or the first content 104 EnterParagraphs.prototype._fenEmptySet = function (parent, node, pong, getCont, last) { 384 385 }; // end of forEachNode() 386 387 // ------------------------------------------------------------------- 388 389 /** 390 * Find a post-insertion node, only if all nodes are empty, or the first content 391 * 392 * @param node node current node beinge examined. 393 * @param next_node node next node to be examined. 394 * @param node string "find_fill" or "find_cursorpoint" 395 * @param last_flag boolean is this the last node? 396 */ 397 398 EnterParagraphs.prototype._fenEmptySet = function( node, next_node, mode, last_flag) 399 { 400 401 this.ddt._ddtDumpNode( "enter-paragraphs.js", "263", "_fenEmptySet() : top with mode '" + mode + "' and last_flag '" + last_flag + "' and node:", node ); 105 402 106 403 // Mark this if it's the first base 107 if ( !pong && !node.firstChild ) pong = node; 108 109 // Check for content 110 if ( (node.nodeType == 1 && parent._elemSolid.test(node.nodeName)) || 111 (node.nodeType == 3 && !parent._whiteSpace.test(node.nodeValue)) || 112 (node.nodeType != 1 && node.nodeType != 3) ) { 113 114 return new Array(true, (getCont?node:false)); 115 } 116 117 // Only return the 'base' node if we didn't want content 118 if ( last && !getCont ) return new Array(true, pong); 119 return new Array(false, pong); 120 }; 121 122 // forEachNode fn: 123 EnterParagraphs.prototype._fenCullIds = function (parent, node, pong, parm, last) { 404 405 if ( !next_node && !node.firstChild ) 406 { 407 next_node = node; 408 } 409 410 // Is it an element node and is it considered content? (br, hr, etc) 411 // or is it a text node that is not just whitespace? 412 // or is it not an element node and not a text node? 413 414 if ( (node.nodeType == 1 && this._elemSolid.test(node.nodeName)) || 415 (node.nodeType == 3 && !this._whiteSpace.test(node.nodeValue)) || 416 (node.nodeType != 1 && node.nodeType != 3) ) 417 { 418 419 this.ddt._ddtDumpNode( "enter-paragraphs.js", "263", "_fenEmptySet() : found content in node:", node ); 420 421 switch( mode ) 422 { 423 424 case "find_fill": 425 426 // does not return content. 427 428 return new Array(true, false ); 429 breal; 430 431 case "find_cursorpoint": 432 433 // returns content 434 435 return new Array(true, node ); 436 break; 437 438 } 439 440 } 441 442 // In either case (fill or findcursor) we return the base node. The avoids 443 // problems in terminal cases (beginning or end of document or container tags) 444 445 if ( last_flag ) 446 { 447 this.ddt._ddtDumpNode( "enter-paragraphs.js", "263", "_fenEmptySet() : return 'base' node:", next_node ); 448 449 return new Array( true, next_node ); 450 } 451 452 this.ddt._ddtDumpNode( "enter-paragraphs.js", "263", "_fenEmptySet() : bottom returning false and :", next_node ); 453 454 return new Array( false, next_node ); 455 456 }; // end of _fenEmptySet() 457 458 // ------------------------------------------------------------------------------ 459 460 /** 461 * remove duplicate Id's. 462 * 463 * @param ep_ref enterparagraphs reference to enterparagraphs object 464 */ 465 466 EnterParagraphs.prototype._fenCullIds = function ( ep_ref, node, pong ) 467 { 468 469 this.ddt._ddt( "enter-paragraphs.js", "299", "_fenCullIds(): top" ); 124 470 125 471 // Check for an id, blast it if it's in the store, otherwise add it 126 if ( node.id ) pong[node.id] ? node.id = '' : pong[node.id] = true; 472 473 if ( node.id ) 474 { 475 476 this.ddt._ddt( "enter-paragraphs.js", "299", "_fenCullIds(): node '" + node.nodeName + "' has an id '" + node.id + "'" ); 477 478 pong[node.id] ? node.id = '' : pong[node.id] = true; 479 } 480 127 481 return new Array(false,pong); 128 }; 129 130 // Grabs a range suitable for paragraph stuffing 131 EnterParagraphs.prototype.processSide = function(rng, left) { 132 133 var next = function(element, left) { return ( left ? element.previousSibling : element.nextSibling ); }; 134 var node = left ? rng.startContainer : rng.endContainer; 135 var offset = left ? rng.startOffset : rng.endOffset; 482 483 }; 484 485 // --------------------------------------------------------------------------------- 486 487 /** 488 * Grabs a range suitable for paragraph stuffing 489 * 490 * @param rng Range 491 * @param search_direction string "left" or "right" 492 * 493 * @todo check blank node issue in roaming loop. 494 */ 495 496 EnterParagraphs.prototype.processSide = function( rng, search_direction) 497 { 498 499 this.ddt._ddt( "enter-paragraphs.js", "329", "processSide(): top search_direction == '" + search_direction + "'" ); 500 501 var next = function(element, search_direction) 502 { 503 return ( search_direction == "left" ? element.previousSibling : element.nextSibling ); 504 }; 505 506 var node = search_direction == "left" ? rng.startContainer : rng.endContainer; 507 var offset = search_direction == "left" ? rng.startOffset : rng.endOffset; 136 508 var roam, start = node; 509 510 this.ddt._ddtDumpNode( "enter-paragraphs.js", "337", "processSide(): starting with node:", node ); 137 511 138 512 // Never start with an element, because then the first roaming node might 139 513 // be on the exclusion list and we wouldn't know until it was too late 140 while ( start.nodeType == 1 && !this._permEmpty.test(start.nodeName) ) start = ( offset ? start.lastChild : start.firstChild ); 514 515 while ( start.nodeType == 1 && !this._permEmpty.test(start.nodeName) ) 516 { 517 start = ( offset ? start.lastChild : start.firstChild ); 518 } 141 519 142 520 // Climb the tree, left or right, until our course of action presents itself 143 while ( roam = roam ? ( next(roam,left) ? next(roam,left) : roam.parentNode ) : start ) { 144 145 if ( next(roam,left) ) { 521 // 522 // if roam is NULL try start. 523 // if roam is NOT NULL, try next node in our search_direction 524 // If that node is NULL, get our parent node. 525 // 526 // If all the above turns out NULL end the loop. 527 // 528 // FIXME: gecko (firefox 1.0.3) - enter "test" into an empty document and press enter. 529 // sometimes this loop finds a blank text node, sometimes it doesn't. 530 531 while ( roam = roam ? ( next(roam,search_direction) ? next(roam,search_direction) : roam.parentNode ) : start ) 532 { 533 534 this.ddt._ddtDumpNode( "enter-paragraphs.js", "357", "processSide(): roaming loop, search_direction is '" + search_direction + "' current node is: ", roam ); 535 536 // next() is an inline function defined above that returns the next node depending 537 // on the direction we're searching. 538 539 if ( next(roam,search_direction) ) 540 { 541 542 this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): Checking next node '" + next(roam,search_direction).NodeName + "' for _pExclusions list." ); 543 146 544 // If the next sibling's on the exclusion list, stop before it 147 if ( this._pExclusions.test(next(roam,left).nodeName) ) { 148 return this.processRng(rng, left, roam, next(roam,left), (left?'AfterEnd':'BeforeBegin'), true, false); 149 } } else { 545 546 if ( this._pExclusions.test(next(roam,search_direction).nodeName) ) 547 { 548 549 this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): Node '" + next(roam,search_direction).NodeName + "' is on the _pExclusions list. Stopping before it." ); 550 551 return this.processRng(rng, search_direction, roam, next(roam,search_direction), (search_direction == "left"?'AfterEnd':'BeforeBegin'), true, false); 552 } 553 } 554 else 555 { 556 557 this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): No next node, examing parent node '" + roam.parentNode.nodeName + "' for containers or exclusions." ); 558 150 559 // If our parent's on the container list, stop inside it 151 if (this._pContainers.test(roam.parentNode.nodeName)) { 152 return this.processRng(rng, left, roam, roam.parentNode, (left?'AfterBegin':'BeforeEnd'), true, false); 153 } 154 // If our parent's on the exclusion list, chop without wrapping 155 else if (this._pExclusions.test(roam.parentNode.nodeName)) { 156 if (this._pBreak.test(roam.parentNode.nodeName)) { 157 return this.processRng(rng, left, roam, roam.parentNode, 158 (left?'AfterBegin':'BeforeEnd'), false, (left?true:false)); 159 } else { 160 return this.processRng(rng, left, (roam = roam.parentNode), 161 (next(roam,left) ? next(roam,left) : roam.parentNode), 162 (next(roam,left) ? (left?'AfterEnd':'BeforeBegin') : (left?'AfterBegin':'BeforeEnd')), false, false); 163 } } } } }; 164 165 // Neighbour and insertion identify where the new node, roam, needs to enter 166 // the document; landmarks in our selection will be deleted before insertion 167 EnterParagraphs.prototype.processRng = function(rng, left, roam, neighbour, insertion, pWrap, preBr) { 168 169 var node = left ? rng.startContainer : rng.endContainer; 170 var offset = left ? rng.startOffset : rng.endOffset; 560 561 if (this._pContainers.test(roam.parentNode.nodeName)) 562 { 563 564 this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): Parent Node '" + roam.parentNode.nodeName + "' is on the _pContainer list. Stopping inside it." ); 565 566 return this.processRng(rng, search_direction, roam, roam.parentNode, (search_direction == "left"?'AfterBegin':'BeforeEnd'), true, false); 567 } 568 else if (this._pExclusions.test(roam.parentNode.nodeName)) 569 { 570 571 this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): Parent Node '" + roam.parentNode.nodeName + "' is on the _pExclusion list." ); 572 573 // chop without wrapping 574 575 if (this._pBreak.test(roam.parentNode.nodeName)) 576 { 577 578 this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): Parent Node '" + roam.parentNode.nodeName + "' is on the _pBreak list." ); 579 580 return this.processRng(rng, search_direction, roam, roam.parentNode, 581 (search_direction == "left"?'AfterBegin':'BeforeEnd'), false, (search_direction == "left" ?true:false)); 582 } 583 else 584 { 585 586 this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): Parent Node '" + roam.parentNode.nodeName + "' is not on the _pBreak list." ); 587 588 // the next(roam,search_direction) in this call is redundant since we know it's false 589 // because of the "if next(roam,search_direction)" above. 590 // 591 // the final false prevents this range from being wrapped in <p>'s most likely 592 // because it's already wrapped. 593 594 return this.processRng(rng, 595 search_direction, 596 (roam = roam.parentNode), 597 (next(roam,search_direction) ? next(roam,search_direction) : roam.parentNode), 598 (next(roam,search_direction) ? (search_direction == "left"?'AfterEnd':'BeforeBegin') : (search_direction == "left"?'AfterBegin':'BeforeEnd')), 599 false, 600 false); 601 } 602 } 603 } 604 } 605 606 this.ddt._ddt( "enter-paragraphs.js", "424", "processSide(): bottom" ); 607 608 }; // end of processSide() 609 610 // ------------------------------------------------------------------------------ 611 612 /** 613 * processRng - process Range. 614 * 615 * Neighbour and insertion identify where the new node, roam, needs to enter 616 * the document; landmarks in our selection will be deleted before insertion 617 * 618 * @param rn Range original selected range 619 * @param search_direction string Direction to search in. 620 * @param roam node 621 * @param insertion string may be AfterBegin of BeforeEnd 622 * @return array 623 */ 624 625 EnterParagraphs.prototype.processRng = function(rng, search_direction, roam, neighbour, insertion, pWrap, preBr) 626 { 627 628 this.ddt._ddtDumpNode( "enter-paragraphs.js", "398", "processRng(): top - roam arg is:", roam ); 629 this.ddt._ddtDumpNode( "enter-paragraphs.js", "398", "processRng(): top - neighbor arg is:", neighbour ); 630 631 this.ddt._ddt( "enter-paragraphs.js", "398", "processRng(): top - insertion arg is: '" + insertion + "'" ); 632 633 var node = search_direction == "left" ? rng.startContainer : rng.endContainer; 634 var offset = search_direction == "left" ? rng.startOffset : rng.endOffset; 635 636 this.ddt._ddtDumpNode( "enter-paragraphs.js", "447", "processRng(): range start (or end) is at offset '" + offset + "' is node :", node ); 171 637 172 638 // Define the range to cut, and extend the selection range to the same boundary 639 173 640 var editor = this.editor; 174 641 var newRng = editor._doc.createRange(); 642 175 643 newRng.selectNode(roam); 176 if (left) { 644 645 this.ddt._ddtDumpNode( "enter-paragraphs.js", "522", "processRng(): selecting newRng is:", newRng ); 646 this.ddt._ddtDumpNode( "enter-paragraphs.js", "522", "processRng(): selecting original rng is:", rng ); 647 648 // extend the range in the given direction. 649 650 if ( search_direction == "left") 651 { 177 652 newRng.setEnd(node, offset); 178 653 rng.setStart(newRng.startContainer, newRng.startOffset); 179 } else { 654 655 this.ddt._ddtDumpNode( "enter-paragraphs.js", "522", "processRng(): extending direction left - newRng is:", newRng ); 656 this.ddt._ddtDumpNode( "enter-paragraphs.js", "522", "processRng(): extending direction left - rng is:", rng ); 657 658 } 659 else if ( search_direction == "right" ) 660 { 661 180 662 newRng.setStart(node, offset); 181 rng.setEnd(newRng.endContainer, newRng.endOffset); 182 } 663 rng.setEnd(newRng.endContainer, newRng.endOffset); 664 665 this.ddt._ddt( "enter-paragraphs.js", "522", "processRng(): right - new range start is '" + offset + "' end offset is '" + newRng.endOffset + "'" ); 666 } 667 668 this.ddt._ddtDumpNode( "enter-paragraphs.js", "522", "processRng(): rng is:", rng ); 669 this.ddt._ddtDumpNode( "enter-paragraphs.js", "522", "processRng(): newRng is:", newRng ); 183 670 184 671 // Clone the range and remove duplicate ids it would otherwise produce 672 185 673 var cnt = newRng.cloneContents(); 186 this.forEachNodeUnder(cnt, this._fenCullIds, true, this.takenIds, false); 187 188 // Special case, for inserting paragraphs before some blocks when caret is at their zero offset 674 675 this.ddt._ddtDumpNode( "enter-paragraphs.js", "509", "processRng(): culling duplicate ids from:", cnt ); 676 677 // in this case "init" is an object not a boolen. 678 679 this.forEachNodeUnder( cnt, "cullids", "ltr", this.takenIds, false, false); 680 681 // Special case, for inserting paragraphs before some blocks when caret is at 682 // their zero offset. 683 // 684 // Used to "open up space" in front of a list, table. Usefull if the list is at 685 // the top of the document. (otherwise you'd have no way of "moving it down"). 686 189 687 var pify, pifyOffset, fill; 190 pify = left? (newRng.endContainer.nodeType == 3 ? true:false) : (newRng.startContainer.nodeType == 3 ? false:true);688 pify = search_direction == "left" ? (newRng.endContainer.nodeType == 3 ? true:false) : (newRng.startContainer.nodeType == 3 ? false:true); 191 689 pifyOffset = pify ? newRng.startOffset : newRng.endOffset; 192 690 pify = pify ? newRng.startContainer : newRng.endContainer; 193 691 194 if ( this._pifyParent.test(pify.nodeName) && pify.parentNode.childNodes.item(0) == pify ) { 195 while ( !this._pifySibling.test(pify.nodeName) ) pify = pify.parentNode; 196 } 197 198 if ( cnt.nodeType == 11 && !cnt.firstChild ) cnt.appendChild(editor._doc.createElement(pify.nodeName)); 199 fill = this.forEachNodeUnder(cnt,this._fenEmptySet,true,false,false); 200 201 if ( fill && this._pifySibling.test(pify.nodeName) && 202 ( (pifyOffset == 0) || ( pifyOffset == 1 && this._pifyForced.test(pify.nodeName) ) ) ) { 203 204 roam = editor._doc.createElement('p'); 205 roam.appendChild(editor._doc.createElement('br')); 206 207 if (left && pify.previousSibling) return new Array(pify.previousSibling, 'AfterEnd', roam); 208 else if (!left && pify.nextSibling) return new Array(pify.nextSibling, 'BeforeBegin', roam); 209 else return new Array(pify.parentNode, (left?'AfterBegin':'BeforeEnd'), roam); 210 } 692 this.ddt._ddtDumpNode( "enter-paragraphs.js", "521", "processRng(): pify is '" + pify.nodeName + "' pifyOffset is '" + pifyOffset + "':", pify ); 693 694 if ( this._pifyParent.test(pify.nodeName) && pify.parentNode.childNodes.item(0) == pify ) 695 { 696 while ( !this._pifySibling.test(pify.nodeName) ) 697 { 698 pify = pify.parentNode; 699 } 700 } 701 702 // NODE TYPE 11 is DOCUMENT_FRAGMENT NODE 703 704 if ( cnt.nodeType == 11 && !cnt.firstChild ) 705 { 706 cnt.appendChild(editor._doc.createElement(pify.nodeName)); 707 } 708 709 // YmL: Added additional last parameter for fill case to work around logic 710 // error in forEachNode() 711 712 this.ddt._ddt( "enter-paragraphs.js", "612", "processRng(): find_fill in cnt." ); 713 714 fill = this.forEachNodeUnder(cnt, "find_fill", "ltr", false ); 715 716 this.ddt._ddtDumpNode( "enter-paragraphs.js", "612", "processRng(): fill node:" , fill ); 717 718 if ( fill && 719 this._pifySibling.test(pify.nodeName) && 720 ( (pifyOffset == 0) || ( pifyOffset == 1 && this._pifyForced.test(pify.nodeName) ) ) ) 721 { 722 723 this.ddt._ddt( "enter-paragraphs.js", "544", "processRng(): pify handling. Creating p tag followed by nbsp tag" ); 724 725 roam = editor._doc.createElement( 'p' ); 726 roam.innerHTML = " "; 727 728 // roam = editor._doc.createElement('p'); 729 // roam.appendChild(editor._doc.createElement('br')); 730 731 // for these cases, if we are processing the left hand side we want it to halt 732 // processing instead of doing the right hand side. (Avoids adding another <p> </p> 733 // after the list etc. 734 735 if ((search_direction == "left" ) && pify.previousSibling) 736 { 737 738 this.ddt._ddt( "enter-paragraphs.js", "682", "processRng(): returning created roam AfterEnd" ); 739 740 return new Array(pify.previousSibling, 'AfterEnd', roam); 741 } 742 else if (( search_direction == "right") && pify.nextSibling) 743 { 744 745 this.ddt._ddt( "enter-paragraphs.js", "682", "processRng(): returning created roam BeforeBegin" ); 746 747 return new Array(pify.nextSibling, 'BeforeBegin', roam); 748 } 749 else 750 { 751 752 this.ddt._ddt( "enter-paragraphs.js", "682", "processRng(): returning created roam for direction '" + search_direction + "'" ); 753 754 return new Array(pify.parentNode, (search_direction == "left"?'AfterBegin':'BeforeEnd'), roam); 755 } 756 757 } 211 758 212 759 // If our cloned contents are 'content'-less, shove a break in them 213 if ( fill ) { 214 if ( fill.nodeType == 3 ) fill = fill.parentNode; // Ill-concieved? 215 if ( (fill.nodeType == 1 && !this._elemSolid.test()) || fill.nodeType == 11 ) fill.appendChild(editor._doc.createElement('br')); 216 else fill.parentNode.insertBefore(editor._doc.createElement('br'),fill); 217 } 218 219 // And stuff a shiny new object with whatever contents we have 220 roam = (pWrap || (cnt.nodeType == 11 && !cnt.firstChild)) ? editor._doc.createElement('p') : editor._doc.createDocumentFragment(); 221 roam.appendChild(cnt); 222 if (preBr) roam.appendChild(editor._doc.createElement('br')); 760 761 if ( fill ) 762 { 763 764 // Ill-concieved? 765 // 766 // 3 is a TEXT node and it should be empty. 767 // 768 769 if ( fill.nodeType == 3 ) 770 { 771 // fill = fill.parentNode; 772 773 fill = editor._doc.createDocumentFragment(); 774 775 this.ddt._ddtDumpNode( "enter-paragraphs.js", "575", "processRng(): fill.nodeType is 3. Moving up to parent:", fill ); 776 } 777 778 if ( (fill.nodeType == 1 && !this._elemSolid.test()) || fill.nodeType == 11 ) 779 { 780 781 // FIXME:/CHECKME: When Xinha is switched from WYSIWYG to text mode 782 // HTMLArea.getHTMLWrapper() will strip out the trailing br. Not sure why. 783 784 // fill.appendChild(editor._doc.createElement('br')); 785 786 var pterminator = editor._doc.createElement( 'p' ); 787 pterminator.innerHTML = " "; 788 789 fill.appendChild( pterminator ); 790 791 this.ddt._ddtDumpNode( "enter-paragraphs.js", "583", "processRng(): fill type is 1 and !elemsolid or it's type 11. Appending an nbsp tag:", fill ); 792 793 } 794 else 795 { 796 797 this.ddt._ddt( "enter-paragraphs.js", "583", "processRng(): inserting a br tag before." ); 798 799 // fill.parentNode.insertBefore(editor._doc.createElement('br'),fill); 800 801 var pterminator = editor._doc.createElement( 'p' ); 802 pterminator.innerHTML = " "; 803 804 fill.parentNode.insertBefore(parentNode,fill); 805 806 } 807 } 808 809 // YmL: If there was no content replace with fill 810 // (previous code did not use fill and we ended up with the 811 // <p>test</p><p></p> because Gecko was finding two empty text nodes 812 // when traversing on the right hand side of an empty document. 813 814 if ( fill ) 815 { 816 817 this.ddt._ddtDumpNode( "enter-paragraphs.js", "606", "processRng(): no content. Using fill.", fill ); 818 819 roam = fill; 820 } 821 else 822 { 823 // And stuff a shiny new object with whatever contents we have 824 825 this.ddt._ddt( "enter-paragraphs.js", "606", "processRng(): creating p tag or document fragment - pWrap is '" + pWrap + "' " ); 826 827 roam = (pWrap || (cnt.nodeType == 11 && !cnt.firstChild)) ? editor._doc.createElement('p') : editor._doc.createDocumentFragment(); 828 roam.appendChild(cnt); 829 } 830 831 if (preBr) 832 { 833 this.ddt._ddt( "enter-paragraphs.js", "767", "processRng(): appending a br based on preBr flag" ); 834 835 roam.appendChild(editor._doc.createElement('br')); 836 } 837 838 this.ddt._ddtDumpNode( "enter-paragraphs.js", "606", "processRng(): bottom with roam:", roam ); 839 this.ddt._ddtDumpNode( "enter-paragraphs.js", "606", "processRng(): bottom with neighbour:", neighbour ); 223 840 224 841 // Return the nearest relative, relative insertion point and fragment to insert 842 225 843 return new Array(neighbour, insertion, roam); 226 }; 227 228 // Called when a key is pressed in the editor 229 EnterParagraphs.prototype.__onKeyPress = function(ev) { 230 231 // If they've hit enter and shift is up, take it 844 845 }; // end of processRng() 846 847 // ---------------------------------------------------------------------------------- 848 849 /** 850 * are we an <li> that should be handled by the browser? 851 * 852 * there is no good way to "get out of" ordered or unordered lists from Javascript. 853 * We have to pass the onKeyPress 13 event to the browser so it can take care of 854 * getting us "out of" the list. 855 * 856 * The Gecko engine does a good job of handling all the normal <li> cases except the "press 857 * enter at the first position" where we want a <p> </p> inserted before the list. The 858 * built-in behavior is to open up a <li> before the current entry (not good). 859 * 860 * @param rng Range range. 861 */ 862 863 EnterParagraphs.prototype.isNormalListItem = function(rng) 864 { 865 866 this.ddt._ddtDumpNode( "enter-paragraphs.js", "863", "isNormaListItem(): checking rng for list end:", rng ); 867 868 var node, listNode; 869 870 node = rng.startContainer; 871 872 if (( typeof node.nodeName != 'undefined') && 873 ( node.nodeName.toLowerCase() == 'li' )) 874 { 875 876 this.ddt._ddt( "enter-paragraphs.js", "863", "isNormaListItem(): node is a list item"); 877 878 // are we a list item? 879 880 listNode = node; 881 } 882 else if (( typeof node.parentNode != 'undefined' ) && 883 ( typeof node.parentNode.nodeName != 'undefined' ) && 884 ( node.parentNode.nodeName.toLowerCase() == 'li' )) 885 { 886 887 this.ddt._ddt( "enter-paragraphs.js", "863", "isNormaListItem(): parent is a list item"); 888 889 // our parent is a list item. 890 891 listNode = node.parentNode; 892 893 } 894 else 895 { 896 this.ddt._ddt( "enter-paragraphs.js", "863", "isNormaListItem(): not list item"); 897 898 // neither we nor our parent are a list item. this is not a normal 899 // li case. 900 901 return false; 902 } 903 904 // at this point we have a listNode. Is it the first list item? 905 906 if ( ! listNode.previousSibling ) 907 { 908 this.ddt._ddt( "enter-paragraphs.js", "839", "isNormaListItem(): we are the first li." ); 909 910 // are we on the first character of the first li? 911 912 if ( rng.startOffset == 0 ) 913 { 914 this.ddt._ddt( "enter-paragraphs.js", "839", "isNormaListItem(): we are on the first character." ); 915 916 return false; 917 } 918 } 919 920 this.ddt._ddt( "enter-paragraphs.js", "839", "isNormaListItem(): this is a normal list item case." ); 921 return true; 922 923 }; // end of isNormalListItem() 924 925 // ---------------------------------------------------------------------------------- 926 /** 927 * Called when a key is pressed in the editor 928 */ 929 930 EnterParagraphs.prototype.__onKeyPress = function(ev) 931 { 932 933 this.ddt._ddt( "enter-paragraphs.js", "517", "__onKeyPress(): top with keyCode '" + ev.keyCode + "'" ); 934 935 // If they've hit enter and shift is not pressed, handle it 936 232 937 if (ev.keyCode == 13 && !ev.shiftKey && this.editor._iframe.contentWindow.getSelection) 938 { 939 this.ddt._ddt( "enter-paragraphs.js", "517", "__onKeyPress(): calling handleEnter" ); 940 233 941 return this.handleEnter(ev); 234 }; 235 236 // Handles the pressing of an unshifted enter for Gecko 237 EnterParagraphs.prototype.handleEnter = function(ev) { 942 } 943 944 this.ddt._ddt( "enter-paragraphs.js", "517", "__onKeyPress(): bottom" ); 945 946 }; // end of _onKeyPress() 947 948 // ----------------------------------------------------------------------------------- 949 950 /** 951 * Handles the pressing of an unshifted enter for Gecko 952 */ 953 954 EnterParagraphs.prototype.handleEnter = function(ev) 955 { 956 957 this.ddt._ddt( "enter-paragraphs.js", "537", "handleEnter(): top" ); 958 959 var cursorNode; 238 960 239 961 // Grab the selection and associated range 962 240 963 var sel = this.editor._getSelection(); 241 964 var rng = this.editor._createRange(sel); 965 966 this.ddt._ddtDumpNode( "enter-paragraphs.js", "757", "handleEnter(): initial range is: ", rng ); 967 968 // if we are at the end of a list and the node is empty let the browser handle 969 // it to get us out of the list. 970 971 if ( this.isNormalListItem(rng) ) 972 { 973 this.ddt._ddt( "enter-paragraphs.js", "757", "handleEnter(): we are at the end of a list with a blank item. Letting the browser handle it." ); 974 return true; 975 } 976 977 // as far as I can tell this isn't actually used. 978 242 979 this.takenIds = new Object(); 243 980 244 981 // Grab ranges for document re-stuffing, if appropriate 245 var pStart = this.processSide(rng, true); 246 var pEnd = this.processSide(rng, false); 982 // 983 // pStart and pEnd are arrays consisting of 984 // [0] neighbor node 985 // [1] insertion type 986 // [2] roam 987 988 this.ddt._ddt( "enter-paragraphs.js", "537", "handleEnter(): calling processSide on left side." ); 989 990 var pStart = this.processSide(rng, "left"); 991 992 this.ddt._ddtDumpNode( "enter-paragraphs.js", "757", "handleEnter(): after processing left side range is: ", rng ); 993 994 this.ddt._ddt( "enter-paragraphs.js", "537", "handleEnter(): calling processSide on right side." ); 995 996 var pEnd = this.processSide(rng, "right"); 997 998 // used to position the cursor after insertion. 999 1000 cursorNode = pEnd[2]; 247 1001 248 1002 // Get rid of everything local to the selection 1003 249 1004 sel.removeAllRanges(); 250 1005 rng.deleteContents(); 251 1006 252 // Grab a node we'll have after insertion, since fragments will be lost 253 var holdEnd = this.forEachNodeUnder(pEnd[2], this._fenEmptySet, true, false, true); 254 255 // Reinsert our carefully chosen document fragments 256 if ( pStart ) this.insertAdjacentElement(pStart[0], pStart[1], pStart[2]); 257 if ( pEnd.nodeType != 1 ) this.insertAdjacentElement(pEnd[0], pEnd[1], pEnd[2]); 1007 // Grab a node we'll have after insertion, since fragments will be lost 1008 // 1009 // we'll use this to position the cursor. 1010 1011 this.ddt._ddt( "enter-paragraphs.js", "712", "handleEnter(): looking for cursor position" ); 1012 1013 var holdEnd = this.forEachNodeUnder( cursorNode, "find_cursorpoint", "ltr", false, true); 1014 1015 if ( ! holdEnd ) 1016 { 1017 alert( "INTERNAL ERROR - could not find place to put cursor after ENTER" ); 1018 } 1019 1020 // Insert our carefully chosen document fragments 1021 1022 if ( pStart ) 1023 { 1024 1025 this.ddt._ddt( "enter-paragraphs.js", "712", "handleEnter(): inserting pEnd" ); 1026 1027 this.insertAdjacentElement(pStart[0], pStart[1], pStart[2]); 1028 } 1029 1030 if ( pEnd && pEnd.nodeType != 1) 1031 { 1032 1033 this.ddt._ddt( "enter-paragraphs.js", "712", "handleEnter(): inserting pEnd" ); 1034 1035 this.insertAdjacentElement(pEnd[0], pEnd[1], pEnd[2]); 1036 } 258 1037 259 1038 // Move the caret in front of the first good text element 260 if ( this._permEmpty.test(holdEnd.nodeName) ) { 1039 1040 if ((holdEnd) && (this._permEmpty.test(holdEnd.nodeName) )) 1041 { 1042 1043 this.ddt._ddt( "enter-paragraphs.js", "712", "handleEnter(): looping to find cursor element." ); 1044 261 1045 var prodigal = 0; 262 while ( holdEnd.parentNode.childNodes.item(prodigal) != holdEnd ) prodigal++; 1046 while ( holdEnd.parentNode.childNodes.item(prodigal) != holdEnd ) 1047 { 1048 prodigal++; 1049 } 1050 263 1051 sel.collapse( holdEnd.parentNode, prodigal); 264 } 265 else sel.collapse(holdEnd, 0); 266 this.editor.scrollToElement(holdEnd); 1052 } 1053 else 1054 { 1055 1056 // holdEnd might be false. 1057 1058 try 1059 { 1060 sel.collapse(holdEnd, 0); 1061 1062 this.ddt._ddtDumpNode( "enter-paragraphs.js", "1057", "handleEnter(): scrolling to element:", holdEnd ); 1063 1064 // interestingly, scrollToElement() scroll so the top if holdEnd is a text node. 1065 1066 if ( holdEnd.nodeType == 3 ) 1067 { 1068 holdEnd = holdEnd.parentNode; 1069 } 1070 1071 this.editor.scrollToElement(holdEnd); 1072 } 1073 catch (e) 1074 { 1075 // we could try to place the cursor at the end of the document. 1076 } 1077 } 1078 267 1079 this.editor.updateToolbar(); 268 1080 269 //====================== 270 HTMLArea._stopEvent(ev); 271 return true; 272 }; 1081 HTMLArea._stopEvent(ev); 1082 1083 return true; 1084 1085 }; // end of handleEnter() 1086 1087 // END -
branches/unified_backend/plugins/ImageManager/backend.php
r121 r172 41 41 */ 42 42 43 include_once( "../ddt/ddt.php" );43 include_once( XINHA_INSTALL_ROOT . "/ddt/ddt.php" ); 44 44 45 45 // uncomment to turn on debugging -
branches/unified_backend/plugins/ImageManager/config.inc.php
r121 r172 1 <? 1 <?php 2 2 /** 3 3 * Image Manager configuration file. … … 292 292 // bring in the debugging library. 293 293 294 include_once( XINHA_INSTALL_ROOT . "/ddt/ddt.php" ); 294 if ( !function_exists( "_ddt" ) ) 295 { 296 include_once( XINHA_INSTALL_ROOT . "/ddt/ddt.php" ); 297 } 295 298 296 299 // uncomment to send debug messages to a local file -
branches/unified_backend/plugins/ImageManager/image-manager.js
r121 r172 99 99 * then image will contain the selected image. 100 100 * 101 * @todo figure out how to get to editor object from Dialog function.101 * @todo check previousSibling issue. The fix here is probably covering up some other problem. 102 102 */ 103 103 … … 116 116 117 117 if (image && !/^img$/i.test(image.tagName)) 118 { 119 this.ddt._ddt( "image-manager.js","114", "_insertImage(): setting image to null" ); 118 120 image = null; 121 } 119 122 } 120 123 … … 197 200 } 198 201 202 // pulled in as a result of the closure above. 203 199 204 var img = image; 200 205 … … 204 209 var range = editor._createRange(sel); 205 210 206 ddt._ddt( "image-manager.js","206", "_insertImage(): execing insertImage" ); 211 // this is the browser built-in execCommand, not the HTMLArea execCommand 212 // method. The assumption here is that it will interact with the range 213 // created above so we can pull out the just inserted image from it. 214 215 ddt._ddt( "image-manager.js","206", "_insertImage(): no image. invoking browser insertImage execCommand" ); 207 216 208 217 editor._doc.execCommand("insertimage", false, param.f_url); … … 221 230 else 222 231 { 232 233 // If the editor window does not have focus or we are positioned immediately 234 // adjacent to another image and do not have a selection this returns a null 235 // object, not an img object. 236 // 237 // FIXME: The current Xinha commit, #156, does not exibit this behavior and it does 238 // not have the logic below. This implies there is some other problem elsewhere. 239 // Why does it return null here under the same circumstances? 240 223 241 img = range.startContainer.previousSibling; 242 243 if ( img == null ) 244 { 245 246 // we are probably at the beginning or end of the document. By trial and 247 // error it looks like the IMG tag is most likely our first child in the 248 // beginning of document case and under nextSibling in the end of document 249 // case. We'll need to verify this for future releases of Gecko. 250 251 ddt._ddt( "image-manager.js", "242", "_insertImage(): previousSibling is NULL. Checking firstChild" ); 252 253 if (( range.startContainer.firstChild != null ) && ( range.startContainer.firstChild.nodeName == "IMG" )) 254 { 255 ddt._ddt( "image-manager.js", "251", "_insertImage(): Found image under firstChild. Beginning of document?" ); 256 257 img = range.startContainer.firstChild; 258 } 259 else if (( range.startContainer.nextSibling != null ) && ( range.startContainer.nextSibling.nodeName == "IMG" )) 260 { 261 ddt._ddt( "image-manager.js", "242", "_insertImage(): Found image under nextSibling. end of document?" ); 262 img = range.startContainer.nextSibling; 263 } 264 else 265 { 266 alert( "INTERNAL ERROR - was unable to locate the newly inserted image object. The HTML in the document may be out of whack." ); 267 return false 268 } 269 } 224 270 } 225 271 } … … 228 274 img.src = param.f_url; 229 275 } 230 276 277 ddt._ddt( "image-manager.js","234", "_insertImage(): before switch type of img is '" + typeof img + "'" ); 278 231 279 for (field in param) 232 280 { … … 235 283 switch (field) 236 284 { 237 case "f_alt" : img.alt = value; break;238 case "f_border" : img.border = parseInt(value || "0"); break;239 case "f_align" : img.align = value; break;240 case "f_vert" : img.vspace = parseInt(value || "0"); break;241 case "f_horiz" : img.hspace = parseInt(value || "0"); break;285 case "f_alt" : img.alt = value; break; 286 case "f_border" : img.border = parseInt(value || "0"); break; 287 case "f_align" : img.align = value; break; 288 case "f_vert" : img.vspace = parseInt(value || "0"); break; 289 case "f_horiz" : img.hspace = parseInt(value || "0"); break; 242 290 case "f_width" : img.width = parseInt(value || "0"); break; 243 291 case "f_height" : img.height = parseInt(value || "0"); break; -
branches/unified_backend/plugins/ImageManager/images.php
r121 r172 1 <? 1 <?php 2 2 3 /** 3 4 * Show a list of images in a long horizontal table. … … 8 9 9 10 require_once('config.inc.php'); 10 require_once(XINHA_INSTALL_ROOT . '/ddt/ddt.php'); 11 12 // we may already have a definition of _ddt(). 13 14 if ( ! function_exists( "_ddt" ) ) 15 { 16 require_once(XINHA_INSTALL_ROOT . '/ddt/ddt.php'); 17 } 18 11 19 require_once('Classes/ImageManager.php'); 12 20 … … 15 23 // _ddtOn(); 16 24 17 //default path is / 25 _ddt( __FILE__, __LINE__, "images.php - base_url is '" . $IMConfig['base_url'] . "'" ); 26 27 // default path is / 28 18 29 $relative = '/'; 19 30 $manager = new ImageManager($IMConfig); 20 31 21 //process any file uploads 32 // process any file uploads 33 22 34 $manager->processUploads(); 23 35 … … 25 37 26 38 $refreshDir = false; 27 //process any directory functions 39 40 // process any directory functions 41 28 42 if($manager->deleteDirs() || $manager->processNewDir()) 29 43 $refreshDir = true; 30 44 31 //check for any sub-directory request 32 //check that the requested sub-directory exists 33 //and valid 34 if(isset($_REQUEST['dir'])) 35 { 45 // check for any sub-directory request 46 // check that the requested sub-directory exists 47 // and valid 48 49 if (isset($_REQUEST['dir'])) 50 { 36 51 $path = rawurldecode($_REQUEST['dir']); 37 52 if($manager->validRelativePath($path)) 38 53 $relative = $path; 39 }54 } 40 55 41 56 42 57 $manager = new ImageManager($IMConfig); 43 58 44 //get the list of files and directories 59 // get the list of files and directories 60 45 61 $list = $manager->getFiles($relative); 46 62 … … 50 66 * Draw the files in an table. 51 67 */ 68 52 69 function drawFiles($list, &$manager) 53 70 { 54 71 global $relative; 55 global $IMConfig; 72 73 // we used to have the global $IMConfig here but for some reason the global 74 // reference was getting dropped. Pulling it from inside manager is probably 75 // cleaner. 76 77 _ddt( __FILE__, __LINE__, "drawFiles(): config['base_url'] is '" . $manager->config['base_url'] . "'" ); 56 78 57 79 foreach($list as $entry => $file) … … 66 88 <a href="javascript:;" onclick="selectImage('<?php echo $file['relative'];?>', '<?php echo $entry; ?>', <?php echo $file['image'][0];?>, <?php echo $file['image'][1]; ?>);"title="<?php echo $entry; ?> - <?php echo Files::formatSize($file['stat']['size']); ?>"><img src="<?php print $manager->getThumbnail($file['relative']); ?>" alt="<?php echo $entry; ?> - <?php echo Files::formatSize($file['stat']['size']); ?>"/></a> 67 89 </td></tr><tr><td class="edit"> 68 <a href="<?php echo $IMConfig['backend_url']; ?>__function=images&dir=<?php echo $relative; ?>&delf=<?php echo rawurlencode($file['relative']);?>" title="Trash" onclick="return confirmDeleteFile('<?php echo $entry; ?>');"><img src="<?php print $IMConfig['base_url'];?>img/edit_trash.gif" height="15" width="15" alt="Trash"/></a><a href="javascript:;" title="Edit" onclick="editImage('<?php echo rawurlencode($file['relative']);?>');"><img src="<?php print $IMConfig['base_url'];?>img/edit_pencil.gif" height="15" width="15" alt="Edit"/></a> 90 <a href="<?php print $IMConfig['backend_url']; ?>__function=images&dir=<?php echo $relative; ?>&delf=<?php echo rawurlencode($file['relative']);?>" title="Trash" onclick="return confirmDeleteFile('<?php echo $entry; ?>');"><img src="<?php 91 92 _ddt( __FILE__, __LINE__, "images.php - base_url is '" . $manager->config['base_url'] . "'" ); 93 94 echo $manager->config['base_url'];?>img/edit_trash.gif" height="15" width="15" alt="Trash"/></a><a href="javascript:;" title="Edit" onclick="editImage('<?php echo rawurlencode($file['relative']);?>');"><img src="<?php print $manager->config['base_url'];?>img/edit_pencil.gif" height="15" width="15" alt="Edit"/></a> 69 95 <?php if($file['image']){ echo $file['image'][0].'x'.$file['image'][1]; } else echo $entry;?> 70 96 </td></tr></table></td> … … 81 107 { 82 108 global $relative; 83 global $IMConfig;84 109 85 110 foreach($list as $path => $dir) 86 111 { ?> 87 112 <td><table width="100" cellpadding="0" cellspacing="0"><tr><td class="block"> 88 <a href="<?php print $ IMConfig['backend_url']; ?>__function=images&dir=<?php echo rawurlencode($path); ?>" onclick="updateDir('<?php echo $path; ?>')" title="<?php echo $dir['entry']; ?>"><img src="<?php print $IMConfig['base_url'];?>img/folder.gif" height="80" width="80" alt="<?php echo $dir['entry']; ?>" /></a>113 <a href="<?php print $manager->config['backend_url']; ?>__function=images&dir=<?php echo rawurlencode($path); ?>" onclick="updateDir('<?php echo $path; ?>')" title="<?php echo $dir['entry']; ?>"><img src="<?php print $manager->config['base_url'];?>img/folder.gif" height="80" width="80" alt="<?php echo $dir['entry']; ?>" /></a> 89 114 </td></tr><tr> 90 115 <td class="edit"> 91 <a href="<?php print $IMConfig['backend_url']; ?>__function=editor&dir=<?php echo $relative; ?>&deld=<?php echo rawurlencode($path); ?>" title="Trash" onclick="return confirmDeleteDir('<?php echo $dir['entry']; ?>', <?php echo $dir['count']; ?>);"><img src="<?php print $IMConfig['base_url'];?>img/edit_trash.gif" height="15" width="15" alt="Trash"/></a> 116 <a href="<?php print $$manager->config['backend_url']; ?>__function=editor&dir=<?php echo $relative; ?>&deld=<?php echo rawurlencode($path); ?>" title="Trash" onclick="return confirmDeleteDir('<?php echo $dir['entry']; ?>', <?php echo $dir['count']; ?>);"><img src="<?php 117 118 _ddt( __FILE__, __LINE__, "images.php - base_url is '" . $manager->config['base_url'] . "'" ); 119 120 print $manager->config['base_url'];?>img/edit_trash.gif" height="15" width="15" alt="Trash"/></a> 92 121 <?php echo $dir['entry']; ?> 93 122 </td> -
branches/unified_backend/plugins/ImageManager/manager.php
r121 r172 1 <? 1 <?php 2 2 /** 3 3 * The main GUI for the ImageManager. … … 8 8 9 9 require_once('config.inc.php'); 10 require_once(XINHA_INSTALL_ROOT . '/ddt/ddt.php'); 10 11 if ( ! function_exists( "_ddt" ) ) 12 { 13 require_once( XINHA_INSTALL_ROOT . '/ddt/ddt.php'); 14 } 15 11 16 require_once('Classes/ImageManager.php'); 12 17 -
branches/unified_backend/plugins/Linker/linker.js
r121 r172 572 572 { 573 573 574 linker.ddt._ddt( "linker.js","574", "_prepareDialog(): backend defined. loading files using _getback() " );574 linker.ddt._ddt( "linker.js","574", "_prepareDialog(): backend defined. loading files using _getback() from '" + linker.lConfig.backend + "__function=scan'" ); 575 575 576 576 //get files from backend … … 579 579 { 580 580 581 linker.ddt._ddt( "linker.js","581", "linker.js", "_getback(): got back txt '" + txt + "'" ); 581 // for some reason this linker reference is not working in this closure 582 // under firefox 1.0.3. 583 584 linker.ddt._ddt( "linker.js","581", "_getback(): got back txt '" + txt + "'" ); 582 585 583 586 try … … 629 632 630 633 var html = this.html; 634 635 linker.ddt._ddt( "linker.js","634", "_prepareDialog(): to dialog html '" + html + "'" ); 631 636 632 637 // Now we have everything we need, so we can build the dialog. -
branches/unified_backend/plugins/Linker/scan.php
r121 r172 278 278 // get the output in an error popup. 279 279 // 280 // _ddtOn(); 281 282 _ddt( __FILE__, __LINE__, "scan.php: Resulting array is '" + $javascript_array + "'" ); 280 281 _setDebugLog( "/tmp/debug_log.txt" ); 282 283 _ddtOn(); 284 285 _ddt( __FILE__, __LINE__, "scan.php: hello\n" ); 286 287 _ddt( __FILE__, __LINE__, "scan.php: Resulting array is '" . $javascript_array . "'" ); 283 288 284 289 echo $javascript_array; -
branches/unified_backend/popups/about.html
r124 r172 17 17 this file will match the version of the repository. 18 18 19 [@@8 2@@]19 [@@83@@] 20 20 21 21 -->
