source: Dev/trunk/src/client/dojox/editor/plugins/NormalizeIndentOutdent.js

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

Added Dojo 1.9.3 release.

  • Property svn:executable set to *
File size: 24.2 KB
Line 
1define([
2        "dojo",
3        "dijit",
4        "dojox",
5        "dijit/_editor/_Plugin",
6        "dojo/_base/declare"
7], function(dojo, dijit, dojox, _Plugin) {
8
9var NormalizeIndentOutdent = dojo.declare("dojox.editor.plugins.NormalizeIndentOutdent", _Plugin, {
10        // summary:
11        //              This plugin provides improved indent and outdent handling to
12        //              the editor.  It tries to generate valid HTML, as well as be
13        //              consistent about how it indents and outdents lists and blocks/elements.
14
15        // indentBy: [public] number
16        //              The amount to indent by.  Valid values are 1+.  This is combined with
17        //              the indentUnits parameter to determine how much to indent or outdent
18        //              by for regular text.  It does not affect lists.
19        indentBy: 40,
20       
21        // indentUnits: [public] String
22        //              The units to apply to the indent amount.  Usually 'px', but can also
23        //              be em.
24        indentUnits: "px",
25
26        setEditor: function(editor){
27                // summary:
28                //              Over-ride for the setting of the editor.
29                // editor: Object
30                //              The editor to configure for this plugin to use.
31                this.editor = editor;
32
33                // Register out indent handler via the builtin over-ride mechanism.
34                editor._indentImpl = dojo.hitch(this, this._indentImpl);
35                editor._outdentImpl = dojo.hitch(this, this._outdentImpl);
36
37                // Take over the query command enabled function, we want to prevent
38                // indent of first items in a list, etc.
39                if(!editor._indentoutdent_queryCommandEnabled){
40                        editor._indentoutdent_queryCommandEnabled = editor.queryCommandEnabled;
41                }
42                editor.queryCommandEnabled = dojo.hitch(this, this._queryCommandEnabled);
43
44                // We need the custom undo code since we manipulate the dom
45                // outside of the browser natives and only customUndo really handles
46                // that.  It will incur a performance hit, but should hopefully be
47                // relatively small.
48                editor.customUndo = true;
49        },
50
51        _queryCommandEnabled: function(command){
52                // summary:
53                //              An over-ride for the editor's query command enabled,
54                //              so that we can prevent indents, etc, on bad elements
55                //              or positions (like first element in a list).
56                // command:
57                //              The command passed in to check enablement.
58                // tags:
59                //              private
60                var c = command.toLowerCase();
61                var ed, sel, range, node, tag, prevNode;
62                var style = "marginLeft";
63                if(!this._isLtr()){
64                        style = "marginRight";
65                }
66                if(c === "indent"){
67                        ed = this.editor;
68                        sel = dijit.range.getSelection(ed.window);
69                        if(sel && sel.rangeCount > 0){
70                                range = sel.getRangeAt(0);
71                                node = range.startContainer;
72
73                                // Check for li nodes first, we handle them a certain way.
74                                while(node && node !== ed.document && node !== ed.editNode){
75                                        tag = this._getTagName(node);
76                                        if(tag === "li"){
77                                               
78                                                prevNode = node.previousSibling;
79                                                while(prevNode && prevNode.nodeType !== 1){
80                                                        prevNode = prevNode.previousSibling;
81                                                }
82                                                if(prevNode && this._getTagName(prevNode) === "li"){
83                                                        return true;
84                                                }else{
85                                                        // First item, disallow
86                                                        return false;
87                                                }
88                                        }else if(this._isIndentableElement(tag)){
89                                                return true;
90                                        }
91                                        node = node.parentNode;
92                                }
93                                if(this._isRootInline(range.startContainer)){
94                                        return true;
95                                }
96                        }
97                }else if(c === "outdent"){
98                        ed = this.editor;
99                        sel = dijit.range.getSelection(ed.window);
100                        if(sel && sel.rangeCount > 0){
101                                range = sel.getRangeAt(0);
102                                node = range.startContainer;
103                                // Check for li nodes first, we handle them a certain way.
104                                while(node && node !== ed.document && node !== ed.editNode){
105                                        tag = this._getTagName(node);
106                                        if(tag === "li"){
107                                                // Standard list, we can ask the browser.
108                                                return this.editor._indentoutdent_queryCommandEnabled(command);
109                                        }else if(this._isIndentableElement(tag)){
110                                                // Block, we need to handle the indent check.
111                                                var cIndent = node.style?node.style[style]:"";
112                                                if(cIndent){
113                                                        cIndent = this._convertIndent(cIndent);
114                                                        if(cIndent/this.indentBy >= 1){
115                                                                return true;
116                                                        }
117                                                }
118                                                return false;
119                                        }
120                                        node = node.parentNode;
121                                }
122                                if(this._isRootInline(range.startContainer)){
123                                        return false;
124                                }
125                        }
126                }else{
127                        return this.editor._indentoutdent_queryCommandEnabled(command);
128                }
129                return false;
130        },
131
132        _indentImpl: function(/*String*/ html) {
133                // summary:
134                //              Improved implementation of indent, generates correct indent for
135                //              ul/ol
136                var ed = this.editor;
137
138                var sel = dijit.range.getSelection(ed.window);
139                if(sel && sel.rangeCount > 0){
140                        var range = sel.getRangeAt(0);
141                        var node = range.startContainer;
142                        var tag, start, end, div;
143                       
144
145                        if(range.startContainer === range.endContainer){
146                                // No selection, just cursor point, we need to see if we're
147                                // in an indentable block, or similar.
148                                if(this._isRootInline(range.startContainer)){
149                                        // Text at the 'root' of the document,
150                                        // we'll try to indent it and all inline selements around it
151                                        // as they are visually a single line.
152
153                                        // First, we need to find the toplevel inline element that is rooted
154                                        // to the document 'editNode'
155                                        start = range.startContainer;
156                                        while(start && start.parentNode !== ed.editNode){
157                                                start = start.parentNode;
158                                        }
159
160                                        // Now we need to walk up its siblings and look for the first one in the rooting
161                                        // that isn't inline or text, as we want to grab all of that for indent.
162                                        while(start && start.previousSibling && (
163                                                        this._isTextElement(start) ||
164                                                        (start.nodeType === 1 && this._isInlineFormat(this._getTagName(start))
165                                                ))){
166                                                start = start.previousSibling;
167                                        }
168                                        if(start && start.nodeType === 1 && !this._isInlineFormat(this._getTagName(start))){
169                                                // Adjust slightly, we're one node too far back in this case.
170                                                start = start.nextSibling;
171                                        }
172
173                                        // Okay, we have a configured start, lets grab everything following it that's
174                                        // inline and make it an indentable block!
175                                        if(start){
176                                                div = ed.document.createElement("div");
177                                                dojo.place(div, start, "after");
178                                                div.appendChild(start);
179                                                end = div.nextSibling;
180                                                while(end && (
181                                                        this._isTextElement(end) ||
182                                                        (end.nodeType === 1 &&
183                                                                this._isInlineFormat(this._getTagName(end)))
184                                                        )){
185                                                        // Add it.
186                                                        div.appendChild(end);
187                                                        end = div.nextSibling;
188                                                }
189                                                this._indentElement(div);
190                                                ed._sCall("selectElementChildren", [div]);
191                                                ed._sCall("collapse", [true]);
192                                        }
193                                }else{
194                                        while(node && node !== ed.document && node !== ed.editNode){
195                                                tag = this._getTagName(node);
196                                                if(tag === "li"){
197                                                        this._indentList(node);
198                                                        return;
199                                                }else if(this._isIndentableElement(tag)){
200                                                        this._indentElement(node);
201                                                        return;
202                                                }
203                                                node = node.parentNode;
204                                        }
205                                }
206                        }else{
207                                var curNode;
208                                // multi-node select.  We need to scan over them.
209                                // Find the two containing nodes at start and end.
210                                // then move the end one node past.  Then ... lets see
211                                // what we can indent!
212                                start = range.startContainer;
213                                end = range.endContainer;
214                                // Find the non-text nodes.
215
216                                while(start && this._isTextElement(start) && start.parentNode !== ed.editNode){
217                                        start = start.parentNode;
218                                }
219                                while(end && this._isTextElement(end) && end.parentNode !== ed.editNode){
220                                        end = end.parentNode;
221                                }
222                                if(end === ed.editNode || end === ed.document.body){
223                                        // Okay, selection end is somewhere after start, we need to find the last node
224                                        // that is safely in the range.
225                                        curNode = start;
226                                        while(curNode.nextSibling &&
227                                                ed._sCall("inSelection", [curNode])){
228                                                curNode = curNode.nextSibling;
229                                        }
230                                        end = curNode;
231                                        if(end === ed.editNode || end === ed.document.body){
232                                                // Unable to determine real selection end, so just make it
233                                                // a single node indent of start + all following inline styles, if
234                                                // present, then just exit.
235                                                tag = this._getTagName(start);
236                                                if(tag === "li"){
237                                                        this._indentList(start);
238                                                }else if(this._isIndentableElement(tag)){
239                                                        this._indentElement(start);
240                                                }else if(this._isTextElement(start) ||
241                                                                 this._isInlineFormat(tag)){
242                                                        // inline element or textnode, So we want to indent it somehow
243                                                        div = ed.document.createElement("div");
244                                                        dojo.place(div, start, "after");
245
246                                                        // Find and move all inline tags following the one we inserted also into the
247                                                        // div so we don't split up content funny.
248                                                        var next = start;
249                                                        while(next && (
250                                                                this._isTextElement(next) ||
251                                                                (next.nodeType === 1 &&
252                                                                this._isInlineFormat(this._getTagName(next))))){
253                                                                div.appendChild(next);
254                                                                next = div.nextSibling;
255                                                        }
256                                                        this._indentElement(div);
257                                                }
258                                                return;
259                                        }
260                                }
261                               
262                                // Has a definite end somewhere, so lets try to indent up to it.
263                                // requires looking at the selections and in some cases, moving nodes
264                                // into indentable blocks.
265                                end = end.nextSibling;
266                                curNode = start;
267                                while(curNode && curNode !== end){
268                                        if(curNode.nodeType === 1){
269                                                tag = this._getTagName(curNode);
270                                                if(dojo.isIE){
271                                                        // IE sometimes inserts blank P tags, which we want to skip
272                                                        // as they end up indented, which messes up layout.
273                                                        if(tag === "p" && this._isEmpty(curNode)){
274                                                                curNode = curNode.nextSibling;
275                                                                continue;
276                                                        }
277                                                }
278                                                if(tag === "li"){
279                                                        if(div){
280                                                                if(this._isEmpty(div)){
281                                                                        div.parentNode.removeChild(div);
282                                                                }else{
283                                                                        this._indentElement(div);
284                                                                }
285                                                                div = null;
286                                                        }
287                                                        this._indentList(curNode);
288                                                }else if(!this._isInlineFormat(tag) && this._isIndentableElement(tag)){
289                                                        if(div){
290                                                                if(this._isEmpty(div)){
291                                                                        div.parentNode.removeChild(div);
292                                                                }else{
293                                                                        this._indentElement(div);
294                                                                }
295                                                                div = null;
296                                                        }
297                                                        curNode = this._indentElement(curNode);
298                                                }else if(this._isInlineFormat(tag)){
299                                                        // inline tag.
300                                                        if(!div){
301                                                                div = ed.document.createElement("div");
302                                                                dojo.place(div, curNode, "after");
303                                                                div.appendChild(curNode);
304                                                                curNode = div;
305                                                        }else{
306                                                                div.appendChild(curNode);
307                                                                curNode = div;
308                                                        }
309                                                }
310                                        }else if(this._isTextElement(curNode)){
311                                                if(!div){
312                                                        div = ed.document.createElement("div");
313                                                        dojo.place(div, curNode, "after");
314                                                        div.appendChild(curNode);
315                                                        curNode = div;
316                                                }else{
317                                                        div.appendChild(curNode);
318                                                        curNode = div;
319                                                }
320                                        }
321                                        curNode = curNode.nextSibling;
322                                }
323                                // Okay, indent everything we merged if we haven't yet..
324                                if(div){
325                                        if(this._isEmpty(div)){
326                                                div.parentNode.removeChild(div);
327                                        }else{
328                                                this._indentElement(div);
329                                        }
330                                        div = null;
331                                }
332                        }
333                }
334        },
335
336        _indentElement: function(node){
337                // summary:
338                //              Function to indent a block type tag.
339                // node:
340                //              The node who's content to indent.
341                // tags:
342                //              private
343                var style = "marginLeft";
344                if(!this._isLtr()){
345                        style = "marginRight";
346                }
347                var tag = this._getTagName(node);
348                if(tag === "ul" || tag === "ol"){
349                        // Lists indent funny, so lets wrap them in a div
350                        // and indent the div instead.
351                        var div = this.editor.document.createElement("div");
352                        dojo.place(div, node, "after");
353                        div.appendChild(node);
354                        node = div;
355                }
356                var cIndent = node.style?node.style[style]:"";
357                if(cIndent){
358                        cIndent = this._convertIndent(cIndent);
359                        cIndent = (parseInt(cIndent, 10) + this.indentBy) + this.indentUnits;
360                }else{
361                        cIndent = this.indentBy + this.indentUnits;
362                }
363                dojo.style(node, style, cIndent);
364                return node; //Return the node that was indented.
365        },
366
367        _outdentElement: function(node){
368                // summary:
369                //              Function to outdent a block type tag.
370                // node:
371                //              The node who's content to outdent.
372                // tags:
373                //              private
374                var style = "marginLeft";
375                if(!this._isLtr()){
376                        style = "marginRight";
377                }
378                var cIndent = node.style?node.style[style]:"";
379                if(cIndent){
380                        cIndent = this._convertIndent(cIndent);
381                        if(cIndent - this.indentBy > 0){
382                                cIndent = (parseInt(cIndent, 10) - this.indentBy) + this.indentUnits;
383                        }else{
384                                cIndent = "";
385                        }
386                        dojo.style(node, style, cIndent);
387                }
388        },
389
390        _outdentImpl: function(/*String*/ html) {
391                // summary:
392                //              Improved implementation of outdent, generates correct indent for
393                //              ul/ol and other elements.
394                // tags:
395                //              private
396                var ed = this.editor;
397                var sel = dijit.range.getSelection(ed.window);
398                if(sel && sel.rangeCount > 0){
399                        var range = sel.getRangeAt(0);
400                        var node = range.startContainer;
401                        var tag;
402
403                        if(range.startContainer === range.endContainer){
404                                // Check for li nodes first, we handle them a certain way.
405                                while(node && node !== ed.document && node !== ed.editNode){
406                                        tag = this._getTagName(node);
407                                        if(tag === "li"){
408                                                return this._outdentList(node);
409                                        }else if(this._isIndentableElement(tag)){
410                                                return this._outdentElement(node);
411                                        }
412                                        node = node.parentNode;
413                                }
414                                ed.document.execCommand("outdent", false, html);
415                        }else{
416                                // multi-node select.  We need to scan over them.
417                                // Find the two containing nodes at start and end.
418                                // then move the end one node past.  Then ... lets see
419                                // what we can outdent!
420                                var start = range.startContainer;
421                                var end =  range.endContainer;
422                                // Find the non-text nodes.
423                                while(start && start.nodeType === 3){
424                                        start = start.parentNode;
425                                }
426                                while(end && end.nodeType === 3){
427                                        end = end.parentNode;
428                                }
429                                end = end.nextSibling;
430                                var curNode = start;
431                                while(curNode && curNode !== end){
432                                        if(curNode.nodeType === 1){
433                                                tag = this._getTagName(curNode);
434                                                if(tag === "li"){
435                                                        this._outdentList(curNode);
436                                                }else if(this._isIndentableElement(tag)){
437                                                        this._outdentElement(curNode);
438                                                }
439
440                                        }
441                                        curNode = curNode.nextSibling;
442                                }
443                        }
444                }
445                return null;
446        },
447
448
449        _indentList: function(listItem){
450                // summary:
451                //              Internal function to handle indenting a list element.
452                // listItem:
453                //              The list item to indent.
454                // tags:
455                //              private
456                var ed = this.editor;
457                var newList, li;
458                var listContainer = listItem.parentNode;
459                var prevTag = listItem.previousSibling;
460               
461                // Ignore text, we want elements.
462                while(prevTag && prevTag.nodeType !== 1){
463                        prevTag = prevTag.previousSibling;
464                }
465                var type = null;
466                var tg = this._getTagName(listContainer);
467               
468                // Try to determine what kind of list item is here to indent.
469                if(tg === "ol"){
470                        type = "ol";
471                }else if(tg === "ul"){
472                        type = "ul";
473                }
474               
475                // Only indent list items actually in a list.
476                // Bail out if the list is malformed somehow.
477                if(type){
478                        // There is a previous node in the list, so we want to append a new list
479                        // element after it that contains a new list of the content to indent it.
480                        if(prevTag && prevTag.tagName.toLowerCase() == "li"){
481                                // Lets see if we can merge this into another  (Eg,
482                                // does the sibling li contain an embedded list already of
483                                // the same type?  if so, we move into that one.
484                                var embList;
485                                if(prevTag.childNodes){
486                                        var i;
487                                        for(i = 0; i < prevTag.childNodes.length; i++){
488                                                var n = prevTag.childNodes[i];
489                                                if(n.nodeType === 3){
490                                                        if(dojo.trim(n.nodeValue)){
491                                                                if(embList){
492                                                                        // Non-empty text after list, exit, can't embed.
493                                                                        break;
494                                                                }
495                                                        }
496                                                }else if(n.nodeType === 1 && !embList){
497                                                        // See if this is a list container.
498                                                        if(type === n.tagName.toLowerCase()){
499                                                                embList = n;
500                                                        }
501                                                }else{
502                                                        // Other node present, break, can't embed.
503                                                        break;
504                                                }
505                                        }
506                                }
507                                if(embList){
508                                        // We found a list to merge to, so merge.
509                                        embList.appendChild(listItem);
510                                }else{
511                                        // Nope, wasn't an embedded list container,
512                                        // So lets just create a new one.
513                                        newList = ed.document.createElement(type);
514                                        dojo.style(newList, {
515                                                paddingTop: "0px",
516                                                paddingBottom: "0px"
517                                        });
518                                        li = ed.document.createElement("li");
519                                        dojo.style(li, {
520                                                listStyleImage: "none",
521                                                listStyleType: "none"
522                                        });
523                                        prevTag.appendChild(newList);
524                                        newList.appendChild(listItem);
525                                }
526
527                                // Move cursor.
528                                ed._sCall("selectElementChildren", [listItem]);
529                                ed._sCall("collapse", [true]);
530                        }
531                }
532        },
533
534        _outdentList: function(listItem){
535                // summary:
536                //              Internal function to handle outdenting a list element.
537                // listItem:
538                //              The list item to outdent.
539                // tags:
540                //              private
541                var ed = this.editor;
542                var list = listItem.parentNode;
543                var type = null;
544                var tg = list.tagName ? list.tagName.toLowerCase() : "";
545                var li;
546
547                // Try to determine what kind of list contains the item.
548                if(tg === "ol"){
549                        type = "ol";
550                }else if(tg === "ul"){
551                        type = "ul";
552                }
553
554                // Check to see if it is a nested list, as outdenting is handled differently.
555                var listParent = list.parentNode;
556                var lpTg = this._getTagName(listParent);
557               
558                // We're in a list, so we need to outdent this specially.
559                // Check for welformed and malformed lists (<ul><ul></ul>U/ul> type stuff).
560                if(lpTg === "li" || lpTg === "ol" || lpTg === "ul"){
561                        if(lpTg === "ol" || lpTg === "ul"){
562                                // Okay, we need to fix this up, this is invalid html,
563                                // So try to combine this into a previous element before
564                                // de do a shuffle of the nodes, to build an HTML compliant
565                                // list.
566                                var prevListLi = list.previousSibling;
567                                while(prevListLi && (prevListLi.nodeType !== 1 ||
568                                                (prevListLi.nodeType === 1 &&
569                                                this._getTagName(prevListLi) !== "li"))
570                                        ){
571                                        prevListLi = prevListLi.previousSibling;
572                                }
573                                if(prevListLi){
574                                        // Move this list up into the previous li
575                                        // to fix malformation.
576                                        prevListLi.appendChild(list);
577                                        listParent = prevListLi;
578                                }else{
579                                        li = listItem;
580                                        var firstItem = listItem;
581                                        while(li.previousSibling){
582                                                li = li.previousSibling;
583                                                if(li.nodeType === 1 && this._getTagName(li) === "li"){
584                                                        firstItem = li;
585                                                }
586                                        }
587
588                                        if(firstItem !== listItem){
589                                                dojo.place(firstItem, list, "before");
590                                                firstItem.appendChild(list);
591                                                listParent = firstItem;
592                                        }else{
593                                                // No previous list item in a malformed list
594                                                // ... so create one  and move into that.
595                                                li = ed.document.createElement("li");
596                                                dojo.place(li, list, "before");
597                                                li.appendChild(list);
598                                                listParent = li;
599                                        }
600                                        dojo.style(list, {
601                                                paddingTop: "0px",
602                                                paddingBottom: "0px"
603                                        });
604                                }
605                        }
606
607                        // find the previous node, if any,
608                        // non-text.
609                        var prevLi = listItem.previousSibling;
610                        while(prevLi && prevLi.nodeType !== 1){
611                                prevLi = prevLi.previousSibling;
612                        }
613                        var nextLi = listItem.nextSibling;
614                        while(nextLi && nextLi.nodeType !== 1){
615                                nextLi = nextLi.nextSibling;
616                        }
617
618                        if(!prevLi){
619                                // Top item in a nested list, so just move it out
620                                // and then shuffle the remaining indented list into it.
621                                dojo.place(listItem, listParent, "after");
622                                listItem.appendChild(list);
623                        }else if(!nextLi){
624                                // Last item in a nested list, shuffle it out after
625                                // the nsted list only.
626                                dojo.place(listItem, listParent, "after");
627                        }else{
628                                // Item is in the middle of an embedded  list, so we
629                                // have to split it.
630
631                                // Move all the items following current list item into
632                                // a list after it.
633                                var newList = ed.document.createElement(type);
634                                dojo.style(newList, {
635                                        paddingTop: "0px",
636                                        paddingBottom: "0px"
637                                });
638                                listItem.appendChild(newList);
639                                while(listItem.nextSibling){
640                                        newList.appendChild(listItem.nextSibling);
641                                }
642
643                                // Okay, now place the list item after the
644                                // current list parent (li).
645                                dojo.place(listItem, listParent, "after");
646                        }
647                       
648                        // Clean up any empty lists left behind.
649                        if(list && this._isEmpty(list)){
650                                list.parentNode.removeChild(list);
651                        }
652                        if(listParent && this._isEmpty(listParent)){
653                                listParent.parentNode.removeChild(listParent);
654                        }
655                       
656                        // Move our cursor to the list item we moved.
657                        ed._sCall("selectElementChildren", [listItem]);
658                        ed._sCall("collapse", [true]);
659                }else{
660                        // Not in a nested list, so we can just defer to the
661                        // browser and hope it outdents right.
662                        ed.document.execCommand("outdent", false, null);
663                }
664        },
665
666        _isEmpty: function(node){
667                // summary:
668                //              Internal function to determine if a node is 'empty'
669                //              Eg, contains only blank text.  Used to determine if
670                //              an empty list element should be removed or not.
671                // node:
672                //              The node to check.
673                // tags:
674                //              private
675                if(node.childNodes){
676                        var empty = true;
677                        var i;
678                        for(i = 0; i < node.childNodes.length; i++){
679                                var n = node.childNodes[i];
680                                if(n.nodeType === 1){
681                                        if(this._getTagName(n) === "p"){
682                                                if(!dojo.trim(n.innerHTML)){
683                                                        continue;
684                                                }
685                                        }
686                                        empty = false;
687                                        break;
688                                }else if(this._isTextElement(n)){
689                                        // Check for empty text.
690                                        var nv = dojo.trim(n.nodeValue);
691                                        if(nv && nv !=="&nbsp;" && nv !== "\u00A0"){
692                                                empty = false;
693                                                break;
694                                        }
695                                }else{
696                                        empty = false;
697                                        break;
698                                }
699                        }
700                        return empty;
701                }else{
702                        return true;
703                }
704        },
705
706        _isIndentableElement: function(tag){
707                // summary:
708                //              Internal function to detect what element types
709                //              are indent-controllable by us.
710                // tag:
711                //              The tag to check
712                // tags:
713                //              private
714                switch(tag){
715                        case "p":
716                        case "div":
717                        case "h1":
718                        case "h2":
719                        case "h3":
720                        case "center":
721                        case "table":
722                        case "ul":
723                        case "ol":
724                                return true;
725                        default:
726                                return false;
727                }
728        },
729
730        _convertIndent: function(indent){
731                // summary:
732                //              Function to convert the current indent style to
733                //              the units we're using by some heuristic.
734                // indent:
735                //              The indent amount to convert.
736                // tags:
737                //              private
738                var pxPerEm = 12;
739                indent = indent + "";
740                indent = indent.toLowerCase();
741                var curUnit = (indent.indexOf("px") > 0) ? "px" : (indent.indexOf("em") > 0) ? "em" : "px";
742                indent = indent.replace(/(px;?|em;?)/gi, "");
743                if(curUnit === "px"){
744                        if(this.indentUnits === "em"){
745                                indent = Math.ceil(indent/pxPerEm);
746                        }
747                }else{
748                        if(this.indentUnits === "px"){
749                                indent = indent * pxPerEm;
750                        }
751                }
752                return indent;
753        },
754
755        _isLtr: function(){
756                // summary:
757                //              Function to detect if the editor body is in RTL or LTR.
758                // tags:
759                //              private
760                var editDoc = this.editor.document.body;
761                var cs = dojo.getComputedStyle(editDoc);
762                return cs ? cs.direction == "ltr" : true;
763        },
764
765        _isInlineFormat: function(tag){
766                // summary:
767                //              Function to determine if the current tag is an inline
768                //              element that does formatting, as we don't want to
769                //              break/indent around it, as it can screw up text.
770                // tag:
771                //              The tag to examine
772                // tags:
773                //              private
774                switch(tag){
775                        case "a":
776                        case "b":
777                        case "strong":
778                        case "s":
779                        case "strike":
780                        case "i":
781                        case "u":
782                        case "em":
783                        case "sup":
784                        case "sub":
785                        case "span":
786                        case "font":
787                        case "big":
788                        case "cite":
789                        case "q":
790                        case "img":
791                        case "small":
792                                return true;
793                        default:
794                                return false;
795                }
796        },
797
798        _getTagName: function(node){
799                // summary:
800                //              Internal function to get the tag name of an element
801                //              if any.
802                // node:
803                //              The node to look at.
804                // tags:
805                //              private
806                var tag = "";
807                if(node && node.nodeType === 1){
808                        tag = node.tagName?node.tagName.toLowerCase():"";
809                }
810                return tag;
811        },
812
813        _isRootInline: function(node){
814                // summary:
815                //              This functions tests whether an indicated node is in root as inline
816                //              or rooted inline elements in the page.
817                // node:
818                //              The node to start at.
819                // tags:
820                //              private
821                var ed = this.editor;
822                if(this._isTextElement(node) && node.parentNode === ed.editNode){
823                        return true;
824                }else if(node.nodeType === 1 && this._isInlineFormat(node) && node.parentNode === ed.editNode){
825                        return true;
826                }else if(this._isTextElement(node) && this._isInlineFormat(this._getTagName(node.parentNode))){
827                        node = node.parentNode;
828                        while(node && node !== ed.editNode && this._isInlineFormat(this._getTagName(node))){
829                                node = node.parentNode;
830                        }
831                        if(node === ed.editNode){
832                                return true;
833                        }
834                }
835                return false;
836        },
837
838        _isTextElement: function(node){
839                // summary:
840                //              Helper function to check for text nodes.
841                // node:
842                //              The node to check.
843                // tags:
844                //              private
845                if(node && node.nodeType === 3 || node.nodeType === 4){
846                        return true;
847                }
848                return false;
849        }
850});
851
852// Register this plugin.
853dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
854        if(o.plugin){ return; }
855        var name = o.args.name.toLowerCase();
856        if(name === "normalizeindentoutdent"){
857                o.plugin = new NormalizeIndentOutdent({
858                        indentBy: ("indentBy" in o.args) ?
859                                (o.args.indentBy > 0 ? o.args.indentBy : 40) :
860                                40,
861                        indentUnits: ("indentUnits" in o.args) ?
862                                (o.args.indentUnits.toLowerCase() == "em"? "em" : "px") :
863                                "px"
864                });
865        }
866});
867
868return NormalizeIndentOutdent;
869
870});
Note: See TracBrowser for help on using the repository browser.