| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 | define("dojox/editor/plugins/InsertAnchor", [	"dojo",	"dijit",	"dojox",	"dijit/_base/manager",	// TODO: change to dijit/registry, and change dijit.byId to registry.byId	"dijit/_editor/range",	"dijit/_Templated",	"dijit/TooltipDialog",	"dijit/form/ValidationTextBox",	"dijit/form/Select",	"dijit/form/Button",	"dijit/form/DropDownButton",	"dijit/_editor/range",	"dijit/_editor/selection",	"dijit/_editor/_Plugin",	"dojo/_base/connect",	"dojo/_base/declare",	"dojo/i18n",	"dojo/string",	"dojox/editor/plugins/ToolbarLineBreak",	"dojo/i18n!dojox/editor/plugins/nls/InsertAnchor",	"dojo/i18n!dijit/nls/common"], function(dojo, dijit, dojox) {dojo.declare("dojox.editor.plugins.InsertAnchor", dijit._editor._Plugin, {	// summary:	//		This plugin provides the basis for an insert anchor dialog for the	//		dijit.Editor	//	// description:	//		The command provided by this plugin is:	//		* insertAnchor	// htmlTemplate: [protected] String	//		String used for templating the HTML to insert at the desired point.	htmlTemplate: "<a name=\"${anchorInput}\" class=\"dijitEditorPluginInsertAnchorStyle\">${textInput}</a>",	// iconClassPrefix: [const] String	//		The CSS class name for the button node icon.	iconClassPrefix: "dijitAdditionalEditorIcon",	// linkDialogTemplate: [private] String	//		Template for contents of TooltipDialog to pick URL	_template: [		"<table><tr><td>",		"<label for='${id}_anchorInput'>${anchor}</label>",		"</td><td>",		"<input dojoType='dijit.form.ValidationTextBox' required='true' " +		"id='${id}_anchorInput' name='anchorInput' intermediateChanges='true'>",		"</td></tr><tr><td>",		"<label for='${id}_textInput'>${text}</label>",		"</td><td>",		"<input dojoType='dijit.form.ValidationTextBox' required='true' id='${id}_textInput' " +		"name='textInput' intermediateChanges='true'>",		"</td></tr>",		"<tr><td colspan='2'>",		"<button dojoType='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>",		"<button dojoType='dijit.form.Button' type='button' id='${id}_cancelButton'>${cancel}</button>",		"</td></tr></table>"	].join(""),	_initButton: function(){		// Override _Plugin._initButton() to initialize DropDownButton and TooltipDialog.		var _this = this;		var messages = dojo.i18n.getLocalization("dojox.editor.plugins", "InsertAnchor", this.lang);		// Build the dropdown dialog we'll use for the button		var dropDown = (this.dropDown = new dijit.TooltipDialog({			title: messages["title"],			execute: dojo.hitch(this, "setValue"),			onOpen: function(){				_this._onOpenDialog();				dijit.TooltipDialog.prototype.onOpen.apply(this, arguments);			},			onCancel: function(){				setTimeout(dojo.hitch(_this, "_onCloseDialog"),0);			}		}));		this.button = new dijit.form.DropDownButton({			label: messages["insertAnchor"],			showLabel: false,			iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "InsertAnchor",			tabIndex: "-1",			dropDown: this.dropDown		});		messages.id = dijit.getUniqueId(this.editor.id);		this._uniqueId = messages.id;		this.dropDown.set('content', dropDown.title +			"<div style='border-bottom: 1px black solid;padding-bottom:2pt;margin-bottom:4pt'></div>" +			dojo.string.substitute(this._template, messages));		dropDown.startup();		this._anchorInput = dijit.byId(this._uniqueId + "_anchorInput");		this._textInput = dijit.byId(this._uniqueId + "_textInput");		this._setButton = dijit.byId(this._uniqueId + "_setButton");		this.connect(dijit.byId(this._uniqueId + "_cancelButton"), "onClick", function(){			this.dropDown.onCancel();		});		if(this._anchorInput){			this.connect(this._anchorInput, "onChange", "_checkInput");		}		if(this._textInput){			this.connect(this._anchorInput, "onChange", "_checkInput");		}		//Register some filters to handle setting/removing the class tags on anchors.		this.editor.contentDomPreFilters.push(dojo.hitch(this, this._preDomFilter));		this.editor.contentDomPostFilters.push(dojo.hitch(this, this._postDomFilter));		this._setup();	},		updateState: function(){		// summary:		//		Over-ride for button state control for disabled to work.		this.button.set("disabled", this.get("disabled"));	},	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();	},	_checkInput: function(){		// summary:		//		Function to check the input to the dialog is valid		//		and enable/disable set button		// tags:		//		private		var disable = true;		if(this._anchorInput.isValid()){			disable = false;		}		this._setButton.set("disabled", disable);	},	_setup: function(){		// summary:		//		Over-ridable function that connects tag specific events.		this.editor.onLoadDeferred.addCallback(dojo.hitch(this, function(){			this.connect(this.editor.editNode, "ondblclick", this._onDblClick);			setTimeout(dojo.hitch(this, function() {				this._applyStyles();			}), 100);		}));	},	getAnchorStyle: function(){		// summary:		//		Over-ridable function for getting the style to apply to the anchor.		//		The default is a dashed border with an anchor symbol.		// tags:		//		public		var style = "@media screen {\n" +				"\t.dijitEditorPluginInsertAnchorStyle {\n" +				"\t\tbackground-image: url({MODURL}/images/anchor.gif);\n" +				"\t\tbackground-repeat: no-repeat;\n"	+				"\t\tbackground-position: top left;\n" +				"\t\tborder-width: 1px;\n" +				"\t\tborder-style: dashed;\n" +				"\t\tborder-color: #D0D0D0;\n" +				 "\t\tpadding-left: 20px;\n" +			"\t}\n" +		"}\n";		//Finally associate in the image locations based off the module url.		var modurl = dojo.moduleUrl(dojox._scopeName, "editor/plugins/resources").toString();		if(!(modurl.match(/^https?:\/\//i)) &&			!(modurl.match(/^file:\/\//i))){			// We have to root it to the page location on webkit for some nutball reason.			// Probably has to do with how iframe was loaded.			var bUrl;			if(modurl.charAt(0) === "/"){				//Absolute path on the server, so lets handle...				var proto = dojo.doc.location.protocol;				var hostn = dojo.doc.location.host;				bUrl = proto + "//" + hostn;			}else{				bUrl = this._calcBaseUrl(dojo.global.location.href);			}			if(bUrl[bUrl.length - 1] !== "/" && modurl.charAt(0) !== "/"){				bUrl += "/";			}			modurl = bUrl + modurl;		}		return style.replace(/\{MODURL\}/gi, modurl);	},	_applyStyles: function(){		// summary:		//		Function to apply a style to inserted anchor tags so that		//		they are obviously anchors.		if(!this._styled){			try{				//Attempt to inject our specialized style rules for doing this.				this._styled = true;				var doc = this.editor.document;				var style = this.getAnchorStyle();				if(!dojo.isIE){					var sNode = doc.createElement("style");					sNode.appendChild(doc.createTextNode(style));					doc.getElementsByTagName("head")[0].appendChild(sNode);				}else{					var ss = doc.createStyleSheet("");					ss.cssText = style;				}			 }catch(e){ /* Squelch */ }		 }	},	_calcBaseUrl: function(fullUrl) {		// summary:		//		Internal function used to figure out the full root url (no relatives)		//		for loading images in the styles in the iframe.		// fullUrl: String		//		The full url to tear down to the base.		// tags:		//		private		var baseUrl = null;		if (fullUrl !== null) {			// Check to see if we need to strip off any query parameters from the Url.			var index = fullUrl.indexOf("?");			if (index != -1) {				fullUrl = fullUrl.substring(0,index);			}			// Now we need to trim if necessary.  If it ends in /, then we don't			// have a filename to trim off so we can return.			index = fullUrl.lastIndexOf("/");			if (index > 0 && index < fullUrl.length) {				baseUrl = fullUrl.substring(0,index);			}else{				baseUrl = fullUrl;			}		}		return baseUrl; //String	},	_checkValues: function(args){		// summary:		//		Function to check the values in args and 'fix' them up as needed.		// args: Object		//		Content being set.		// tags:		//		protected		if(args){			if(args.anchorInput){				args.anchorInput = args.anchorInput.replace(/"/g, """);			}			if(!args.textInput){				// WebKit doesn't work with double-click select unless there's				// a space in the anchor text, so put a in the case of				// empty desc.				args.textInput = " ";			}		}		return args;	},	setValue: function(args){		// summary:		//		Callback from the dialog when user presses "set" button.		// tags:		//		private		this._onCloseDialog();		if(!this.editor.window.getSelection){			// IE check without using user agent string.			var sel = dijit.range.getSelection(this.editor.window);			var range = sel.getRangeAt(0);			var a = range.endContainer;			if(a.nodeType === 3){				// Text node, may be the link contents, so check parent.				// This plugin doesn't really support nested HTML elements				// in the link, it assumes all link content is text.				a = a.parentNode;			}			if(a && (a.nodeName && a.nodeName.toLowerCase() !== "a")){				// Stll nothing, one last thing to try on IE, as it might be 'img'				// and thus considered a control.				a = dojo.withGlobal(this.editor.window,					"getSelectedElement", dijit._editor.selection, ["a"]);			}			if(a && (a.nodeName && a.nodeName.toLowerCase() === "a")){				// Okay, we do have a match.  IE, for some reason, sometimes pastes before				// instead of removing the targetted paste-over element, so we unlink the				// old one first.  If we do not the <a> tag remains, but it has no content,				// so isn't readily visible (but is wrong for the action).				if(this.editor.queryCommandEnabled("unlink")){					// Select all the link childent, then unlink.  The following insert will					// then replace the selected text.					dojo.withGlobal(this.editor.window,						"selectElementChildren", dijit._editor.selection, [a]);					this.editor.execCommand("unlink");				}			}		}		// make sure values are properly escaped, etc.		args = this._checkValues(args);		this.editor.execCommand('inserthtml',			dojo.string.substitute(this.htmlTemplate, args));	},	_onCloseDialog: function(){		// summary:		//		Handler for close event on the dialog		this.editor.focus();	},	_getCurrentValues: function(a){		// summary:		//		Over-ride for getting the values to set in the dropdown.		// a:		//		The anchor/link to process for data for the dropdown.		// tags:		//		protected		var anchor, text;		if(a && a.tagName.toLowerCase() === "a" && dojo.attr(a, "name")){			anchor = dojo.attr(a, "name");			text = a.textContent || a.innerText;			dojo.withGlobal(this.editor.window, "selectElement", dijit._editor.selection, [a, true]);		}else{			text = dojo.withGlobal(this.editor.window, dijit._editor.selection.getSelectedText);		}		return {anchorInput: anchor || '', textInput: text || ''}; //Object;	},	_onOpenDialog: function(){		// summary:		//		Handler for when the dialog is opened.		//		If the caret is currently in a URL then populate the URL's info into the dialog.		var a;		if(!this.editor.window.getSelection){			// IE is difficult to select the element in, using the range unified			// API seems to work reasonably well.			var sel = dijit.range.getSelection(this.editor.window);			var range = sel.getRangeAt(0);			a = range.endContainer;			if(a.nodeType === 3){				// Text node, may be the link contents, so check parent.				// This plugin doesn't really support nested HTML elements				// in the link, it assumes all link content is text.				a = a.parentNode;			}			if(a && (a.nodeName && a.nodeName.toLowerCase() !== "a")){				// Stll nothing, one last thing to try on IE, as it might be 'img'				// and thus considered a control.				a = dojo.withGlobal(this.editor.window,					"getSelectedElement", dijit._editor.selection, ["a"]);			}		}else{			a = dojo.withGlobal(this.editor.window,				"getAncestorElement", dijit._editor.selection, ["a"]);		}		this.dropDown.reset();		this._setButton.set("disabled", true);		this.dropDown.set("value", this._getCurrentValues(a));	},	_onDblClick: function(e){		// summary:		//		Function to define a behavior on double clicks on the element		//		type this dialog edits to select it and pop up the editor		//		dialog.		// e: Object		//		The double-click event.		// tags:		//		protected.		if(e && e.target){			var t = e.target;			var tg = t.tagName? t.tagName.toLowerCase() : "";			if(tg === "a" && dojo.attr(t, "name")){				this.editor.onDisplayChanged();				dojo.withGlobal(this.editor.window,					 "selectElement",					 dijit._editor.selection, [t]);				setTimeout(dojo.hitch(this, function(){					// Focus shift outside the event handler.					// IE doesn't like focus changes in event handles.					this.button.set("disabled", false);					this.button.openDropDown();					if(this.button.dropDown.focus){						this.button.dropDown.focus();					}				}), 10);			}		}	},	_preDomFilter: function(node){		// summary:		//		A filter to identify the 'a' tags and if they're anchors,		//		apply the right style to them.		// node:		//		The node to search from.		// tags:		//		private		var ed = this.editor;		dojo.withGlobal(ed.window, function(){			dojo.query("a", ed.editNode).forEach(function(a){				if(dojo.attr(a, "name") && !dojo.attr(a, "href")){					if(!dojo.hasClass(a,"dijitEditorPluginInsertAnchorStyle")){						dojo.addClass(a, "dijitEditorPluginInsertAnchorStyle");					}				}			});		});	},	_postDomFilter: function(node){		// summary:		//		A filter to identify the 'a' tags and if they're anchors,		//		remove the class style that shows up in the editor from		//		them.		// node:		//		The node to search from.		// tags:		//		private		var ed = this.editor;		dojo.withGlobal(ed.window, function(){			dojo.query("a", node).forEach(function(a){				if(dojo.attr(a, "name") && !dojo.attr(a, "href")){					if(dojo.hasClass(a,"dijitEditorPluginInsertAnchorStyle")){						dojo.removeClass(a, "dijitEditorPluginInsertAnchorStyle");					}				}			});		});		return node;	}});// Register this plugin.dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){	if(o.plugin){ return; }	var name = o.args.name;	if(name) { name = name.toLowerCase(); }	if(name === "insertanchor"){		o.plugin = new dojox.editor.plugins.InsertAnchor();	}});return dojox.editor.plugins.InsertAnchor;});
 |