text: /*
  	Copyright (c) 2004-2010, 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.Blockquote"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  dojo._hasResource["dojox.editor.plugins.Blockquote"] = true;
  dojo.provide("dojox.editor.plugins.Blockquote");
  
  dojo.require("dijit._editor._Plugin");
  dojo.require("dijit.form.Button");
  dojo.require("dojo.i18n");
  
  dojo.requireLocalization("dojox.editor.plugins", "Blockquote", null, "ROOT,ro");
  
  dojo.declare("dojox.editor.plugins.Blockquote",dijit._editor._Plugin,{
  	//	summary:
  	//		This plugin provides Blockquote cabability to the editor. 
  	//		window/tab
  
  	// iconClassPrefix: [const] String
  	//		The CSS class name for the button node icon.
  	iconClassPrefix: "dijitAdditionalEditorIcon",
  
  	_initButton: function(){
  		// summary:
  		//		Over-ride for creation of the preview button.
  		this._nlsResources = dojo.i18n.getLocalization("dojox.editor.plugins", "Blockquote");
  		this.button = new dijit.form.ToggleButton({
  			label: this._nlsResources["blockquote"],
  			showLabel: false,
  			iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "Blockquote",
  			tabIndex: "-1",
  			onClick: dojo.hitch(this, "_toggleQuote")
  		});
  	},
  
  	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;
  		this._initButton();
  		this.connect(this.editor, "onNormalizedDisplayChanged", "updateState");
  		// 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;
  	},
  
  	_toggleQuote: function(arg){
  		// summary:
  		//		Function to trigger previewing of the editor document
  		// tags:
  		//		private
  		try{
  			var ed = this.editor;
  			ed.focus();
  
  			var quoteIt = this.button.get("checked");
  			var sel = dijit.range.getSelection(ed.window);
  			var range, elem, start, end;
  			if(sel && sel.rangeCount > 0){
  				range = sel.getRangeAt(0);
  			}
  			if(range){
  				ed.beginEditing();
  				if(quoteIt){
  					// Lets see what we've got as a selection...
  					var bq, tag;
  					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, so we need to gather all of it., 
  		
  							// 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 part of the blockquote!
  							if(start){
  								bq = ed.document.createElement("blockquote");
  								dojo.place(bq, start, "after");
  								bq.appendChild(start);
  								end = bq.nextSibling;
  								while(end && (
  									this._isTextElement(end) ||
  									(end.nodeType === 1 && 
  										this._isInlineFormat(this._getTagName(end)))
  									)){
  									// Add it. 
  									bq.appendChild(end);
  									end = bq.nextSibling;
  								}
  							}
  						}else{
  							// Figure out what to do when not root inline....
  							var node = range.startContainer;
  							while ((this._isTextElement(node) || 
  									this._isInlineFormat(this._getTagName(node))
  									|| this._getTagName(node) === "li") && 
  								node !== ed.editNode && node !== ed.document.body){
  								node = node.parentNode;
  							}
  							if(node !== ed.editNode && node !==	node.ownerDocument.documentElement){
  								bq = ed.document.createElement("blockquote");
  								dojo.place(bq, node, "after");
  								bq.appendChild(node);
  							}
  						}
  						if(bq){
  							dojo.withGlobal(ed.window, 
  								"selectElementChildren", dijit._editor.selection, [bq]);
  							dojo.withGlobal(ed.window, 
  								"collapse", dijit._editor.selection, [true]);
  						}
  					}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 blockquote!
  						start = range.startContainer;
  						end = range.endContainer;
  						// Find the non-text nodes.
  
  						while(start && this._isTextElement(start) && start.parentNode !== ed.editNode){
  							start = start.parentNode;
  						}
  
  						// Try to find the end node.  We have to check the selection junk
  						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.
  							bq = ed.document.createElement("blockquote");
  							dojo.place(bq, start, "after");
  							tag = this._getTagName(start);
  							if(this._isTextElement(start) || this._isInlineFormat(tag)){
  								// inline element or textnode
  								// Find and move all inline tags following the one we inserted also into the 
  								// blockquote so we don't split up content funny.
  								var next = start;
  								while(next && (
  									this._isTextElement(next) ||
  									(next.nodeType === 1 &&
  									this._isInlineFormat(this._getTagName(next))))){
  									bq.appendChild(next);
  									next = bq.nextSibling;
  								}
  							}else{
  								bq.appendChild(start);
  							}
  							return;
  						}
  
  						// Has a definite end somewhere, so lets try to blockquote up to it.
  						// requires looking at the selections and in some cases, moving nodes
  						// into separate blockquotes.
  						end = end.nextSibling;
  						curNode = start;
  						while(curNode && curNode !== end){
  							if(curNode.nodeType === 1){
  								tag = this._getTagName(curNode);
  								if(tag !== "br"){
  									if(!window.getSelection){
  										// IE sometimes inserts blank P tags, which we want to skip 
  										// as they end up blockquoted, which messes up layout.
  										if(tag === "p" && this._isEmpty(curNode)){
  											curNode = curNode.nextSibling;
  											continue;
  										}
  									}
  									if(this._isInlineFormat(tag)){
  										// inline tag.
  										if(!bq){
  											bq = ed.document.createElement("blockquote");
  											dojo.place(bq, curNode, "after");
  											bq.appendChild(curNode);
  										}else{
  											bq.appendChild(curNode);
  										}
  										curNode = bq;
  									}else{
  										if(bq){
  											if(this._isEmpty(bq)){
  												bq.parentNode.removeChild(bq);
  											}
  										}
  										bq = ed.document.createElement("blockquote");
  										dojo.place(bq, curNode, "after");
  										bq.appendChild(curNode);
  										curNode = bq;
  									}
  								}
  							}else if(this._isTextElement(curNode)){
  								if(!bq){
  									bq = ed.document.createElement("blockquote");
  									dojo.place(bq, curNode, "after");
  									bq.appendChild(curNode);
  								}else{
  									bq.appendChild(curNode);
  								}
  								curNode = bq;
  							}
  							curNode = curNode.nextSibling;
  						}
  						// Okay, check the last bq, remove it if no content.
  						if(bq){
  							if(this._isEmpty(bq)){
  								bq.parentNode.removeChild(bq);
  							}else{
  								dojo.withGlobal(ed.window, 
  									"selectElementChildren", dijit._editor.selection, [bq]);
  								dojo.withGlobal(ed.window, 
  									"collapse", dijit._editor.selection, [true]);
  							}
  							bq = null;
  						}
  					}
  				}else{
  					var found = false;
  					if(range.startContainer === range.endContainer){
  						elem = range.endContainer;
  						// Okay, now see if we can find one of the formatting types we're in.
  						while(elem && elem !== ed.editNode && elem !== ed.document.body){
  							var tg = elem.tagName?elem.tagName.toLowerCase():"";
  							if(tg === "blockquote"){
  								found = true;
  								break;
  							}
  							elem = elem.parentNode;
  						}
  						if(found){
  							var lastChild;
  							while(elem.firstChild){
  								lastChild = elem.firstChild;
  								dojo.place(lastChild, elem, "before");
  							}
  							elem.parentNode.removeChild(elem);
  							if(lastChild){
  								dojo.withGlobal(ed.window, 
  									"selectElementChildren", dijit._editor.selection, [lastChild]);
  								dojo.withGlobal(ed.window, 
  									"collapse", dijit._editor.selection, [true]);
  							}
  						}
  					}else{
  						// Multi-select!  Gotta find all the blockquotes contained within the selection area.
  						start = range.startContainer;
  						end = range.endContainer;
  						while(start && this._isTextElement(start) && start.parentNode !== ed.editNode){
  							start = start.parentNode;
  						}
  						var selectedNodes = [];
  						var cNode = start;
  						while(cNode && cNode.nextSibling && dojo.withGlobal(ed.window, 
  							"inSelection", dijit._editor.selection, [cNode])){
  							if(cNode.parentNode && this._getTagName(cNode.parentNode) === "blockquote"){
  								cNode = cNode.parentNode;
  							}
  							selectedNodes.push(cNode);
  							cNode = cNode.nextSibling;
  						}
  						
  						// Find all the blocknodes now that we know the selection area.
  						var bnNodes = this._findBlockQuotes(selectedNodes);
  						while(bnNodes.length){
  							var bn = bnNodes.pop();
  							if(bn.parentNode){
  								// Make sure we haven't seen this before and removed it.
  								while(bn.firstChild){
  									dojo.place(bn.firstChild, bn, "before");
  								}
  								bn.parentNode.removeChild(bn);
  							}
  						}
  					}
  				}
  				ed.endEditing();
  			}
  			ed.onNormalizedDisplayChanged();
  		}catch(e){ /* Squelch */ }
  	},
  
  	updateState: function(){
  		// summary:
  		//		Overrides _Plugin.updateState().  This controls whether or not the current
  		//		cursor position should toggle on the quote button or not.
  		// tags:
  		//		protected
  		var ed = this.editor;
  		if(!ed || !ed.isLoaded){ return; }
  		if(this.button){
  			// Some browsers (WebKit) doesn't actually get the tag info right.
  			// So ... lets check it manually.
  			var elem;
  			var found = false;
  			
  			// Try to find the ansestor element (and see if it is blockquote)
  			var sel = dijit.range.getSelection(ed.window);
  			if(sel && sel.rangeCount > 0){
  				var range = sel.getRangeAt(0);
  				if(range){
  					elem = range.endContainer;
  				}
  			}
  			// Okay, now see if we can find one of the formatting types we're in.
  			while(elem && elem !== ed.editNode && elem !== ed.document){
  				var tg = elem.tagName?elem.tagName.toLowerCase():"";
  				if(tg === "blockquote"){
  					found = true;
  					break;
  				}
  				elem = elem.parentNode;
  			}
  			// toggle whether or not the current selection is blockquoted.
  			this.button.set("checked", found);
  		}
  	},
  
  	_findBlockQuotes: function(nodeList){
  		// summary:
  		//		function to find a ll the blocknode elements in a collection of
  		//		nodes
  		// nodeList:
  		//		The list of nodes.
  		// tags:
  		//		private
  		var bnList = [];
  		if(nodeList){
  			var i;
  			for(i = 0; i < nodeList.length; i++){
  				var node = nodeList[i];
  				if(node.nodeType === 1){
  					if(this._getTagName(node) === "blockquote"){
  						bnList.push(node);   
  					}
  					if(node.childNodes && node.childNodes.length > 0){
  						bnList = bnList.concat(this._findBlockQuotes(node.childNodes));
  					}
  				}
  			}
  		}
  		return bnList;
  	},
  
  	/*****************************************************************/
  	/* Functions borrowed from NormalizeIndentOutdent                */
  	/*****************************************************************/
  
  	_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;
  	},
  
  	_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 !=="&nbsp;" && nv !== "\u00A0"){
  						empty = false;
  						break;
  					}
  				}else{
  					empty = false;
  					break;
  				}
  			}
  			return empty;
  		}else{
  			return 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;
  		}
  	}
  });
  
  // Register this plugin.
  dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
  	if(o.plugin){ return; }
  	var name = o.args.name.toLowerCase();
  	if(name === "blockquote"){
  		o.plugin = new dojox.editor.plugins.Blockquote({});
  	}
  });
  
  }
  