source: Dev/trunk/src/client/dijit/_editor/plugins/EnterKeyHandling.js

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 21.7 KB
Line 
1define([
2        "dojo/_base/declare", // declare
3        "dojo/dom-construct", // domConstruct.destroy domConstruct.place
4        "dojo/keys", // keys.ENTER
5        "dojo/_base/lang",
6        "dojo/on",
7        "dojo/sniff", // has("ie") has("mozilla") has("webkit")
8        "dojo/_base/window", // win.withGlobal
9        "dojo/window", // winUtils.scrollIntoView
10        "../_Plugin",
11        "../RichText",
12        "../range",
13        "../../_base/focus"
14], function(declare, domConstruct, keys, lang, on, has, win, winUtils, _Plugin, RichText, rangeapi, baseFocus){
15
16        // module:
17        //              dijit/_editor/plugins/EnterKeyHandling
18
19        return declare("dijit._editor.plugins.EnterKeyHandling", _Plugin, {
20                // summary:
21                //              This plugin tries to make all browsers behave consistently with regard to
22                //              how ENTER behaves in the editor window.  It traps the ENTER key and alters
23                //              the way DOM is constructed in certain cases to try to commonize the generated
24                //              DOM and behaviors across browsers.
25                //
26                // description:
27                //              This plugin has three modes:
28                //
29                //              - blockNodeForEnter=BR
30                //              - blockNodeForEnter=DIV
31                //              - blockNodeForEnter=P
32                //
33                //              In blockNodeForEnter=P, the ENTER key starts a new
34                //              paragraph, and shift-ENTER starts a new line in the current paragraph.
35                //              For example, the input:
36                //
37                //      |       first paragraph <shift-ENTER>
38                //      |       second line of first paragraph <ENTER>
39                //      |       second paragraph
40                //
41                //              will generate:
42                //
43                //      |       <p>
44                //      |               first paragraph
45                //      |               <br/>
46                //      |               second line of first paragraph
47                //      |       </p>
48                //      |       <p>
49                //      |               second paragraph
50                //      |       </p>
51                //
52                //              In BR and DIV mode, the ENTER key conceptually goes to a new line in the
53                //              current paragraph, and users conceptually create a new paragraph by pressing ENTER twice.
54                //              For example, if the user enters text into an editor like this:
55                //
56                //      |               one <ENTER>
57                //      |               two <ENTER>
58                //      |               three <ENTER>
59                //      |               <ENTER>
60                //      |               four <ENTER>
61                //      |               five <ENTER>
62                //      |               six <ENTER>
63                //
64                //              It will appear on the screen as two 'paragraphs' of three lines each.  Markupwise, this generates:
65                //
66                //              BR:
67                //      |               one<br/>
68                //      |               two<br/>
69                //      |               three<br/>
70                //      |               <br/>
71                //      |               four<br/>
72                //      |               five<br/>
73                //      |               six<br/>
74                //
75                //              DIV:
76                //      |               <div>one</div>
77                //      |               <div>two</div>
78                //      |               <div>three</div>
79                //      |               <div>&nbsp;</div>
80                //      |               <div>four</div>
81                //      |               <div>five</div>
82                //      |               <div>six</div>
83
84                // blockNodeForEnter: String
85                //              This property decides the behavior of Enter key. It can be either P,
86                //              DIV, BR, or empty (which means disable this feature). Anything else
87                //              will trigger errors.  The default is 'BR'
88                //
89                //              See class description for more details.
90                blockNodeForEnter: 'BR',
91
92                constructor: function(args){
93                        if(args){
94                                if("blockNodeForEnter" in args){
95                                        args.blockNodeForEnter = args.blockNodeForEnter.toUpperCase();
96                                }
97                                lang.mixin(this, args);
98                        }
99                },
100
101                setEditor: function(editor){
102                        // Overrides _Plugin.setEditor().
103                        if(this.editor === editor){
104                                return;
105                        }
106                        this.editor = editor;
107                        if(this.blockNodeForEnter == 'BR'){
108                                // While Moz has a mode tht mostly works, it's still a little different,
109                                // So, try to just have a common mode and be consistent.  Which means
110                                // we need to enable customUndo, if not already enabled.
111                                this.editor.customUndo = true;
112                                editor.onLoadDeferred.then(lang.hitch(this, function(d){
113                                        this.own(on(editor.document, "keydown", lang.hitch(this, function(e){
114                                                if(e.keyCode == keys.ENTER){
115                                                        // Just do it manually.  The handleEnterKey has a shift mode that
116                                                        // Always acts like <br>, so just use it.
117                                                        var ne = lang.mixin({}, e);
118                                                        ne.shiftKey = true;
119                                                        if(!this.handleEnterKey(ne)){
120                                                                e.stopPropagation();
121                                                                e.preventDefault();
122                                                        }
123                                                }
124                                        })));
125                                        if(has("ie") >= 9 && has("ie") <= 10){
126                                                this.own(on(editor.document, "paste", lang.hitch(this, function(e){
127                                                        setTimeout(lang.hitch(this, function(){
128                                                                // Use the old range/selection code to kick IE 9 into updating
129                                                                // its range by moving it back, then forward, one 'character'.
130                                                                var r = this.editor.document.selection.createRange();
131                                                                r.move('character', -1);
132                                                                r.select();
133                                                                r.move('character', 1);
134                                                                r.select();
135                                                        }), 0);
136                                                })));
137                                        }
138                                        return d;
139                                }));
140                        }else if(this.blockNodeForEnter){
141                                // add enter key handler
142                                var h = lang.hitch(this, "handleEnterKey");
143                                editor.addKeyHandler(13, 0, 0, h); //enter
144                                editor.addKeyHandler(13, 0, 1, h); //shift+enter
145                                this.own(this.editor.on('KeyPressed', lang.hitch(this, 'onKeyPressed')));
146                        }
147                },
148                onKeyPressed: function(){
149                        // summary:
150                        //              Handler for after the user has pressed a key, and the display has been updated.
151                        //              Connected to RichText's onKeyPressed() method.
152                        // tags:
153                        //              private
154                        if(this._checkListLater){
155                                if(win.withGlobal(this.editor.window, 'isCollapsed', baseFocus)){       // TODO: stop using withGlobal(), and baseFocus
156                                        var liparent = this.editor.selection.getAncestorElement('LI');
157                                        if(!liparent){
158                                                // circulate the undo detection code by calling RichText::execCommand directly
159                                                RichText.prototype.execCommand.call(this.editor, 'formatblock', this.blockNodeForEnter);
160                                                // set the innerHTML of the new block node
161                                                var block = this.editor.selection.getAncestorElement(this.blockNodeForEnter);
162                                                if(block){
163                                                        block.innerHTML = this.bogusHtmlContent;
164                                                        if(has("ie") <= 9){
165                                                                // move to the start by moving backwards one char
166                                                                var r = this.editor.document.selection.createRange();
167                                                                r.move('character', -1);
168                                                                r.select();
169                                                        }
170                                                }else{
171                                                        console.error('onKeyPressed: Cannot find the new block node'); // FIXME
172                                                }
173                                        }else{
174                                                if(has("mozilla")){
175                                                        if(liparent.parentNode.parentNode.nodeName == 'LI'){
176                                                                liparent = liparent.parentNode.parentNode;
177                                                        }
178                                                }
179                                                var fc = liparent.firstChild;
180                                                if(fc && fc.nodeType == 1 && (fc.nodeName == 'UL' || fc.nodeName == 'OL')){
181                                                        liparent.insertBefore(fc.ownerDocument.createTextNode('\xA0'), fc);
182                                                        var newrange = rangeapi.create(this.editor.window);
183                                                        newrange.setStart(liparent.firstChild, 0);
184                                                        var selection = rangeapi.getSelection(this.editor.window, true);
185                                                        selection.removeAllRanges();
186                                                        selection.addRange(newrange);
187                                                }
188                                        }
189                                }
190                                this._checkListLater = false;
191                        }
192                        if(this._pressedEnterInBlock){
193                                // the new created is the original current P, so we have previousSibling below
194                                if(this._pressedEnterInBlock.previousSibling){
195                                        this.removeTrailingBr(this._pressedEnterInBlock.previousSibling);
196                                }
197                                delete this._pressedEnterInBlock;
198                        }
199                },
200
201                // bogusHtmlContent: [private] String
202                //              HTML to stick into a new empty block
203                bogusHtmlContent: '&#160;', // &nbsp;
204
205                // blockNodes: [private] Regex
206                //              Regex for testing if a given tag is a block level (display:block) tag
207                blockNodes: /^(?:P|H1|H2|H3|H4|H5|H6|LI)$/,
208
209                handleEnterKey: function(e){
210                        // summary:
211                        //              Handler for enter key events when blockNodeForEnter is DIV or P.
212                        // description:
213                        //              Manually handle enter key event to make the behavior consistent across
214                        //              all supported browsers. See class description for details.
215                        // tags:
216                        //              private
217
218                        var selection, range, newrange, startNode, endNode, brNode, doc = this.editor.document, br, rs, txt;
219                        if(e.shiftKey){        // shift+enter always generates <br>
220                                var parent = this.editor.selection.getParentElement();
221                                var header = rangeapi.getAncestor(parent, this.blockNodes);
222                                if(header){
223                                        if(header.tagName == 'LI'){
224                                                return true; // let browser handle
225                                        }
226                                        selection = rangeapi.getSelection(this.editor.window);
227                                        range = selection.getRangeAt(0);
228                                        if(!range.collapsed){
229                                                range.deleteContents();
230                                                selection = rangeapi.getSelection(this.editor.window);
231                                                range = selection.getRangeAt(0);
232                                        }
233                                        if(rangeapi.atBeginningOfContainer(header, range.startContainer, range.startOffset)){
234                                                br = doc.createElement('br');
235                                                newrange = rangeapi.create(this.editor.window);
236                                                header.insertBefore(br, header.firstChild);
237                                                newrange.setStartAfter(br);
238                                                selection.removeAllRanges();
239                                                selection.addRange(newrange);
240                                        }else if(rangeapi.atEndOfContainer(header, range.startContainer, range.startOffset)){
241                                                newrange = rangeapi.create(this.editor.window);
242                                                br = doc.createElement('br');
243                                                header.appendChild(br);
244                                                header.appendChild(doc.createTextNode('\xA0'));
245                                                newrange.setStart(header.lastChild, 0);
246                                                selection.removeAllRanges();
247                                                selection.addRange(newrange);
248                                        }else{
249                                                rs = range.startContainer;
250                                                if(rs && rs.nodeType == 3){
251                                                        // Text node, we have to split it.
252                                                        txt = rs.nodeValue;
253                                                        startNode = doc.createTextNode(txt.substring(0, range.startOffset));
254                                                        endNode = doc.createTextNode(txt.substring(range.startOffset));
255                                                        brNode = doc.createElement("br");
256
257                                                        if(endNode.nodeValue == "" && has("webkit")){
258                                                                endNode = doc.createTextNode('\xA0')
259                                                        }
260                                                        domConstruct.place(startNode, rs, "after");
261                                                        domConstruct.place(brNode, startNode, "after");
262                                                        domConstruct.place(endNode, brNode, "after");
263                                                        domConstruct.destroy(rs);
264                                                        newrange = rangeapi.create(this.editor.window);
265                                                        newrange.setStart(endNode, 0);
266                                                        selection.removeAllRanges();
267                                                        selection.addRange(newrange);
268                                                        return false;
269                                                }
270                                                return true; // let browser handle
271                                        }
272                                }else{
273                                        selection = rangeapi.getSelection(this.editor.window);
274                                        if(selection.rangeCount){
275                                                range = selection.getRangeAt(0);
276                                                if(range && range.startContainer){
277                                                        if(!range.collapsed){
278                                                                range.deleteContents();
279                                                                selection = rangeapi.getSelection(this.editor.window);
280                                                                range = selection.getRangeAt(0);
281                                                        }
282                                                        rs = range.startContainer;
283                                                        if(rs && rs.nodeType == 3){
284                                                                // Text node, we have to split it.
285
286                                                                var offset = range.startOffset;
287                                                                if(rs.length < offset){
288                                                                        //We are not splitting the right node, try to locate the correct one
289                                                                        ret = this._adjustNodeAndOffset(rs, offset);
290                                                                        rs = ret.node;
291                                                                        offset = ret.offset;
292                                                                }
293                                                                txt = rs.nodeValue;
294
295                                                                startNode = doc.createTextNode(txt.substring(0, offset));
296                                                                endNode = doc.createTextNode(txt.substring(offset));
297                                                                brNode = doc.createElement("br");
298
299                                                                if(!endNode.length){
300                                                                        // Create dummy text with a &nbsp to go after the BR, to prevent IE crash.
301                                                                        // See https://bugs.dojotoolkit.org/ticket/12008 for details.
302                                                                        endNode = doc.createTextNode('\xA0');
303                                                                }
304
305                                                                if(startNode.length){
306                                                                        domConstruct.place(startNode, rs, "after");
307                                                                }else{
308                                                                        startNode = rs;
309                                                                }
310                                                                domConstruct.place(brNode, startNode, "after");
311                                                                domConstruct.place(endNode, brNode, "after");
312                                                                domConstruct.destroy(rs);
313                                                                newrange = rangeapi.create(this.editor.window);
314                                                                newrange.setStart(endNode, 0);
315                                                                newrange.setEnd(endNode, endNode.length);
316                                                                selection.removeAllRanges();
317                                                                selection.addRange(newrange);
318                                                                this.editor.selection.collapse(true);
319                                                        }else{
320                                                                var targetNode;
321                                                                if(range.startOffset >= 0){
322                                                                        targetNode = rs.childNodes[range.startOffset];
323                                                                }
324                                                                var brNode = doc.createElement("br");
325                                                                var endNode = doc.createTextNode('\xA0');
326                                                                if(!targetNode){
327                                                                        rs.appendChild(brNode);
328                                                                        rs.appendChild(endNode);
329                                                                }else{
330                                                                        domConstruct.place(brNode, targetNode, "before");
331                                                                        domConstruct.place(endNode, brNode, "after");
332                                                                }
333                                                                newrange = rangeapi.create(this.editor.window);
334                                                                newrange.setStart(endNode, 0);
335                                                                newrange.setEnd(endNode, endNode.length);
336                                                                selection.removeAllRanges();
337                                                                selection.addRange(newrange);
338                                                                this.editor.selection.collapse(true);
339                                                        }
340                                                        // \xA0 dummy text node remains, but is stripped before get("value")
341                                                        // by RichText._stripTrailingEmptyNodes().  Still, could we just use a plain
342                                                        // space (" ") instead?
343                                                }
344                                        }else{
345                                                // don't change this: do not call this.execCommand, as that may have other logic in subclass
346                                                RichText.prototype.execCommand.call(this.editor, 'inserthtml', '<br>');
347                                        }
348                                }
349                                return false;
350                        }
351                        var _letBrowserHandle = true;
352
353                        // first remove selection
354                        selection = rangeapi.getSelection(this.editor.window);
355                        range = selection.getRangeAt(0);
356                        if(!range.collapsed){
357                                range.deleteContents();
358                                selection = rangeapi.getSelection(this.editor.window);
359                                range = selection.getRangeAt(0);
360                        }
361
362                        var block = rangeapi.getBlockAncestor(range.endContainer, null, this.editor.editNode);
363                        var blockNode = block.blockNode;
364
365                        // if this is under a LI or the parent of the blockNode is LI, just let browser to handle it
366                        if((this._checkListLater = (blockNode && (blockNode.nodeName == 'LI' || blockNode.parentNode.nodeName == 'LI')))){
367                                if(has("mozilla")){
368                                        // press enter in middle of P may leave a trailing <br/>, let's remove it later
369                                        this._pressedEnterInBlock = blockNode;
370                                }
371                                // if this li only contains spaces, set the content to empty so the browser will outdent this item
372                                if(/^(\s|&nbsp;|&#160;|\xA0|<span\b[^>]*\bclass=['"]Apple-style-span['"][^>]*>(\s|&nbsp;|&#160;|\xA0)<\/span>)?(<br>)?$/.test(blockNode.innerHTML)){
373                                        // empty LI node
374                                        blockNode.innerHTML = '';
375                                        if(has("webkit")){ // WebKit tosses the range when innerHTML is reset
376                                                newrange = rangeapi.create(this.editor.window);
377                                                newrange.setStart(blockNode, 0);
378                                                selection.removeAllRanges();
379                                                selection.addRange(newrange);
380                                        }
381                                        this._checkListLater = false; // nothing to check since the browser handles outdent
382                                }
383                                return true;
384                        }
385
386                        // text node directly under body, let's wrap them in a node
387                        if(!block.blockNode || block.blockNode === this.editor.editNode){
388                                try{
389                                        RichText.prototype.execCommand.call(this.editor, 'formatblock', this.blockNodeForEnter);
390                                }catch(e2){ /*squelch FF3 exception bug when editor content is a single BR*/
391                                }
392                                // get the newly created block node
393                                // FIXME
394                                block = {blockNode: this.editor.selection.getAncestorElement(this.blockNodeForEnter),
395                                        blockContainer: this.editor.editNode};
396                                if(block.blockNode){
397                                        if(block.blockNode != this.editor.editNode &&
398                                                (!(block.blockNode.textContent || block.blockNode.innerHTML).replace(/^\s+|\s+$/g, "").length)){
399                                                this.removeTrailingBr(block.blockNode);
400                                                return false;
401                                        }
402                                }else{    // we shouldn't be here if formatblock worked
403                                        block.blockNode = this.editor.editNode;
404                                }
405                                selection = rangeapi.getSelection(this.editor.window);
406                                range = selection.getRangeAt(0);
407                        }
408
409                        var newblock = doc.createElement(this.blockNodeForEnter);
410                        newblock.innerHTML = this.bogusHtmlContent;
411                        this.removeTrailingBr(block.blockNode);
412                        var endOffset = range.endOffset;
413                        var node = range.endContainer;
414                        if(node.length < endOffset){
415                                //We are not checking the right node, try to locate the correct one
416                                var ret = this._adjustNodeAndOffset(node, endOffset);
417                                node = ret.node;
418                                endOffset = ret.offset;
419                        }
420                        if(rangeapi.atEndOfContainer(block.blockNode, node, endOffset)){
421                                if(block.blockNode === block.blockContainer){
422                                        block.blockNode.appendChild(newblock);
423                                }else{
424                                        domConstruct.place(newblock, block.blockNode, "after");
425                                }
426                                _letBrowserHandle = false;
427                                // lets move caret to the newly created block
428                                newrange = rangeapi.create(this.editor.window);
429                                newrange.setStart(newblock, 0);
430                                selection.removeAllRanges();
431                                selection.addRange(newrange);
432                                if(this.editor.height){
433                                        winUtils.scrollIntoView(newblock);
434                                }
435                        }else if(rangeapi.atBeginningOfContainer(block.blockNode,
436                                range.startContainer, range.startOffset)){
437                                domConstruct.place(newblock, block.blockNode, block.blockNode === block.blockContainer ? "first" : "before");
438                                if(newblock.nextSibling && this.editor.height){
439                                        // position input caret - mostly WebKit needs this
440                                        newrange = rangeapi.create(this.editor.window);
441                                        newrange.setStart(newblock.nextSibling, 0);
442                                        selection.removeAllRanges();
443                                        selection.addRange(newrange);
444                                        // browser does not scroll the caret position into view, do it manually
445                                        winUtils.scrollIntoView(newblock.nextSibling);
446                                }
447                                _letBrowserHandle = false;
448                        }else{ //press enter in the middle of P/DIV/Whatever/
449                                if(block.blockNode === block.blockContainer){
450                                        block.blockNode.appendChild(newblock);
451                                }else{
452                                        domConstruct.place(newblock, block.blockNode, "after");
453                                }
454                                _letBrowserHandle = false;
455
456                                // Clone any block level styles.
457                                if(block.blockNode.style){
458                                        if(newblock.style){
459                                                if(block.blockNode.style.cssText){
460                                                        newblock.style.cssText = block.blockNode.style.cssText;
461                                                }
462                                        }
463                                }
464
465                                // Okay, we probably have to split.
466                                rs = range.startContainer;
467                                var firstNodeMoved;
468                                if(rs && rs.nodeType == 3){
469                                        // Text node, we have to split it.
470                                        var nodeToMove, tNode;
471                                        endOffset = range.endOffset;
472                                        if(rs.length < endOffset){
473                                                //We are not splitting the right node, try to locate the correct one
474                                                ret = this._adjustNodeAndOffset(rs, endOffset);
475                                                rs = ret.node;
476                                                endOffset = ret.offset;
477                                        }
478
479                                        txt = rs.nodeValue;
480                                        startNode = doc.createTextNode(txt.substring(0, endOffset));
481                                        endNode = doc.createTextNode(txt.substring(endOffset, txt.length));
482
483                                        // Place the split, then remove original nodes.
484                                        domConstruct.place(startNode, rs, "before");
485                                        domConstruct.place(endNode, rs, "after");
486                                        domConstruct.destroy(rs);
487
488                                        // Okay, we split the text.  Now we need to see if we're
489                                        // parented to the block element we're splitting and if
490                                        // not, we have to split all the way up.  Ugh.
491                                        var parentC = startNode.parentNode;
492                                        while(parentC !== block.blockNode){
493                                                var tg = parentC.tagName;
494                                                var newTg = doc.createElement(tg);
495                                                // Clone over any 'style' data.
496                                                if(parentC.style){
497                                                        if(newTg.style){
498                                                                if(parentC.style.cssText){
499                                                                        newTg.style.cssText = parentC.style.cssText;
500                                                                }
501                                                        }
502                                                }
503                                                // If font also need to clone over any font data.
504                                                if(parentC.tagName === "FONT"){
505                                                        if(parentC.color){
506                                                                newTg.color = parentC.color;
507                                                        }
508                                                        if(parentC.face){
509                                                                newTg.face = parentC.face;
510                                                        }
511                                                        if(parentC.size){  // this check was necessary on IE
512                                                                newTg.size = parentC.size;
513                                                        }
514                                                }
515
516                                                nodeToMove = endNode;
517                                                while(nodeToMove){
518                                                        tNode = nodeToMove.nextSibling;
519                                                        newTg.appendChild(nodeToMove);
520                                                        nodeToMove = tNode;
521                                                }
522                                                domConstruct.place(newTg, parentC, "after");
523                                                startNode = parentC;
524                                                endNode = newTg;
525                                                parentC = parentC.parentNode;
526                                        }
527
528                                        // Lastly, move the split out tags to the new block.
529                                        // as they should now be split properly.
530                                        nodeToMove = endNode;
531                                        if(nodeToMove.nodeType == 1 || (nodeToMove.nodeType == 3 && nodeToMove.nodeValue)){
532                                                // Non-blank text and non-text nodes need to clear out that blank space
533                                                // before moving the contents.
534                                                newblock.innerHTML = "";
535                                        }
536                                        firstNodeMoved = nodeToMove;
537                                        while(nodeToMove){
538                                                tNode = nodeToMove.nextSibling;
539                                                newblock.appendChild(nodeToMove);
540                                                nodeToMove = tNode;
541                                        }
542                                }
543
544                                //lets move caret to the newly created block
545                                newrange = rangeapi.create(this.editor.window);
546                                var nodeForCursor;
547                                var innerMostFirstNodeMoved = firstNodeMoved;
548                                if(this.blockNodeForEnter !== 'BR'){
549                                        while(innerMostFirstNodeMoved){
550                                                nodeForCursor = innerMostFirstNodeMoved;
551                                                tNode = innerMostFirstNodeMoved.firstChild;
552                                                innerMostFirstNodeMoved = tNode;
553                                        }
554                                        if(nodeForCursor && nodeForCursor.parentNode){
555                                                newblock = nodeForCursor.parentNode;
556                                                newrange.setStart(newblock, 0);
557                                                selection.removeAllRanges();
558                                                selection.addRange(newrange);
559                                                if(this.editor.height){
560                                                        winUtils.scrollIntoView(newblock);
561                                                }
562                                                if(has("mozilla")){
563                                                        // press enter in middle of P may leave a trailing <br/>, let's remove it later
564                                                        this._pressedEnterInBlock = block.blockNode;
565                                                }
566                                        }else{
567                                                _letBrowserHandle = true;
568                                        }
569                                }else{
570                                        newrange.setStart(newblock, 0);
571                                        selection.removeAllRanges();
572                                        selection.addRange(newrange);
573                                        if(this.editor.height){
574                                                winUtils.scrollIntoView(newblock);
575                                        }
576                                        if(has("mozilla")){
577                                                // press enter in middle of P may leave a trailing <br/>, let's remove it later
578                                                this._pressedEnterInBlock = block.blockNode;
579                                        }
580                                }
581                        }
582                        return _letBrowserHandle;
583                },
584
585                _adjustNodeAndOffset: function(/*DomNode*/node, /*Int*/offset){
586                        // summary:
587                        //              In the case there are multiple text nodes in a row the offset may not be within the node.  If the offset is larger than the node length, it will attempt to find
588                        //              the next text sibling until it locates the text node in which the offset refers to
589                        // node:
590                        //              The node to check.
591                        // offset:
592                        //              The position to find within the text node
593                        // tags:
594                        //              private.
595                        while(node.length < offset && node.nextSibling && node.nextSibling.nodeType == 3){
596                                //Adjust the offset and node in the case of multiple text nodes in a row
597                                offset = offset - node.length;
598                                node = node.nextSibling;
599                        }
600                        return {"node": node, "offset": offset};
601                },
602
603                removeTrailingBr: function(container){
604                        // summary:
605                        //              If last child of container is a `<br>`, then remove it.
606                        // tags:
607                        //              private
608                        var para = /P|DIV|LI/i.test(container.tagName) ?
609                                container : this.editor.selection.getParentOfType(container, ['P', 'DIV', 'LI']);
610
611                        if(!para){
612                                return;
613                        }
614                        if(para.lastChild){
615                                if((para.childNodes.length > 1 && para.lastChild.nodeType == 3 && /^[\s\xAD]*$/.test(para.lastChild.nodeValue)) ||
616                                        para.lastChild.tagName == 'BR'){
617
618                                        domConstruct.destroy(para.lastChild);
619                                }
620                        }
621                        if(!para.childNodes.length){
622                                para.innerHTML = this.bogusHtmlContent;
623                        }
624                }
625        });
626
627});
Note: See TracBrowser for help on using the repository browser.