Ignore:
Timestamp:
05/18/05 21:15:06 (15 years ago)
Author:
yermol
Message:

htmlarea.js

. added workaround fix for NASTY FIREFOX BUG resulting in the infamous

uneditable area problem (exception on designMode="on" issue -
refer to bug:


https://bugzilla.mozilla.org/show_bug.cgi?id=207842


and this thread:


http://xinha.gogo.co.nz/punbb/viewtopic.php?id=229


. trailing <BR>'s are no longer stripped out of the document. This

was wreaking havoc on EnterParagraphs?. It's not clear whether or not
this is going to have unanticipated side-effects.

plugins/EnterParagraphs/enter-paragraphs.js

NOT FULLY FUNCTIONAL YET - DOESN'T HANDLE ALL CASES CORRECTLY,
but it's much better than it was I think.

. largely reworked.
. changed obfuscated variables names to make it more readable.
. expanded out nested (x ? y : z) constructs to make it more readable.
. added alot of comments.
. fixed a serious bug in findEachNodeUnder() that was not correctly

handling beginning and end node conditions.

. fixed design flaw that selected a non-existent insertion point for

placing the cursor.

. fixed several exceptions.
. now correctly handles lists by passing the back back to the Gecko

engine if we are in a list with the exception of being at the
first position in the first element in which case we insert
a paragraph before the list and move the cursor back to the first
item on the list.

Location:
branches/unified_backend/plugins
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • 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 
     17EnterParagraphs._pluginInfo =  
     18        { 
    1419  name          : "EnterParagraphs", 
    1520  version       : "1.0", 
     
    1924  sponsor_url   : "http://www.uwa.edu.au/", 
    2025  license       : "htmlArea" 
    21 }; 
     26        }; 
     27 
     28// ------------------------------------------------------------------ 
     29 
     30// "constants" 
     31 
     32/** 
     33* Whitespace Regex 
     34*/ 
     35 
     36EnterParagraphs.prototype._whiteSpace = /^\s*$/; 
     37 
     38/** 
     39* The pragmatic list of which elements a paragraph may not contain 
     40*/ 
     41 
     42EnterParagraphs.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 
     48EnterParagraphs.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 
     54EnterParagraphs.prototype._pBreak = /^(address|pre|blockquote)$/i; 
     55 
     56/** 
     57* Elements which may not contain children 
     58*/ 
     59 
     60EnterParagraphs.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 
     66EnterParagraphs.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 
     72EnterParagraphs.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; 
     73EnterParagraphs.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 
     79EnterParagraphs.prototype._pifyParent = /^(dd|dt|li|td|th|tr)$/i; 
     80 
     81// --------------------------------------------------------------------- 
     82 
     83/** 
     84* EnterParagraphs Constructor 
     85*/ 
     86 
     87function 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// ------------------------------------------------------------------ 
    22119 
    23120/** 
     
    30127EnterParagraphs.prototype.name = "EnterParagraphs"; 
    31128 
    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 
     133EnterParagraphs.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 
     171EnterParagraphs.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 ); 
    60175 
    61176  // Identify the first and last nodes to deal with 
     177         
    62178  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 
     218EnterParagraphs.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                                        { 
    90295          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 
    100383  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 
     398EnterParagraphs.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 ); 
    105402 
    106403  // 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 
     466EnterParagraphs.prototype._fenCullIds = function ( ep_ref, node, pong )  
     467        { 
     468 
     469        this.ddt._ddt( "enter-paragraphs.js", "299", "_fenCullIds(): top" ); 
    124470 
    125471  // 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 
    127481  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 
     496EnterParagraphs.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; 
    136508  var roam, start = node; 
     509 
     510        this.ddt._ddtDumpNode( "enter-paragraphs.js", "337", "processSide(): starting with node:", node ); 
    137511 
    138512  // Never start with an element, because then the first roaming node might 
    139513  // 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                } 
    141519 
    142520  // 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 
    146544      // 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 
    150559      // 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 
     625EnterParagraphs.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 ); 
    171637 
    172638  // Define the range to cut, and extend the selection range to the same boundary 
     639 
    173640  var editor = this.editor; 
    174641  var newRng = editor._doc.createRange(); 
     642 
    175643  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                { 
    177652    newRng.setEnd(node, offset); 
    178653    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 
    180662    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 ); 
    183670 
    184671  // Clone the range and remove duplicate ids it would otherwise produce 
     672 
    185673  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 
    189687  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); 
    191689  pifyOffset = pify ? newRng.startOffset : newRng.endOffset; 
    192690  pify = pify ? newRng.startContainer : newRng.endContainer; 
    193691 
    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 = "&nbsp;"; 
     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>&nbsp</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          } 
    211758 
    212759  // 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 = "&nbsp;"; 
     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 = "&nbsp;"; 
     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 ); 
    223840 
    224841  // Return the nearest relative, relative insertion point and fragment to insert 
     842 
    225843  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>&nbsp</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 
     863EnterParagraphs.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 
     930EnterParagraphs.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 
    232937  if (ev.keyCode == 13 && !ev.shiftKey && this.editor._iframe.contentWindow.getSelection) 
     938                { 
     939                this.ddt._ddt( "enter-paragraphs.js", "517", "__onKeyPress(): calling handleEnter" ); 
     940 
    233941    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 
     954EnterParagraphs.prototype.handleEnter = function(ev)  
     955        { 
     956 
     957        this.ddt._ddt( "enter-paragraphs.js", "537", "handleEnter(): top" ); 
     958 
     959        var cursorNode; 
    238960 
    239961  // Grab the selection and associated range 
     962 
    240963  var sel = this.editor._getSelection(); 
    241964  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 
    242979  this.takenIds = new Object(); 
    243980 
    244981  // 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]; 
    2471001 
    2481002  // Get rid of everything local to the selection 
     1003 
    2491004  sel.removeAllRanges(); 
    2501005  rng.deleteContents(); 
    2511006 
    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                } 
    2581037 
    2591038  // 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 
    2611045    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 
    2631051    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         
    2671079  this.editor.updateToolbar(); 
    2681080 
    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  
    4141*/ 
    4242 
    43 include_once( "../ddt/ddt.php" ); 
     43include_once( XINHA_INSTALL_ROOT . "/ddt/ddt.php" ); 
    4444 
    4545// uncomment to turn on debugging 
  • branches/unified_backend/plugins/ImageManager/config.inc.php

    r121 r172  
    1 <? 
     1<?php 
    22/** 
    33 * Image Manager configuration file. 
     
    292292// bring in the debugging library. 
    293293 
    294 include_once( XINHA_INSTALL_ROOT . "/ddt/ddt.php" ); 
     294if ( !function_exists( "_ddt" ) ) 
     295        { 
     296        include_once( XINHA_INSTALL_ROOT . "/ddt/ddt.php" ); 
     297        } 
    295298 
    296299// uncomment to send debug messages to a local file 
  • branches/unified_backend/plugins/ImageManager/image-manager.js

    r121 r172  
    9999* then image will contain the selected image. 
    100100* 
    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. 
    102102*/ 
    103103 
     
    116116 
    117117                if (image && !/^img$/i.test(image.tagName)) 
     118                        { 
     119                        this.ddt._ddt( "image-manager.js","114", "_insertImage(): setting image to null" ); 
    118120                        image = null; 
     121                        } 
    119122                } 
    120123 
     
    197200                                } 
    198201 
     202                        // pulled in as a result of the closure above. 
     203 
    199204                        var img = image; 
    200205 
     
    204209                                var range = editor._createRange(sel);                    
    205210 
    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" ); 
    207216 
    208217                                editor._doc.execCommand("insertimage", false, param.f_url); 
     
    221230                                else  
    222231                                        { 
     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 
    223241                                        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                                                } 
    224270                                        } 
    225271                                }  
     
    228274                                img.src = param.f_url; 
    229275                                } 
    230                  
     276 
     277                        ddt._ddt( "image-manager.js","234", "_insertImage(): before switch type of img is '" + typeof img + "'" ); 
     278                                         
    231279                        for (field in param)  
    232280                                { 
     
    235283                                switch (field)  
    236284                                        { 
    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; 
    242290                                        case "f_width"  : img.width = parseInt(value || "0"); break; 
    243291                                        case "f_height"  : img.height = parseInt(value || "0"); break; 
  • branches/unified_backend/plugins/ImageManager/images.php

    r121 r172  
    1 <? 
     1<?php 
     2 
    23/** 
    34 * Show a list of images in a long horizontal table. 
     
    89 
    910require_once('config.inc.php'); 
    10 require_once(XINHA_INSTALL_ROOT . '/ddt/ddt.php'); 
     11 
     12// we may already have a definition of _ddt().  
     13 
     14if ( ! function_exists( "_ddt" ) ) 
     15        { 
     16        require_once(XINHA_INSTALL_ROOT . '/ddt/ddt.php'); 
     17        } 
     18 
    1119require_once('Classes/ImageManager.php'); 
    1220 
     
    1523// _ddtOn(); 
    1624 
    17 //default path is / 
     25_ddt( __FILE__, __LINE__, "images.php - base_url is '" . $IMConfig['base_url'] . "'" ); 
     26 
     27// default path is / 
     28 
    1829$relative = '/'; 
    1930$manager = new ImageManager($IMConfig); 
    2031 
    21 //process any file uploads 
     32// process any file uploads 
     33 
    2234$manager->processUploads(); 
    2335 
     
    2537 
    2638$refreshDir = false; 
    27 //process any directory functions 
     39 
     40// process any directory functions 
     41 
    2842if($manager->deleteDirs() || $manager->processNewDir()) 
    2943        $refreshDir = true; 
    3044 
    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 
     49if (isset($_REQUEST['dir'])) 
     50        { 
    3651        $path = rawurldecode($_REQUEST['dir']); 
    3752        if($manager->validRelativePath($path)) 
    3853                $relative = $path; 
    39 } 
     54        } 
    4055 
    4156 
    4257$manager = new ImageManager($IMConfig); 
    4358 
    44 //get the list of files and directories 
     59// get the list of files and directories 
     60 
    4561$list = $manager->getFiles($relative); 
    4662 
     
    5066 * Draw the files in an table. 
    5167 */ 
     68 
    5269function drawFiles($list, &$manager) 
    5370{ 
    5471        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'] . "'" ); 
    5678 
    5779        foreach($list as $entry => $file)  
     
    6688                <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> 
    6789                </td></tr><tr><td class="edit"> 
    68                         <a href="<?php echo $IMConfig['backend_url']; ?>__function=images&dir=<?php echo $relative; ?>&amp;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; ?>&amp;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> 
    6995                <?php if($file['image']){ echo $file['image'][0].'x'.$file['image'][1]; } else echo $entry;?> 
    7096                </td></tr></table></td>  
     
    81107{ 
    82108        global $relative; 
    83    global $IMConfig; 
    84109 
    85110        foreach($list as $path => $dir)  
    86111        { ?> 
    87112                <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> 
    89114                </td></tr><tr> 
    90115                <td class="edit"> 
    91                         <a href="<?php print $IMConfig['backend_url']; ?>__function=editor&dir=<?php echo $relative; ?>&amp;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; ?>&amp;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> 
    92121                        <?php echo $dir['entry']; ?> 
    93122                </td> 
  • branches/unified_backend/plugins/ImageManager/manager.php

    r121 r172  
    1 <? 
     1<?php 
    22/** 
    33* The main GUI for the ImageManager. 
     
    88 
    99require_once('config.inc.php'); 
    10 require_once(XINHA_INSTALL_ROOT . '/ddt/ddt.php'); 
     10 
     11if ( ! function_exists( "_ddt" ) ) 
     12        { 
     13        require_once( XINHA_INSTALL_ROOT . '/ddt/ddt.php'); 
     14        } 
     15 
    1116require_once('Classes/ImageManager.php'); 
    1217         
  • branches/unified_backend/plugins/Linker/linker.js

    r121 r172  
    572572            { 
    573573 
    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'" ); 
    575575 
    576576                        //get files from backend 
     
    579579                                                        { 
    580580 
    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 + "'"  ); 
    582585 
    583586                                                        try  
     
    629632 
    630633  var html = this.html; 
     634 
     635        linker.ddt._ddt( "linker.js","634", "_prepareDialog(): to dialog html '" + html + "'" ); 
    631636 
    632637  // Now we have everything we need, so we can build the dialog. 
  • branches/unified_backend/plugins/Linker/scan.php

    r121 r172  
    278278// get the output in an error popup. 
    279279// 
    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 . "'" ); 
    283288 
    284289echo $javascript_array; 
Note: See TracChangeset for help on using the changeset viewer.