123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- /*
- 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.InsertAnchor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
- dojo._hasResource["dojox.editor.plugins.InsertAnchor"] = true;
- dojo.provide("dojox.editor.plugins.InsertAnchor");
- dojo.require("dojo.string");
- dojo.require("dijit._Widget");
- dojo.require("dijit._editor.range");
- dojo.require("dijit._Templated");
- dojo.require("dijit.TooltipDialog");
- dojo.require("dijit.form.ValidationTextBox");
- dojo.require("dijit.form.Select");
- dojo.require("dijit._editor._Plugin");
- dojo.require("dijit.form.Button");
- dojo.require("dojox.editor.plugins.ToolbarLineBreak");
- dojo.require("dojo.i18n");
- dojo.requireLocalization("dojox.editor.plugins", "InsertAnchor", null, "ROOT,ar,bg,ca,cs,da,de,el,es,fi,fr,he,hr,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
- dojo.requireLocalization("dijit", "common", null, "ROOT,ar,az,bg,ca,cs,da,de,el,es,fi,fr,he,hr,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
- 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();
- }), 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();
- }
- });
- }
|