| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882 | 
							- /*
 
- 	Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
 
- 	Available via Academic Free License >= 2.1 OR the modified BSD license.
 
- 	see: http://dojotoolkit.org/license for details
 
- */
 
- if(!dojo._hasResource["dojox.editor.plugins.NormalizeIndentOutdent"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
 
- dojo._hasResource["dojox.editor.plugins.NormalizeIndentOutdent"] = true;
 
- dojo.provide("dojox.editor.plugins.NormalizeIndentOutdent");
 
- dojo.require("dijit._editor.selection");
 
- dojo.require("dijit._editor._Plugin");
 
- dojo.declare("dojox.editor.plugins.NormalizeIndentOutdent",dijit._editor._Plugin,{
 
- 	// summary:
 
- 	//		This plugin provides improved indent and outdent handling to
 
- 	//		the editor.  It tries to generate valid HTML, as well as be
 
- 	//		consistent about how it indents and outdents lists and blocks/elements.
 
- 	// indentBy: [public] number
 
- 	//		The amount to indent by.  Valid values are 1+.  This is combined with
 
- 	//		the indentUnits parameter to determine how much to indent or outdent
 
- 	//		by for regular text.  It does not affect lists.
 
- 	indentBy: 40,
 
- 	
 
- 	// indentUnits: [public] String
 
- 	//		The units to apply to the indent amount.  Usually 'px', but can also
 
- 	//		be em.
 
- 	indentUnits: "px",
 
- 	setEditor: function(editor){
 
- 		// summary:
 
- 		//		Over-ride for the setting of the editor.
 
- 		// editor: Object
 
- 		//		The editor to configure for this plugin to use.
 
- 		this.editor = editor;
 
- 		// Register out indent handler via the builtin over-ride mechanism.
 
- 		editor._indentImpl = dojo.hitch(this, this._indentImpl);
 
- 		editor._outdentImpl = dojo.hitch(this, this._outdentImpl);
 
- 		// Take over the query command enabled function, we want to prevent
 
- 		// indent of first items in a list, etc.
 
- 		if(!editor._indentoutdent_queryCommandEnabled){
 
- 			editor._indentoutdent_queryCommandEnabled = editor.queryCommandEnabled;
 
- 		}
 
- 		editor.queryCommandEnabled = dojo.hitch(this, this._queryCommandEnabled);
 
- 		// We need the custom undo code since we manipulate the dom
 
- 		// outside of the browser natives and only customUndo really handles
 
- 		// that.  It will incur a performance hit, but should hopefully be
 
- 		// relatively small.
 
- 		editor.customUndo = true;
 
- 	},
 
- 	_queryCommandEnabled: function(command){
 
- 		// summary:
 
- 		//		An over-ride for the editor's query command enabled,
 
- 		//		so that we can prevent indents, etc, on bad elements
 
- 		//		or positions (like first element in a list).
 
- 		// command:
 
- 		//		The command passed in to check enablement.
 
- 		// tags:
 
- 		//		private
 
- 		var c = command.toLowerCase();
 
- 		var ed, sel, range, node, tag, prevNode;
 
- 		var style = "marginLeft";
 
- 		if(!this._isLtr()){
 
- 			style = "marginRight";
 
- 		}
 
- 		if(c === "indent"){
 
- 			ed = this.editor;
 
- 			sel = dijit.range.getSelection(ed.window);
 
- 			if(sel && sel.rangeCount > 0){
 
- 				range = sel.getRangeAt(0);
 
- 				node = range.startContainer;
 
- 				// Check for li nodes first, we handle them a certain way.
 
- 				while(node && node !== ed.document && node !== ed.editNode){
 
- 					tag = this._getTagName(node);
 
- 					if(tag === "li"){
 
- 						
 
- 						prevNode = node.previousSibling;
 
- 						while(prevNode && prevNode.nodeType !== 1){
 
- 							prevNode = prevNode.previousSibling;
 
- 						}
 
- 						if(prevNode && this._getTagName(prevNode) === "li"){
 
- 							return true;
 
- 						}else{
 
- 							// First item, disallow
 
- 							return false;
 
- 						}
 
- 					}else if(this._isIndentableElement(tag)){
 
- 						return true;
 
- 					}
 
- 					node = node.parentNode;
 
- 				}
 
- 				if(this._isRootInline(range.startContainer)){
 
- 					return true;
 
- 				}
 
- 			}
 
- 		}else if(c === "outdent"){
 
- 			ed = this.editor;
 
- 			sel = dijit.range.getSelection(ed.window);
 
- 			if(sel && sel.rangeCount > 0){
 
- 				range = sel.getRangeAt(0);
 
- 				node = range.startContainer;
 
- 				// Check for li nodes first, we handle them a certain way.
 
- 				while(node && node !== ed.document && node !== ed.editNode){
 
- 					tag = this._getTagName(node);
 
- 					if(tag === "li"){
 
- 						// Standard list, we can ask the browser.
 
- 						return this.editor._indentoutdent_queryCommandEnabled(command);
 
- 					}else if(this._isIndentableElement(tag)){
 
- 						// Block, we need to handle the indent check.
 
- 						var cIndent = node.style?node.style[style]:"";
 
- 						if(cIndent){
 
- 							cIndent = this._convertIndent(cIndent);
 
- 							if(cIndent/this.indentBy >= 1){
 
- 								return true;
 
- 							}
 
- 						}
 
- 						return false;
 
- 					}
 
- 					node = node.parentNode;
 
- 				}
 
- 				if(this._isRootInline(range.startContainer)){
 
- 					return false;
 
- 				}
 
- 			}
 
- 		}else{
 
- 			return this.editor._indentoutdent_queryCommandEnabled(command);
 
- 		}
 
- 		return false;
 
- 	},
 
- 	_indentImpl: function(/*String*/ html) {
 
- 		// summary:
 
- 		//		Improved implementation of indent, generates correct indent for
 
- 		//		ul/ol
 
- 		var ed = this.editor;
 
- 		var sel = dijit.range.getSelection(ed.window);
 
- 		if(sel && sel.rangeCount > 0){
 
- 			var range = sel.getRangeAt(0);
 
- 			var node = range.startContainer;
 
- 			var tag, start, end, div;
 
- 			
 
- 			if(range.startContainer === range.endContainer){
 
- 				// No selection, just cursor point, we need to see if we're
 
- 				// in an indentable block, or similar.
 
- 				if(this._isRootInline(range.startContainer)){
 
- 					// Text at the 'root' of the document,
 
- 					// we'll try to indent it and all inline selements around it
 
- 					// as they are visually a single line.
 
- 					// First, we need to find the toplevel inline element that is rooted
 
- 					// to the document 'editNode'
 
- 					start = range.startContainer;
 
- 					while(start && start.parentNode !== ed.editNode){
 
- 						start = start.parentNode;
 
- 					}
 
- 					// Now we need to walk up its siblings and look for the first one in the rooting
 
- 					// that isn't inline or text, as we want to grab all of that for indent.
 
- 					while(start && start.previousSibling && (
 
- 							this._isTextElement(start) ||
 
- 							(start.nodeType === 1 && this._isInlineFormat(this._getTagName(start))
 
- 						))){
 
- 						start = start.previousSibling;
 
- 					}
 
- 					if(start && start.nodeType === 1 && !this._isInlineFormat(this._getTagName(start))){
 
- 						// Adjust slightly, we're one node too far back in this case.
 
- 						start = start.nextSibling;
 
- 					}
 
- 					// Okay, we have a configured start, lets grab everything following it that's
 
- 					// inline and make it an indentable block!
 
- 					if(start){
 
- 						div = ed.document.createElement("div");
 
- 						dojo.place(div, start, "after");
 
- 						div.appendChild(start);
 
- 						end = div.nextSibling;
 
- 						while(end && (
 
- 							this._isTextElement(end) ||
 
- 							(end.nodeType === 1 &&
 
- 								this._isInlineFormat(this._getTagName(end)))
 
- 							)){
 
- 							// Add it.
 
- 							div.appendChild(end);
 
- 							end = div.nextSibling;
 
- 						}
 
- 						this._indentElement(div);
 
- 						dojo.withGlobal(ed.window,
 
- 							"selectElementChildren", dijit._editor.selection, [div]);
 
- 						dojo.withGlobal(ed.window,
 
- 							"collapse", dijit._editor.selection, [true]);
 
- 					}
 
- 				}else{
 
- 					while(node && node !== ed.document && node !== ed.editNode){
 
- 						tag = this._getTagName(node);
 
- 						if(tag === "li"){
 
- 							this._indentList(node);
 
- 							return;
 
- 						}else if(this._isIndentableElement(tag)){
 
- 							this._indentElement(node);
 
- 							return;
 
- 						}
 
- 						node = node.parentNode;
 
- 					}
 
- 				}
 
- 			}else{
 
- 				var curNode;
 
- 				// multi-node select.  We need to scan over them.
 
- 				// Find the two containing nodes at start and end.
 
- 				// then move the end one node past.  Then ... lets see
 
- 				// what we can indent!
 
- 				start = range.startContainer;
 
- 				end = range.endContainer;
 
- 				// Find the non-text nodes.
 
- 				while(start && this._isTextElement(start) && start.parentNode !== ed.editNode){
 
- 					start = start.parentNode;
 
- 				}
 
- 				while(end && this._isTextElement(end) && end.parentNode !== ed.editNode){
 
- 					end = end.parentNode;
 
- 				}
 
- 				if(end === ed.editNode || end === ed.document.body){
 
- 					// Okay, selection end is somewhere after start, we need to find the last node
 
- 					// that is safely in the range.
 
- 					curNode = start;
 
- 					while(curNode.nextSibling &&
 
- 						dojo.withGlobal(ed.window, "inSelection", dijit._editor.selection, [curNode])){
 
- 						curNode = curNode.nextSibling;
 
- 					}
 
- 					end = curNode;
 
- 					if(end === ed.editNode || end === ed.document.body){
 
- 						// Unable to determine real selection end, so just make it
 
- 						// a single node indent of start + all following inline styles, if
 
- 						// present, then just exit.
 
- 						tag = this._getTagName(start);
 
- 						if(tag === "li"){
 
- 							this._indentList(start);
 
- 						}else if(this._isIndentableElement(tag)){
 
- 							this._indentElement(start);
 
- 						}else if(this._isTextElement(start) ||
 
- 								 this._isInlineFormat(tag)){
 
- 							// inline element or textnode, So we want to indent it somehow
 
- 							div = ed.document.createElement("div");
 
- 							dojo.place(div, start, "after");
 
- 							// Find and move all inline tags following the one we inserted also into the
 
- 							// div so we don't split up content funny.
 
- 							var next = start;
 
- 							while(next && (
 
- 								this._isTextElement(next) ||
 
- 								(next.nodeType === 1 &&
 
- 								this._isInlineFormat(this._getTagName(next))))){
 
- 								div.appendChild(next);
 
- 								next = div.nextSibling;
 
- 							}
 
- 							this._indentElement(div);
 
- 						}
 
- 						return;
 
- 					}
 
- 				}
 
- 				
 
- 				// Has a definite end somewhere, so lets try to indent up to it.
 
- 				// requires looking at the selections and in some cases, moving nodes
 
- 				// into indentable blocks.
 
- 				end = end.nextSibling;
 
- 				curNode = start;
 
- 				while(curNode && curNode !== end){
 
- 					if(curNode.nodeType === 1){
 
- 						tag = this._getTagName(curNode);
 
- 						if(dojo.isIE){
 
- 							// IE sometimes inserts blank P tags, which we want to skip
 
- 							// as they end up indented, which messes up layout.
 
- 							if(tag === "p" && this._isEmpty(curNode)){
 
- 								curNode = curNode.nextSibling;
 
- 								continue;
 
- 							}
 
- 						}
 
- 						if(tag === "li"){
 
- 							if(div){
 
- 								if(this._isEmpty(div)){
 
- 									div.parentNode.removeChild(div);
 
- 								}else{
 
- 									this._indentElement(div);
 
- 								}
 
- 								div = null;
 
- 							}
 
- 							this._indentList(curNode);
 
- 						}else if(!this._isInlineFormat(tag) && this._isIndentableElement(tag)){
 
- 							if(div){
 
- 								if(this._isEmpty(div)){
 
- 									div.parentNode.removeChild(div);
 
- 								}else{
 
- 									this._indentElement(div);
 
- 								}
 
- 								div = null;
 
- 							}
 
- 							curNode = this._indentElement(curNode);
 
- 						}else if(this._isInlineFormat(tag)){
 
- 							// inline tag.
 
- 							if(!div){
 
- 								div = ed.document.createElement("div");
 
- 								dojo.place(div, curNode, "after");
 
- 								div.appendChild(curNode);
 
- 								curNode = div;
 
- 							}else{
 
- 								div.appendChild(curNode);
 
- 								curNode = div;
 
- 							}
 
- 						}
 
- 					}else if(this._isTextElement(curNode)){
 
- 						if(!div){
 
- 							div = ed.document.createElement("div");
 
- 							dojo.place(div, curNode, "after");
 
- 							div.appendChild(curNode);
 
- 							curNode = div;
 
- 						}else{
 
- 							div.appendChild(curNode);
 
- 							curNode = div;
 
- 						}
 
- 					}
 
- 					curNode = curNode.nextSibling;
 
- 				}
 
- 				// Okay, indent everything we merged if we haven't yet..
 
- 				if(div){
 
- 					if(this._isEmpty(div)){
 
- 						div.parentNode.removeChild(div);
 
- 					}else{
 
- 						this._indentElement(div);
 
- 					}
 
- 					div = null;
 
- 				}
 
- 			}
 
- 		}
 
- 	},
 
- 	_indentElement: function(node){
 
- 		// summary:
 
- 		//		Function to indent a block type tag.
 
- 		// node:
 
- 		//		The node who's content to indent.
 
- 		// tags:
 
- 		//		private
 
- 		var style = "marginLeft";
 
- 		if(!this._isLtr()){
 
- 			style = "marginRight";
 
- 		}
 
- 		var tag = this._getTagName(node);
 
- 		if(tag === "ul" || tag === "ol"){
 
- 			// Lists indent funny, so lets wrap them in a div
 
- 			// and indent the div instead.
 
- 			var div = this.editor.document.createElement("div");
 
- 			dojo.place(div, node, "after");
 
- 			div.appendChild(node);
 
- 			node = div;
 
- 		}
 
- 		var cIndent = node.style?node.style[style]:"";
 
- 		if(cIndent){
 
- 			cIndent = this._convertIndent(cIndent);
 
- 			cIndent = (parseInt(cIndent, 10) + this.indentBy) + this.indentUnits;
 
- 		}else{
 
- 			cIndent = this.indentBy + this.indentUnits;
 
- 		}
 
- 		dojo.style(node, style, cIndent);
 
- 		return node; //Return the node that was indented.
 
- 	},
 
- 	_outdentElement: function(node){
 
- 		// summary:
 
- 		//		Function to outdent a block type tag.
 
- 		// node:
 
- 		//		The node who's content to outdent.
 
- 		// tags:
 
- 		//		private
 
- 		var style = "marginLeft";
 
- 		if(!this._isLtr()){
 
- 			style = "marginRight";
 
- 		}
 
- 		var cIndent = node.style?node.style[style]:"";
 
- 		if(cIndent){
 
- 			cIndent = this._convertIndent(cIndent);
 
- 			if(cIndent - this.indentBy > 0){
 
- 				cIndent = (parseInt(cIndent, 10) - this.indentBy) + this.indentUnits;
 
- 			}else{
 
- 				cIndent = "";
 
- 			}
 
- 			dojo.style(node, style, cIndent);
 
- 		}
 
- 	},
 
- 	_outdentImpl: function(/*String*/ html) {
 
- 		// summary:
 
- 		//		Improved implementation of outdent, generates correct indent for
 
- 		//		ul/ol and other elements.
 
- 		// tags:
 
- 		//		private
 
- 		var ed = this.editor;
 
- 		var sel = dijit.range.getSelection(ed.window);
 
- 		if(sel && sel.rangeCount > 0){
 
- 			var range = sel.getRangeAt(0);
 
- 			var node = range.startContainer;
 
- 			var tag;
 
- 			if(range.startContainer === range.endContainer){
 
- 				// Check for li nodes first, we handle them a certain way.
 
- 				while(node && node !== ed.document && node !== ed.editNode){
 
- 					tag = this._getTagName(node);
 
- 					if(tag === "li"){
 
- 						return this._outdentList(node);
 
- 					}else if(this._isIndentableElement(tag)){
 
- 						return this._outdentElement(node);
 
- 					}
 
- 					node = node.parentNode;
 
- 				}
 
- 				ed.document.execCommand("outdent", false, html);
 
- 			}else{
 
- 				// multi-node select.  We need to scan over them.
 
- 				// Find the two containing nodes at start and end.
 
- 				// then move the end one node past.  Then ... lets see
 
- 				// what we can outdent!
 
- 				var start = range.startContainer;
 
- 				var end =  range.endContainer;
 
- 				// Find the non-text nodes.
 
- 				while(start && start.nodeType === 3){
 
- 					start = start.parentNode;
 
- 				}
 
- 				while(end && end.nodeType === 3){
 
- 					end = end.parentNode;
 
- 				}
 
- 				end = end.nextSibling;
 
- 				var curNode = start;
 
- 				while(curNode && curNode !== end){
 
- 					if(curNode.nodeType === 1){
 
- 						tag = this._getTagName(curNode);
 
- 						if(tag === "li"){
 
- 							this._outdentList(curNode);
 
- 						}else if(this._isIndentableElement(tag)){
 
- 							this._outdentElement(curNode);
 
- 						}
 
- 					}
 
- 					curNode = curNode.nextSibling;
 
- 				}
 
- 			}
 
- 		}
 
- 		return null;
 
- 	},
 
- 	_indentList: function(listItem){
 
- 		// summary:
 
- 		//		Internal function to handle indenting a list element.
 
- 		// listItem:
 
- 		//		The list item to indent.
 
- 		// tags:
 
- 		//		private
 
- 		var ed = this.editor;
 
- 		var newList, li;
 
- 		var listContainer = listItem.parentNode;
 
- 		var prevTag = listItem.previousSibling;
 
- 		
 
- 		// Ignore text, we want elements.
 
- 		while(prevTag && prevTag.nodeType !== 1){
 
- 			prevTag = prevTag.previousSibling;
 
- 		}
 
- 		var type = null;
 
- 		var tg = this._getTagName(listContainer);
 
- 		
 
- 		// Try to determine what kind of list item is here to indent.
 
- 		if(tg === "ol"){
 
- 			type = "ol";
 
- 		}else if(tg === "ul"){
 
- 			type = "ul";
 
- 		}
 
- 		
 
- 		// Only indent list items actually in a list.
 
- 		// Bail out if the list is malformed somehow.
 
- 		if(type){
 
- 			// There is a previous node in the list, so we want to append a new list
 
- 			// element after it that contains a new list of the content to indent it.
 
- 			if(prevTag && prevTag.tagName.toLowerCase() == "li"){
 
- 				// Lets see if we can merge this into another  (Eg,
 
- 				// does the sibling li contain an embedded list already of
 
- 				// the same type?  if so, we move into that one.
 
- 				var embList;
 
- 				if(prevTag.childNodes){
 
- 					var i;
 
- 					for(i = 0; i < prevTag.childNodes.length; i++){
 
- 						var n = prevTag.childNodes[i];
 
- 						if(n.nodeType === 3){
 
- 							if(dojo.trim(n.nodeValue)){
 
- 								if(embList){
 
- 									// Non-empty text after list, exit, can't embed.
 
- 									break;
 
- 								}
 
- 							}
 
- 						}else if(n.nodeType === 1 && !embList){
 
- 							// See if this is a list container.
 
- 							if(type === n.tagName.toLowerCase()){
 
- 								embList = n;
 
- 							}
 
- 						}else{
 
- 							// Other node present, break, can't embed.
 
- 							break;
 
- 						}
 
- 					}
 
- 				}
 
- 				if(embList){
 
- 					// We found a list to merge to, so merge.
 
- 					embList.appendChild(listItem);
 
- 				}else{
 
- 					// Nope, wasn't an embedded list container,
 
- 					// So lets just create a new one.
 
- 					newList = ed.document.createElement(type);
 
- 					dojo.style(newList, {
 
- 						paddingTop: "0px",
 
- 						paddingBottom: "0px"
 
- 					});
 
- 					li = ed.document.createElement("li");
 
- 					dojo.style(li, {
 
- 						listStyleImage: "none",
 
- 						listStyleType: "none"
 
- 					});
 
- 					prevTag.appendChild(newList);
 
- 					newList.appendChild(listItem);
 
- 				}
 
- 				// Move cursor.
 
- 				dojo.withGlobal(ed.window,
 
- 					"selectElementChildren", dijit._editor.selection, [listItem]);
 
- 				dojo.withGlobal(ed.window,
 
- 					"collapse", dijit._editor.selection, [true]);
 
- 			}
 
- 		}
 
- 	},
 
- 	_outdentList: function(listItem){
 
- 		// summary:
 
- 		//		Internal function to handle outdenting a list element.
 
- 		// listItem:
 
- 		//		The list item to outdent.
 
- 		// tags:
 
- 		//		private
 
- 		var ed = this.editor;
 
- 		var list = listItem.parentNode;
 
- 		var type = null;
 
- 		var tg = list.tagName ? list.tagName.toLowerCase() : "";
 
- 		var li;
 
- 		// Try to determine what kind of list contains the item.
 
- 		if(tg === "ol"){
 
- 			type = "ol";
 
- 		}else if(tg === "ul"){
 
- 			type = "ul";
 
- 		}
 
- 		// Check to see if it is a nested list, as outdenting is handled differently.
 
- 		var listParent = list.parentNode;
 
- 		var lpTg = this._getTagName(listParent);
 
- 		
 
- 		// We're in a list, so we need to outdent this specially.
 
- 		// Check for welformed and malformed lists (<ul><ul></ul>U/ul> type stuff).
 
- 		if(lpTg === "li" || lpTg === "ol" || lpTg === "ul"){
 
- 			if(lpTg === "ol" || lpTg === "ul"){
 
- 				// Okay, we need to fix this up, this is invalid html,
 
- 				// So try to combine this into a previous element before
 
- 				// de do a shuffle of the nodes, to build an HTML compliant
 
- 				// list.
 
- 				var prevListLi = list.previousSibling;
 
- 				while(prevListLi && (prevListLi.nodeType !== 1 ||
 
- 						(prevListLi.nodeType === 1 &&
 
- 						this._getTagName(prevListLi) !== "li"))
 
- 					){
 
- 					prevListLi = prevListLi.previousSibling;
 
- 				}
 
- 				if(prevListLi){
 
- 					// Move this list up into the previous li
 
- 					// to fix malformation.
 
- 					prevListLi.appendChild(list);
 
- 					listParent = prevListLi;
 
- 				}else{
 
- 					li = listItem;
 
- 					var firstItem = listItem;
 
- 					while(li.previousSibling){
 
- 						li = li.previousSibling;
 
- 						if(li.nodeType === 1 && this._getTagName(li) === "li"){
 
- 							firstItem = li;
 
- 						}
 
- 					}
 
- 					if(firstItem !== listItem){
 
- 						dojo.place(firstItem, list, "before");
 
- 						firstItem.appendChild(list);
 
- 						listParent = firstItem;
 
- 					}else{
 
- 						// No previous list item in a malformed list
 
- 						// ... so create one  and move into that.
 
- 						li = ed.document.createElement("li");
 
- 						dojo.place(li, list, "before");
 
- 						li.appendChild(list);
 
- 						listParent = li;
 
- 					}
 
- 					dojo.style(list, {
 
- 						paddingTop: "0px",
 
- 						paddingBottom: "0px"
 
- 					});
 
- 				}
 
- 			}
 
- 			// find the previous node, if any,
 
- 			// non-text.
 
- 			var prevLi = listItem.previousSibling;
 
- 			while(prevLi && prevLi.nodeType !== 1){
 
- 				prevLi = prevLi.previousSibling;
 
- 			}
 
- 			var nextLi = listItem.nextSibling;
 
- 			while(nextLi && nextLi.nodeType !== 1){
 
- 				nextLi = nextLi.nextSibling;
 
- 			}
 
- 			if(!prevLi){
 
- 				// Top item in a nested list, so just move it out
 
- 				// and then shuffle the remaining indented list into it.
 
- 				dojo.place(listItem, listParent, "after");
 
- 				listItem.appendChild(list);
 
- 			}else if(!nextLi){
 
- 				// Last item in a nested list, shuffle it out after
 
- 				// the nsted list only.
 
- 				dojo.place(listItem, listParent, "after");
 
- 			}else{
 
- 				// Item is in the middle of an embedded  list, so we
 
- 				// have to split it.
 
- 				// Move all the items following current list item into
 
- 				// a list after it.
 
- 				var newList = ed.document.createElement(type);
 
- 				dojo.style(newList, {
 
- 					paddingTop: "0px",
 
- 					paddingBottom: "0px"
 
- 				});
 
- 				listItem.appendChild(newList);
 
- 				while(listItem.nextSibling){
 
- 					newList.appendChild(listItem.nextSibling);
 
- 				}
 
- 				// Okay, now place the list item after the
 
- 				// current list parent (li).
 
- 				dojo.place(listItem, listParent, "after");
 
- 			}
 
- 			
 
- 			// Clean up any empty lists left behind.
 
- 			if(list && this._isEmpty(list)){
 
- 				list.parentNode.removeChild(list);
 
- 			}
 
- 			if(listParent && this._isEmpty(listParent)){
 
- 				listParent.parentNode.removeChild(listParent);
 
- 			}
 
- 			
 
- 			// Move our cursor to the list item we moved.
 
- 			dojo.withGlobal(ed.window,
 
- 				"selectElementChildren", dijit._editor.selection, [listItem]);
 
- 			dojo.withGlobal(ed.window,
 
- 				"collapse", dijit._editor.selection, [true]);
 
- 		}else{
 
- 			// Not in a nested list, so we can just defer to the
 
- 			// browser and hope it outdents right.
 
- 			ed.document.execCommand("outdent", false, null);
 
- 		}
 
- 	},
 
- 	_isEmpty: function(node){
 
- 		// summary:
 
- 		//		Internal function to determine if a node is 'empty'
 
- 		//		Eg, contains only blank text.  Used to determine if
 
- 		//		an empty list element should be removed or not.
 
- 		// node:
 
- 		//		The node to check.
 
- 		// tags:
 
- 		//		private
 
- 		if(node.childNodes){
 
- 			var empty = true;
 
- 			var i;
 
- 			for(i = 0; i < node.childNodes.length; i++){
 
- 				var n = node.childNodes[i];
 
- 				if(n.nodeType === 1){
 
- 					if(this._getTagName(n) === "p"){
 
- 						if(!dojo.trim(n.innerHTML)){
 
- 							continue;
 
- 						}
 
- 					}
 
- 					empty = false;
 
- 					break;
 
- 				}else if(this._isTextElement(n)){
 
- 					// Check for empty text.
 
- 					var nv = dojo.trim(n.nodeValue);
 
- 					if(nv && nv !==" " && nv !== "\u00A0"){
 
- 						empty = false;
 
- 						break;
 
- 					}
 
- 				}else{
 
- 					empty = false;
 
- 					break;
 
- 				}
 
- 			}
 
- 			return empty;
 
- 		}else{
 
- 			return true;
 
- 		}
 
- 	},
 
- 	_isIndentableElement: function(tag){
 
- 		// summary:
 
- 		//		Internal function to detect what element types
 
- 		//		are indent-controllable by us.
 
- 		// tag:
 
- 		//		The tag to check
 
- 		// tags:
 
- 		//		private
 
- 		switch(tag){
 
- 			case "p":
 
- 			case "div":
 
- 			case "h1":
 
- 			case "h2":
 
- 			case "h3":
 
- 			case "center":
 
- 			case "table":
 
- 			case "ul":
 
- 			case "ol":
 
- 				return true;
 
- 			default:
 
- 				return false;
 
- 		}
 
- 	},
 
- 	_convertIndent: function(indent){
 
- 		// summary:
 
- 		//		Function to convert the current indent style to
 
- 		//		the units we're using by some heuristic.
 
- 		// indent:
 
- 		//		The indent amount to convert.
 
- 		// tags:
 
- 		//		private
 
- 		var pxPerEm = 12;
 
- 		indent = indent + "";
 
- 		indent = indent.toLowerCase();
 
- 		var curUnit = (indent.indexOf("px") > 0) ? "px" : (indent.indexOf("em") > 0) ? "em" : "px";
 
- 		indent = indent.replace(/(px;?|em;?)/gi, "");
 
- 		if(curUnit === "px"){
 
- 			if(this.indentUnits === "em"){
 
- 				indent = Math.ceil(indent/pxPerEm);
 
- 			}
 
- 		}else{
 
- 			if(this.indentUnits === "px"){
 
- 				indent = indent * pxPerEm;
 
- 			}
 
- 		}
 
- 		return indent;
 
- 	},
 
- 	_isLtr: function(){
 
- 		// summary:
 
- 		//		Function to detect if the editor body is in RTL or LTR.
 
- 		// tags:
 
- 		//		private
 
- 		var editDoc = this.editor.document.body;
 
- 		return dojo.withGlobal(this.editor.window, function(){
 
- 			var cs = dojo.getComputedStyle(editDoc);
 
- 			return cs ? cs.direction == "ltr" : true;
 
- 		});
 
- 	},
 
- 	_isInlineFormat: function(tag){
 
- 		// summary:
 
- 		//		Function to determine if the current tag is an inline
 
- 		//		element that does formatting, as we don't want to
 
- 		//		break/indent around it, as it can screw up text.
 
- 		// tag:
 
- 		//		The tag to examine
 
- 		// tags:
 
- 		//		private
 
- 		switch(tag){
 
- 			case "a":
 
- 			case "b":
 
- 			case "strong":
 
- 			case "s":
 
- 			case "strike":
 
- 			case "i":
 
- 			case "u":
 
- 			case "em":
 
- 			case "sup":
 
- 			case "sub":
 
- 			case "span":
 
- 			case "font":
 
- 			case "big":
 
- 			case "cite":
 
- 			case "q":
 
- 			case "img":
 
- 			case "small":
 
- 				return true;
 
- 			default:
 
- 				return false;
 
- 		}
 
- 	},
 
- 	_getTagName: function(node){
 
- 		// summary:
 
- 		//		Internal function to get the tag name of an element
 
- 		//		if any.
 
- 		// node:
 
- 		//		The node to look at.
 
- 		// tags:
 
- 		//		private
 
- 		var tag = "";
 
- 		if(node && node.nodeType === 1){
 
- 			tag = node.tagName?node.tagName.toLowerCase():"";
 
- 		}
 
- 		return tag;
 
- 	},
 
- 	_isRootInline: function(node){
 
- 		// summary:
 
- 		//		This functions tests whether an indicated node is in root as inline
 
- 		//		or rooted inline elements in the page.
 
- 		// node:
 
- 		//		The node to start at.
 
- 		// tags:
 
- 		//		private
 
- 		var ed = this.editor;
 
- 		if(this._isTextElement(node) && node.parentNode === ed.editNode){
 
- 			return true;
 
- 		}else if(node.nodeType === 1 && this._isInlineFormat(node) && node.parentNode === ed.editNode){
 
- 			return true;
 
- 		}else if(this._isTextElement(node) && this._isInlineFormat(this._getTagName(node.parentNode))){
 
- 			node = node.parentNode;
 
- 			while(node && node !== ed.editNode && this._isInlineFormat(this._getTagName(node))){
 
- 				node = node.parentNode;
 
- 			}
 
- 			if(node === ed.editNode){
 
- 				return true;
 
- 			}
 
- 		}
 
- 		return false;
 
- 	},
 
- 	_isTextElement: function(node){
 
- 		// summary:
 
- 		//		Helper function to check for text nodes.
 
- 		// node:
 
- 		//		The node to check.
 
- 		// tags:
 
- 		//		private
 
- 		if(node && node.nodeType === 3 || node.nodeType === 4){
 
- 			return true;
 
- 		}
 
- 		return false;
 
- 	}
 
- });
 
- // Register this plugin.
 
- dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
 
- 	if(o.plugin){ return; }
 
- 	var name = o.args.name.toLowerCase();
 
- 	if(name === "normalizeindentoutdent"){
 
- 		o.plugin = new dojox.editor.plugins.NormalizeIndentOutdent({
 
- 			indentBy: ("indentBy" in o.args) ?
 
- 				(o.args.indentBy > 0 ? o.args.indentBy : 40) :
 
- 				40,
 
- 			indentUnits: ("indentUnits" in o.args) ?
 
- 				(o.args.indentUnits.toLowerCase() == "em"? "em" : "px") :
 
- 				"px"
 
- 		});
 
- 	}
 
- });
 
- }
 
 
  |