diff options
Diffstat (limited to 'js/dojo/dijit/_editor')
112 files changed, 11166 insertions, 0 deletions
diff --git a/js/dojo/dijit/_editor/RichText.js b/js/dojo/dijit/_editor/RichText.js new file mode 100644 index 0000000..fd38538 --- /dev/null +++ b/js/dojo/dijit/_editor/RichText.js @@ -0,0 +1,2892 @@ +//>>built +define("dijit/_editor/RichText", [ + "dojo/_base/array", // array.forEach array.indexOf array.some + "dojo/_base/config", // config + "dojo/_base/declare", // declare + "dojo/_base/Deferred", // Deferred + "dojo/dom", // dom.byId + "dojo/dom-attr", // domAttr.set or get + "dojo/dom-class", // domClass.add domClass.remove + "dojo/dom-construct", // domConstruct.create domConstruct.destroy domConstruct.place + "dojo/dom-geometry", // domGeometry.getMarginBox domGeometry.position + "dojo/dom-style", // domStyle.getComputedStyle domStyle.set + "dojo/_base/event", // event.stop + "dojo/_base/kernel", // kernel.deprecated + "dojo/keys", // keys.BACKSPACE keys.TAB + "dojo/_base/lang", // lang.clone lang.hitch lang.isArray lang.isFunction lang.isString lang.trim + "dojo/on", // on() + "dojo/query", // query + "dojo/ready", // ready + "dojo/_base/sniff", // has("ie") has("mozilla") has("opera") has("safari") has("webkit") + "dojo/topic", // topic.publish() (publish) + "dojo/_base/unload", // unload + "dojo/_base/url", // url + "dojo/_base/window", // win.body win.doc.body.focus win.doc.createElement win.global.location win.withGlobal + "../_Widget", + "../_CssStateMixin", + "./selection", + "./range", + "./html", + "../focus", + ".." // dijit._scopeName +], function(array, config, declare, Deferred, dom, domAttr, domClass, domConstruct, domGeometry, domStyle, + event, kernel, keys, lang, on, query, ready, has, topic, unload, _Url, win, + _Widget, _CssStateMixin, selectionapi, rangeapi, htmlapi, focus, dijit){ + +/*===== + var _Widget = dijit._Widget; + var _CssStateMixin = dijit._CssStateMixin; +=====*/ + +// module: +// dijit/_editor/RichText +// summary: +// dijit._editor.RichText is the core of dijit.Editor, which provides basic +// WYSIWYG editing features. + +// if you want to allow for rich text saving with back/forward actions, you must add a text area to your page with +// the id==dijit._scopeName + "._editor.RichText.value" (typically "dijit._editor.RichText.value). For example, +// something like this will work: +// +// <textarea id="dijit._editor.RichText.value" style="display:none;position:absolute;top:-100px;left:-100px;height:3px;width:3px;overflow:hidden;"></textarea> +// + +var RichText = declare("dijit._editor.RichText", [_Widget, _CssStateMixin], { + // summary: + // dijit._editor.RichText is the core of dijit.Editor, which provides basic + // WYSIWYG editing features. + // + // description: + // dijit._editor.RichText is the core of dijit.Editor, which provides basic + // WYSIWYG editing features. It also encapsulates the differences + // of different js engines for various browsers. Do not use this widget + // with an HTML <TEXTAREA> tag, since the browser unescapes XML escape characters, + // like <. This can have unexpected behavior and lead to security issues + // such as scripting attacks. + // + // tags: + // private + + constructor: function(params){ + // contentPreFilters: Function(String)[] + // Pre content filter function register array. + // these filters will be executed before the actual + // editing area gets the html content. + this.contentPreFilters = []; + + // contentPostFilters: Function(String)[] + // post content filter function register array. + // These will be used on the resulting html + // from contentDomPostFilters. The resulting + // content is the final html (returned by getValue()). + this.contentPostFilters = []; + + // contentDomPreFilters: Function(DomNode)[] + // Pre content dom filter function register array. + // These filters are applied after the result from + // contentPreFilters are set to the editing area. + this.contentDomPreFilters = []; + + // contentDomPostFilters: Function(DomNode)[] + // Post content dom filter function register array. + // These filters are executed on the editing area dom. + // The result from these will be passed to contentPostFilters. + this.contentDomPostFilters = []; + + // editingAreaStyleSheets: dojo._URL[] + // array to store all the stylesheets applied to the editing area + this.editingAreaStyleSheets = []; + + // Make a copy of this.events before we start writing into it, otherwise we + // will modify the prototype which leads to bad things on pages w/multiple editors + this.events = [].concat(this.events); + + this._keyHandlers = {}; + + if(params && lang.isString(params.value)){ + this.value = params.value; + } + + this.onLoadDeferred = new Deferred(); + }, + + baseClass: "dijitEditor", + + // inheritWidth: Boolean + // whether to inherit the parent's width or simply use 100% + inheritWidth: false, + + // focusOnLoad: [deprecated] Boolean + // Focus into this widget when the page is loaded + focusOnLoad: false, + + // name: String? + // Specifies the name of a (hidden) <textarea> node on the page that's used to save + // the editor content on page leave. Used to restore editor contents after navigating + // to a new page and then hitting the back button. + name: "", + + // styleSheets: [const] String + // semicolon (";") separated list of css files for the editing area + styleSheets: "", + + // height: String + // Set height to fix the editor at a specific height, with scrolling. + // By default, this is 300px. If you want to have the editor always + // resizes to accommodate the content, use AlwaysShowToolbar plugin + // and set height="". If this editor is used within a layout widget, + // set height="100%". + height: "300px", + + // minHeight: String + // The minimum height that the editor should have. + minHeight: "1em", + + // isClosed: [private] Boolean + isClosed: true, + + // isLoaded: [private] Boolean + isLoaded: false, + + // _SEPARATOR: [private] String + // Used to concat contents from multiple editors into a single string, + // so they can be saved into a single <textarea> node. See "name" attribute. + _SEPARATOR: "@@**%%__RICHTEXTBOUNDRY__%%**@@", + + // _NAME_CONTENT_SEP: [private] String + // USed to separate name from content. Just a colon isn't safe. + _NAME_CONTENT_SEP: "@@**%%:%%**@@", + + // onLoadDeferred: [readonly] dojo.Deferred + // Deferred which is fired when the editor finishes loading. + // Call myEditor.onLoadDeferred.then(callback) it to be informed + // when the rich-text area initialization is finalized. + onLoadDeferred: null, + + // isTabIndent: Boolean + // Make tab key and shift-tab indent and outdent rather than navigating. + // Caution: sing this makes web pages inaccessible to users unable to use a mouse. + isTabIndent: false, + + // disableSpellCheck: [const] Boolean + // When true, disables the browser's native spell checking, if supported. + // Works only in Firefox. + disableSpellCheck: false, + + postCreate: function(){ + if("textarea" === this.domNode.tagName.toLowerCase()){ + console.warn("RichText should not be used with the TEXTAREA tag. See dijit._editor.RichText docs."); + } + + // Push in the builtin filters now, making them the first executed, but not over-riding anything + // users passed in. See: #6062 + this.contentPreFilters = [lang.hitch(this, "_preFixUrlAttributes")].concat(this.contentPreFilters); + if(has("mozilla")){ + this.contentPreFilters = [this._normalizeFontStyle].concat(this.contentPreFilters); + this.contentPostFilters = [this._removeMozBogus].concat(this.contentPostFilters); + } + if(has("webkit")){ + // Try to clean up WebKit bogus artifacts. The inserted classes + // made by WebKit sometimes messes things up. + this.contentPreFilters = [this._removeWebkitBogus].concat(this.contentPreFilters); + this.contentPostFilters = [this._removeWebkitBogus].concat(this.contentPostFilters); + } + if(has("ie")){ + // IE generates <strong> and <em> but we want to normalize to <b> and <i> + this.contentPostFilters = [this._normalizeFontStyle].concat(this.contentPostFilters); + this.contentDomPostFilters = [lang.hitch(this, this._stripBreakerNodes)].concat(this.contentDomPostFilters); + } + this.inherited(arguments); + + topic.publish(dijit._scopeName + "._editor.RichText::init", this); + this.open(); + this.setupDefaultShortcuts(); + }, + + setupDefaultShortcuts: function(){ + // summary: + // Add some default key handlers + // description: + // Overwrite this to setup your own handlers. The default + // implementation does not use Editor commands, but directly + // executes the builtin commands within the underlying browser + // support. + // tags: + // protected + var exec = lang.hitch(this, function(cmd, arg){ + return function(){ + return !this.execCommand(cmd,arg); + }; + }); + + var ctrlKeyHandlers = { + b: exec("bold"), + i: exec("italic"), + u: exec("underline"), + a: exec("selectall"), + s: function(){ this.save(true); }, + m: function(){ this.isTabIndent = !this.isTabIndent; }, + + "1": exec("formatblock", "h1"), + "2": exec("formatblock", "h2"), + "3": exec("formatblock", "h3"), + "4": exec("formatblock", "h4"), + + "\\": exec("insertunorderedlist") + }; + + if(!has("ie")){ + ctrlKeyHandlers.Z = exec("redo"); //FIXME: undo? + } + + var key; + for(key in ctrlKeyHandlers){ + this.addKeyHandler(key, true, false, ctrlKeyHandlers[key]); + } + }, + + // events: [private] String[] + // events which should be connected to the underlying editing area + events: ["onKeyPress", "onKeyDown", "onKeyUp"], // onClick handled specially + + // captureEvents: [deprecated] String[] + // Events which should be connected to the underlying editing + // area, events in this array will be addListener with + // capture=true. + // TODO: looking at the code I don't see any distinction between events and captureEvents, + // so get rid of this for 2.0 if not sooner + captureEvents: [], + + _editorCommandsLocalized: false, + _localizeEditorCommands: function(){ + // summary: + // When IE is running in a non-English locale, the API actually changes, + // so that we have to say (for example) danraku instead of p (for paragraph). + // Handle that here. + // tags: + // private + if(RichText._editorCommandsLocalized){ + // Use the already generate cache of mappings. + this._local2NativeFormatNames = RichText._local2NativeFormatNames; + this._native2LocalFormatNames = RichText._native2LocalFormatNames; + return; + } + RichText._editorCommandsLocalized = true; + RichText._local2NativeFormatNames = {}; + RichText._native2LocalFormatNames = {}; + this._local2NativeFormatNames = RichText._local2NativeFormatNames; + this._native2LocalFormatNames = RichText._native2LocalFormatNames; + //in IE, names for blockformat is locale dependent, so we cache the values here + + //put p after div, so if IE returns Normal, we show it as paragraph + //We can distinguish p and div if IE returns Normal, however, in order to detect that, + //we have to call this.document.selection.createRange().parentElement() or such, which + //could slow things down. Leave it as it is for now + var formats = ['div', 'p', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul', 'address']; + var localhtml = "", format, i=0; + while((format=formats[i++])){ + //append a <br> after each element to separate the elements more reliably + if(format.charAt(1) !== 'l'){ + localhtml += "<"+format+"><span>content</span></"+format+"><br/>"; + }else{ + localhtml += "<"+format+"><li>content</li></"+format+"><br/>"; + } + } + // queryCommandValue returns empty if we hide editNode, so move it out of screen temporary + // Also, IE9 does weird stuff unless we do it inside the editor iframe. + var style = { position: "absolute", top: "0px", zIndex: 10, opacity: 0.01 }; + var div = domConstruct.create('div', {style: style, innerHTML: localhtml}); + win.body().appendChild(div); + + // IE9 has a timing issue with doing this right after setting + // the inner HTML, so put a delay in. + var inject = lang.hitch(this, function(){ + var node = div.firstChild; + while(node){ + try{ + selectionapi.selectElement(node.firstChild); + var nativename = node.tagName.toLowerCase(); + this._local2NativeFormatNames[nativename] = document.queryCommandValue("formatblock"); + this._native2LocalFormatNames[this._local2NativeFormatNames[nativename]] = nativename; + node = node.nextSibling.nextSibling; + //console.log("Mapped: ", nativename, " to: ", this._local2NativeFormatNames[nativename]); + }catch(e){ /*Sqelch the occasional IE9 error */ } + } + div.parentNode.removeChild(div); + div.innerHTML = ""; + }); + setTimeout(inject, 0); + }, + + open: function(/*DomNode?*/ element){ + // summary: + // Transforms the node referenced in this.domNode into a rich text editing + // node. + // description: + // Sets up the editing area asynchronously. This will result in + // the creation and replacement with an iframe. + // tags: + // private + + if(!this.onLoadDeferred || this.onLoadDeferred.fired >= 0){ + this.onLoadDeferred = new Deferred(); + } + + if(!this.isClosed){ this.close(); } + topic.publish(dijit._scopeName + "._editor.RichText::open", this); + + if(arguments.length === 1 && element.nodeName){ // else unchanged + this.domNode = element; + } + + var dn = this.domNode; + + // "html" will hold the innerHTML of the srcNodeRef and will be used to + // initialize the editor. + var html; + + if(lang.isString(this.value)){ + // Allow setting the editor content programmatically instead of + // relying on the initial content being contained within the target + // domNode. + html = this.value; + delete this.value; + dn.innerHTML = ""; + }else if(dn.nodeName && dn.nodeName.toLowerCase() == "textarea"){ + // if we were created from a textarea, then we need to create a + // new editing harness node. + var ta = (this.textarea = dn); + this.name = ta.name; + html = ta.value; + dn = this.domNode = win.doc.createElement("div"); + dn.setAttribute('widgetId', this.id); + ta.removeAttribute('widgetId'); + dn.cssText = ta.cssText; + dn.className += " " + ta.className; + domConstruct.place(dn, ta, "before"); + var tmpFunc = lang.hitch(this, function(){ + //some browsers refuse to submit display=none textarea, so + //move the textarea off screen instead + domStyle.set(ta, { + display: "block", + position: "absolute", + top: "-1000px" + }); + + if(has("ie")){ //nasty IE bug: abnormal formatting if overflow is not hidden + var s = ta.style; + this.__overflow = s.overflow; + s.overflow = "hidden"; + } + }); + if(has("ie")){ + setTimeout(tmpFunc, 10); + }else{ + tmpFunc(); + } + + if(ta.form){ + var resetValue = ta.value; + this.reset = function(){ + var current = this.getValue(); + if(current !== resetValue){ + this.replaceValue(resetValue); + } + }; + on(ta.form, "submit", lang.hitch(this, function(){ + // Copy value to the <textarea> so it gets submitted along with form. + // FIXME: should we be calling close() here instead? + domAttr.set(ta, 'disabled', this.disabled); // don't submit the value if disabled + ta.value = this.getValue(); + })); + } + }else{ + html = htmlapi.getChildrenHtml(dn); + dn.innerHTML = ""; + } + + this.value = html; + + // If we're a list item we have to put in a blank line to force the + // bullet to nicely align at the top of text + if(dn.nodeName && dn.nodeName === "LI"){ + dn.innerHTML = " <br>"; + } + + // Construct the editor div structure. + this.header = dn.ownerDocument.createElement("div"); + dn.appendChild(this.header); + this.editingArea = dn.ownerDocument.createElement("div"); + dn.appendChild(this.editingArea); + this.footer = dn.ownerDocument.createElement("div"); + dn.appendChild(this.footer); + + if(!this.name){ + this.name = this.id + "_AUTOGEN"; + } + + // User has pressed back/forward button so we lost the text in the editor, but it's saved + // in a hidden <textarea> (which contains the data for all the editors on this page), + // so get editor value from there + if(this.name !== "" && (!config["useXDomain"] || config["allowXdRichTextSave"])){ + var saveTextarea = dom.byId(dijit._scopeName + "._editor.RichText.value"); + if(saveTextarea && saveTextarea.value !== ""){ + var datas = saveTextarea.value.split(this._SEPARATOR), i=0, dat; + while((dat=datas[i++])){ + var data = dat.split(this._NAME_CONTENT_SEP); + if(data[0] === this.name){ + html = data[1]; + datas = datas.splice(i, 1); + saveTextarea.value = datas.join(this._SEPARATOR); + break; + } + } + } + + if(!RichText._globalSaveHandler){ + RichText._globalSaveHandler = {}; + unload.addOnUnload(function(){ + var id; + for(id in RichText._globalSaveHandler){ + var f = RichText._globalSaveHandler[id]; + if(lang.isFunction(f)){ + f(); + } + } + }); + } + RichText._globalSaveHandler[this.id] = lang.hitch(this, "_saveContent"); + } + + this.isClosed = false; + + var ifr = (this.editorObject = this.iframe = win.doc.createElement('iframe')); + ifr.id = this.id+"_iframe"; + this._iframeSrc = this._getIframeDocTxt(); + ifr.style.border = "none"; + ifr.style.width = "100%"; + if(this._layoutMode){ + // iframe should be 100% height, thus getting it's height from surrounding + // <div> (which has the correct height set by Editor) + ifr.style.height = "100%"; + }else{ + if(has("ie") >= 7){ + if(this.height){ + ifr.style.height = this.height; + } + if(this.minHeight){ + ifr.style.minHeight = this.minHeight; + } + }else{ + ifr.style.height = this.height ? this.height : this.minHeight; + } + } + ifr.frameBorder = 0; + ifr._loadFunc = lang.hitch( this, function(w){ + this.window = w; + this.document = this.window.document; + + if(has("ie")){ + this._localizeEditorCommands(); + } + + // Do final setup and set initial contents of editor + this.onLoad(html); + }); + + // Set the iframe's initial (blank) content. + var iframeSrcRef = 'parent.' + dijit._scopeName + '.byId("'+this.id+'")._iframeSrc'; + var s = 'javascript:(function(){try{return ' + iframeSrcRef + '}catch(e){document.open();document.domain="' + + document.domain + '";document.write(' + iframeSrcRef + ');document.close();}})()'; + ifr.setAttribute('src', s); + this.editingArea.appendChild(ifr); + + if(has("safari") <= 4){ + var src = ifr.getAttribute("src"); + if(!src || src.indexOf("javascript") === -1){ + // Safari 4 and earlier sometimes act oddly + // So we have to set it again. + setTimeout(function(){ifr.setAttribute('src', s);},0); + } + } + + // TODO: this is a guess at the default line-height, kinda works + if(dn.nodeName === "LI"){ + dn.lastChild.style.marginTop = "-1.2em"; + } + + domClass.add(this.domNode, this.baseClass); + }, + + //static cache variables shared among all instance of this class + _local2NativeFormatNames: {}, + _native2LocalFormatNames: {}, + + _getIframeDocTxt: function(){ + // summary: + // Generates the boilerplate text of the document inside the iframe (ie, <html><head>...</head><body/></html>). + // Editor content (if not blank) should be added afterwards. + // tags: + // private + var _cs = domStyle.getComputedStyle(this.domNode); + + // The contents inside of <body>. The real contents are set later via a call to setValue(). + var html = ""; + var setBodyId = true; + if(has("ie") || has("webkit") || (!this.height && !has("mozilla"))){ + // In auto-expand mode, need a wrapper div for AlwaysShowToolbar plugin to correctly + // expand/contract the editor as the content changes. + html = "<div id='dijitEditorBody'></div>"; + setBodyId = false; + }else if(has("mozilla")){ + // workaround bug where can't select then delete text (until user types something + // into the editor)... and/or issue where typing doesn't erase selected text + this._cursorToStart = true; + html = " "; // + } + + var font = [ _cs.fontWeight, _cs.fontSize, _cs.fontFamily ].join(" "); + + // line height is tricky - applying a units value will mess things up. + // if we can't get a non-units value, bail out. + var lineHeight = _cs.lineHeight; + if(lineHeight.indexOf("px") >= 0){ + lineHeight = parseFloat(lineHeight)/parseFloat(_cs.fontSize); + // console.debug(lineHeight); + }else if(lineHeight.indexOf("em")>=0){ + lineHeight = parseFloat(lineHeight); + }else{ + // If we can't get a non-units value, just default + // it to the CSS spec default of 'normal'. Seems to + // work better, esp on IE, than '1.0' + lineHeight = "normal"; + } + var userStyle = ""; + var self = this; + this.style.replace(/(^|;)\s*(line-|font-?)[^;]+/ig, function(match){ + match = match.replace(/^;/ig,"") + ';'; + var s = match.split(":")[0]; + if(s){ + s = lang.trim(s); + s = s.toLowerCase(); + var i; + var sC = ""; + for(i = 0; i < s.length; i++){ + var c = s.charAt(i); + switch(c){ + case "-": + i++; + c = s.charAt(i).toUpperCase(); + default: + sC += c; + } + } + domStyle.set(self.domNode, sC, ""); + } + userStyle += match + ';'; + }); + + + // need to find any associated label element and update iframe document title + var label=query('label[for="'+this.id+'"]'); + + return [ + this.isLeftToRight() ? "<html>\n<head>\n" : "<html dir='rtl'>\n<head>\n", + (has("mozilla") && label.length ? "<title>" + label[0].innerHTML + "</title>\n" : ""), + "<meta http-equiv='Content-Type' content='text/html'>\n", + "<style>\n", + "\tbody,html {\n", + "\t\tbackground:transparent;\n", + "\t\tpadding: 1px 0 0 0;\n", + "\t\tmargin: -1px 0 0 0;\n", // remove extraneous vertical scrollbar on safari and firefox + + // Set the html/body sizing. Webkit always needs this, other browsers + // only set it when height is defined (not auto-expanding), otherwise + // scrollers do not appear. + ((has("webkit"))?"\t\twidth: 100%;\n":""), + ((has("webkit"))?"\t\theight: 100%;\n":""), + "\t}\n", + + // TODO: left positioning will cause contents to disappear out of view + // if it gets too wide for the visible area + "\tbody{\n", + "\t\ttop:0px;\n", + "\t\tleft:0px;\n", + "\t\tright:0px;\n", + "\t\tfont:", font, ";\n", + ((this.height||has("opera")) ? "" : "\t\tposition: fixed;\n"), + // FIXME: IE 6 won't understand min-height? + "\t\tmin-height:", this.minHeight, ";\n", + "\t\tline-height:", lineHeight,";\n", + "\t}\n", + "\tp{ margin: 1em 0; }\n", + + // Determine how scrollers should be applied. In autoexpand mode (height = "") no scrollers on y at all. + // But in fixed height mode we want both x/y scrollers. Also, if it's using wrapping div and in auto-expand + // (Mainly IE) we need to kill the y scroller on body and html. + (!setBodyId && !this.height ? "\tbody,html {overflow-y: hidden;}\n" : ""), + "\t#dijitEditorBody{overflow-x: auto; overflow-y:" + (this.height ? "auto;" : "hidden;") + " outline: 0px;}\n", + "\tli > ul:-moz-first-node, li > ol:-moz-first-node{ padding-top: 1.2em; }\n", + // Can't set min-height in IE9, it puts layout on li, which puts move/resize handles. + (!has("ie") ? "\tli{ min-height:1.2em; }\n" : ""), + "</style>\n", + this._applyEditingAreaStyleSheets(),"\n", + "</head>\n<body ", + (setBodyId?"id='dijitEditorBody' ":""), + "onload='frameElement._loadFunc(window,document)' style='"+userStyle+"'>", html, "</body>\n</html>" + ].join(""); // String + }, + + _applyEditingAreaStyleSheets: function(){ + // summary: + // apply the specified css files in styleSheets + // tags: + // private + var files = []; + if(this.styleSheets){ + files = this.styleSheets.split(';'); + this.styleSheets = ''; + } + + //empty this.editingAreaStyleSheets here, as it will be filled in addStyleSheet + files = files.concat(this.editingAreaStyleSheets); + this.editingAreaStyleSheets = []; + + var text='', i=0, url; + while((url=files[i++])){ + var abstring = (new _Url(win.global.location, url)).toString(); + this.editingAreaStyleSheets.push(abstring); + text += '<link rel="stylesheet" type="text/css" href="'+abstring+'"/>'; + } + return text; + }, + + addStyleSheet: function(/*dojo._Url*/ uri){ + // summary: + // add an external stylesheet for the editing area + // uri: + // A dojo.uri.Uri pointing to the url of the external css file + var url=uri.toString(); + + //if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe + if(url.charAt(0) === '.' || (url.charAt(0) !== '/' && !uri.host)){ + url = (new _Url(win.global.location, url)).toString(); + } + + if(array.indexOf(this.editingAreaStyleSheets, url) > -1){ +// console.debug("dijit._editor.RichText.addStyleSheet: Style sheet "+url+" is already applied"); + return; + } + + this.editingAreaStyleSheets.push(url); + this.onLoadDeferred.addCallback(lang.hitch(this, function(){ + if(this.document.createStyleSheet){ //IE + this.document.createStyleSheet(url); + }else{ //other browser + var head = this.document.getElementsByTagName("head")[0]; + var stylesheet = this.document.createElement("link"); + stylesheet.rel="stylesheet"; + stylesheet.type="text/css"; + stylesheet.href=url; + head.appendChild(stylesheet); + } + })); + }, + + removeStyleSheet: function(/*dojo._Url*/ uri){ + // summary: + // remove an external stylesheet for the editing area + var url=uri.toString(); + //if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe + if(url.charAt(0) === '.' || (url.charAt(0) !== '/' && !uri.host)){ + url = (new _Url(win.global.location, url)).toString(); + } + var index = array.indexOf(this.editingAreaStyleSheets, url); + if(index === -1){ +// console.debug("dijit._editor.RichText.removeStyleSheet: Style sheet "+url+" has not been applied"); + return; + } + delete this.editingAreaStyleSheets[index]; + win.withGlobal(this.window,'query', dojo, ['link:[href="'+url+'"]']).orphan(); + }, + + // disabled: Boolean + // The editor is disabled; the text cannot be changed. + disabled: false, + + _mozSettingProps: {'styleWithCSS':false}, + _setDisabledAttr: function(/*Boolean*/ value){ + value = !!value; + this._set("disabled", value); + if(!this.isLoaded){ return; } // this method requires init to be complete + if(has("ie") || has("webkit") || has("opera")){ + var preventIEfocus = has("ie") && (this.isLoaded || !this.focusOnLoad); + if(preventIEfocus){ this.editNode.unselectable = "on"; } + this.editNode.contentEditable = !value; + if(preventIEfocus){ + var _this = this; + setTimeout(function(){ + if(_this.editNode){ // guard in case widget destroyed before timeout + _this.editNode.unselectable = "off"; + } + }, 0); + } + }else{ //moz + try{ + this.document.designMode=(value?'off':'on'); + }catch(e){ return; } // ! _disabledOK + if(!value && this._mozSettingProps){ + var ps = this._mozSettingProps; + var n; + for(n in ps){ + if(ps.hasOwnProperty(n)){ + try{ + this.document.execCommand(n,false,ps[n]); + }catch(e2){} + } + } + } +// this.document.execCommand('contentReadOnly', false, value); +// if(value){ +// this.blur(); //to remove the blinking caret +// } + } + this._disabledOK = true; + }, + +/* Event handlers + *****************/ + + onLoad: function(/*String*/ html){ + // summary: + // Handler after the iframe finishes loading. + // html: String + // Editor contents should be set to this value + // tags: + // protected + + // TODO: rename this to _onLoad, make empty public onLoad() method, deprecate/make protected onLoadDeferred handler? + + if(!this.window.__registeredWindow){ + this.window.__registeredWindow = true; + this._iframeRegHandle = focus.registerIframe(this.iframe); + } + if(!has("ie") && !has("webkit") && (this.height || has("mozilla"))){ + this.editNode=this.document.body; + }else{ + // there's a wrapper div around the content, see _getIframeDocTxt(). + this.editNode=this.document.body.firstChild; + var _this = this; + if(has("ie")){ // #4996 IE wants to focus the BODY tag + this.tabStop = domConstruct.create('div', { tabIndex: -1 }, this.editingArea); + this.iframe.onfocus = function(){ _this.editNode.setActive(); }; + } + } + this.focusNode = this.editNode; // for InlineEditBox + + + var events = this.events.concat(this.captureEvents); + var ap = this.iframe ? this.document : this.editNode; + array.forEach(events, function(item){ + this.connect(ap, item.toLowerCase(), item); + }, this); + + this.connect(ap, "onmouseup", "onClick"); // mouseup in the margin does not generate an onclick event + + if(has("ie")){ // IE contentEditable + this.connect(this.document, "onmousedown", "_onIEMouseDown"); // #4996 fix focus + + // give the node Layout on IE + // TODO: this may no longer be needed, since we've reverted IE to using an iframe, + // not contentEditable. Removing it would also probably remove the need for creating + // the extra <div> in _getIframeDocTxt() + this.editNode.style.zoom = 1.0; + }else{ + this.connect(this.document, "onmousedown", function(){ + // Clear the moveToStart focus, as mouse + // down will set cursor point. Required to properly + // work with selection/position driven plugins and clicks in + // the window. refs: #10678 + delete this._cursorToStart; + }); + } + + if(has("webkit")){ + //WebKit sometimes doesn't fire right on selections, so the toolbar + //doesn't update right. Therefore, help it out a bit with an additional + //listener. A mouse up will typically indicate a display change, so fire this + //and get the toolbar to adapt. Reference: #9532 + this._webkitListener = this.connect(this.document, "onmouseup", "onDisplayChanged"); + this.connect(this.document, "onmousedown", function(e){ + var t = e.target; + if(t && (t === this.document.body || t === this.document)){ + // Since WebKit uses the inner DIV, we need to check and set position. + // See: #12024 as to why the change was made. + setTimeout(lang.hitch(this, "placeCursorAtEnd"), 0); + } + }); + } + + if(has("ie")){ + // Try to make sure 'hidden' elements aren't visible in edit mode (like browsers other than IE + // do). See #9103 + try{ + this.document.execCommand('RespectVisibilityInDesign', true, null); + }catch(e){/* squelch */} + } + + this.isLoaded = true; + + this.set('disabled', this.disabled); // initialize content to editable (or not) + + // Note that setValue() call will only work after isLoaded is set to true (above) + + // Set up a function to allow delaying the setValue until a callback is fired + // This ensures extensions like dijit.Editor have a way to hold the value set + // until plugins load (and do things like register filters). + var setContent = lang.hitch(this, function(){ + this.setValue(html); + if(this.onLoadDeferred){ + this.onLoadDeferred.callback(true); + } + this.onDisplayChanged(); + if(this.focusOnLoad){ + // after the document loads, then set focus after updateInterval expires so that + // onNormalizedDisplayChanged has run to avoid input caret issues + ready(lang.hitch(this, function(){ setTimeout(lang.hitch(this, "focus"), this.updateInterval); })); + } + // Save off the initial content now + this.value = this.getValue(true); + }); + if(this.setValueDeferred){ + this.setValueDeferred.addCallback(setContent); + }else{ + setContent(); + } + }, + + onKeyDown: function(/* Event */ e){ + // summary: + // Handler for onkeydown event + // tags: + // protected + + // we need this event at the moment to get the events from control keys + // such as the backspace. It might be possible to add this to Dojo, so that + // keyPress events can be emulated by the keyDown and keyUp detection. + + if(e.keyCode === keys.TAB && this.isTabIndent ){ + event.stop(e); //prevent tab from moving focus out of editor + + // FIXME: this is a poor-man's indent/outdent. It would be + // better if it added 4 " " chars in an undoable way. + // Unfortunately pasteHTML does not prove to be undoable + if(this.queryCommandEnabled((e.shiftKey ? "outdent" : "indent"))){ + this.execCommand((e.shiftKey ? "outdent" : "indent")); + } + } + if(has("ie")){ + if(e.keyCode == keys.TAB && !this.isTabIndent){ + if(e.shiftKey && !e.ctrlKey && !e.altKey){ + // focus the BODY so the browser will tab away from it instead + this.iframe.focus(); + }else if(!e.shiftKey && !e.ctrlKey && !e.altKey){ + // focus the BODY so the browser will tab away from it instead + this.tabStop.focus(); + } + }else if(e.keyCode === keys.BACKSPACE && this.document.selection.type === "Control"){ + // IE has a bug where if a non-text object is selected in the editor, + // hitting backspace would act as if the browser's back button was + // clicked instead of deleting the object. see #1069 + event.stop(e); + this.execCommand("delete"); + }else if((65 <= e.keyCode && e.keyCode <= 90) || + (e.keyCode>=37 && e.keyCode<=40) // FIXME: get this from connect() instead! + ){ //arrow keys + e.charCode = e.keyCode; + this.onKeyPress(e); + } + } + if(has("ff")){ + if(e.keyCode === keys.PAGE_UP || e.keyCode === keys.PAGE_DOWN ){ + if(this.editNode.clientHeight >= this.editNode.scrollHeight){ + // Stop the event to prevent firefox from trapping the cursor when there is no scroll bar. + e.preventDefault(); + } + } + } + return true; + }, + + onKeyUp: function(/*===== e =====*/){ + // summary: + // Handler for onkeyup event + // tags: + // callback + }, + + setDisabled: function(/*Boolean*/ disabled){ + // summary: + // Deprecated, use set('disabled', ...) instead. + // tags: + // deprecated + kernel.deprecated('dijit.Editor::setDisabled is deprecated','use dijit.Editor::attr("disabled",boolean) instead', 2.0); + this.set('disabled',disabled); + }, + _setValueAttr: function(/*String*/ value){ + // summary: + // Registers that attr("value", foo) should call setValue(foo) + this.setValue(value); + }, + _setDisableSpellCheckAttr: function(/*Boolean*/ disabled){ + if(this.document){ + domAttr.set(this.document.body, "spellcheck", !disabled); + }else{ + // try again after the editor is finished loading + this.onLoadDeferred.addCallback(lang.hitch(this, function(){ + domAttr.set(this.document.body, "spellcheck", !disabled); + })); + } + this._set("disableSpellCheck", disabled); + }, + + onKeyPress: function(e){ + // summary: + // Handle the various key events + // tags: + // protected + + var c = (e.keyChar && e.keyChar.toLowerCase()) || e.keyCode, + handlers = this._keyHandlers[c], + args = arguments; + + if(handlers && !e.altKey){ + array.some(handlers, function(h){ + // treat meta- same as ctrl-, for benefit of mac users + if(!(h.shift ^ e.shiftKey) && !(h.ctrl ^ (e.ctrlKey||e.metaKey))){ + if(!h.handler.apply(this, args)){ + e.preventDefault(); + } + return true; + } + }, this); + } + + // function call after the character has been inserted + if(!this._onKeyHitch){ + this._onKeyHitch = lang.hitch(this, "onKeyPressed"); + } + setTimeout(this._onKeyHitch, 1); + return true; + }, + + addKeyHandler: function(/*String*/ key, /*Boolean*/ ctrl, /*Boolean*/ shift, /*Function*/ handler){ + // summary: + // Add a handler for a keyboard shortcut + // description: + // The key argument should be in lowercase if it is a letter character + // tags: + // protected + if(!lang.isArray(this._keyHandlers[key])){ + this._keyHandlers[key] = []; + } + //TODO: would be nice to make this a hash instead of an array for quick lookups + this._keyHandlers[key].push({ + shift: shift || false, + ctrl: ctrl || false, + handler: handler + }); + }, + + onKeyPressed: function(){ + // summary: + // Handler for after the user has pressed a key, and the display has been updated. + // (Runs on a timer so that it runs after the display is updated) + // tags: + // private + this.onDisplayChanged(/*e*/); // can't pass in e + }, + + onClick: function(/*Event*/ e){ + // summary: + // Handler for when the user clicks. + // tags: + // private + + // console.info('onClick',this._tryDesignModeOn); + this.onDisplayChanged(e); + }, + + _onIEMouseDown: function(){ + // summary: + // IE only to prevent 2 clicks to focus + // tags: + // protected + + if(!this.focused && !this.disabled){ + this.focus(); + } + }, + + _onBlur: function(e){ + // summary: + // Called from focus manager when focus has moved away from this editor + // tags: + // protected + + // console.info('_onBlur') + + this.inherited(arguments); + + var newValue = this.getValue(true); + if(newValue !== this.value){ + this.onChange(newValue); + } + this._set("value", newValue); + }, + + _onFocus: function(/*Event*/ e){ + // summary: + // Called from focus manager when focus has moved into this editor + // tags: + // protected + + // console.info('_onFocus') + if(!this.disabled){ + if(!this._disabledOK){ + this.set('disabled', false); + } + this.inherited(arguments); + } + }, + + // TODO: remove in 2.0 + blur: function(){ + // summary: + // Remove focus from this instance. + // tags: + // deprecated + if(!has("ie") && this.window.document.documentElement && this.window.document.documentElement.focus){ + this.window.document.documentElement.focus(); + }else if(win.doc.body.focus){ + win.doc.body.focus(); + } + }, + + focus: function(){ + // summary: + // Move focus to this editor + if(!this.isLoaded){ + this.focusOnLoad = true; + return; + } + if(this._cursorToStart){ + delete this._cursorToStart; + if(this.editNode.childNodes){ + this.placeCursorAtStart(); // this calls focus() so return + return; + } + } + if(!has("ie")){ + focus.focus(this.iframe); + }else if(this.editNode && this.editNode.focus){ + // editNode may be hidden in display:none div, lets just punt in this case + //this.editNode.focus(); -> causes IE to scroll always (strict and quirks mode) to the top the Iframe + // if we fire the event manually and let the browser handle the focusing, the latest + // cursor position is focused like in FF + this.iframe.fireEvent('onfocus', document.createEventObject()); // createEventObject only in IE + // }else{ + // TODO: should we throw here? + // console.debug("Have no idea how to focus into the editor!"); + } + }, + + // _lastUpdate: 0, + updateInterval: 200, + _updateTimer: null, + onDisplayChanged: function(/*Event*/ /*===== e =====*/){ + // summary: + // This event will be fired every time the display context + // changes and the result needs to be reflected in the UI. + // description: + // If you don't want to have update too often, + // onNormalizedDisplayChanged should be used instead + // tags: + // private + + // var _t=new Date(); + if(this._updateTimer){ + clearTimeout(this._updateTimer); + } + if(!this._updateHandler){ + this._updateHandler = lang.hitch(this,"onNormalizedDisplayChanged"); + } + this._updateTimer = setTimeout(this._updateHandler, this.updateInterval); + + // Technically this should trigger a call to watch("value", ...) registered handlers, + // but getValue() is too slow to call on every keystroke so we don't. + }, + onNormalizedDisplayChanged: function(){ + // summary: + // This event is fired every updateInterval ms or more + // description: + // If something needs to happen immediately after a + // user change, please use onDisplayChanged instead. + // tags: + // private + delete this._updateTimer; + }, + onChange: function(/*===== newContent =====*/){ + // summary: + // This is fired if and only if the editor loses focus and + // the content is changed. + }, + _normalizeCommand: function(/*String*/ cmd, /*Anything?*/argument){ + // summary: + // Used as the advice function to map our + // normalized set of commands to those supported by the target + // browser. + // tags: + // private + + var command = cmd.toLowerCase(); + if(command === "formatblock"){ + if(has("safari") && argument === undefined){ command = "heading"; } + }else if(command === "hilitecolor" && !has("mozilla")){ + command = "backcolor"; + } + + return command; + }, + + _qcaCache: {}, + queryCommandAvailable: function(/*String*/ command){ + // summary: + // Tests whether a command is supported by the host. Clients + // SHOULD check whether a command is supported before attempting + // to use it, behaviour for unsupported commands is undefined. + // command: + // The command to test for + // tags: + // private + + // memoizing version. See _queryCommandAvailable for computing version + var ca = this._qcaCache[command]; + if(ca !== undefined){ return ca; } + return (this._qcaCache[command] = this._queryCommandAvailable(command)); + }, + + _queryCommandAvailable: function(/*String*/ command){ + // summary: + // See queryCommandAvailable(). + // tags: + // private + + var ie = 1; + var mozilla = 1 << 1; + var webkit = 1 << 2; + var opera = 1 << 3; + + function isSupportedBy(browsers){ + return { + ie: Boolean(browsers & ie), + mozilla: Boolean(browsers & mozilla), + webkit: Boolean(browsers & webkit), + opera: Boolean(browsers & opera) + }; + } + + var supportedBy = null; + + switch(command.toLowerCase()){ + case "bold": case "italic": case "underline": + case "subscript": case "superscript": + case "fontname": case "fontsize": + case "forecolor": case "hilitecolor": + case "justifycenter": case "justifyfull": case "justifyleft": + case "justifyright": case "delete": case "selectall": case "toggledir": + supportedBy = isSupportedBy(mozilla | ie | webkit | opera); + break; + + case "createlink": case "unlink": case "removeformat": + case "inserthorizontalrule": case "insertimage": + case "insertorderedlist": case "insertunorderedlist": + case "indent": case "outdent": case "formatblock": + case "inserthtml": case "undo": case "redo": case "strikethrough": case "tabindent": + supportedBy = isSupportedBy(mozilla | ie | opera | webkit); + break; + + case "blockdirltr": case "blockdirrtl": + case "dirltr": case "dirrtl": + case "inlinedirltr": case "inlinedirrtl": + supportedBy = isSupportedBy(ie); + break; + case "cut": case "copy": case "paste": + supportedBy = isSupportedBy( ie | mozilla | webkit); + break; + + case "inserttable": + supportedBy = isSupportedBy(mozilla | ie); + break; + + case "insertcell": case "insertcol": case "insertrow": + case "deletecells": case "deletecols": case "deleterows": + case "mergecells": case "splitcell": + supportedBy = isSupportedBy(ie | mozilla); + break; + + default: return false; + } + + return (has("ie") && supportedBy.ie) || + (has("mozilla") && supportedBy.mozilla) || + (has("webkit") && supportedBy.webkit) || + (has("opera") && supportedBy.opera); // Boolean return true if the command is supported, false otherwise + }, + + execCommand: function(/*String*/ command, argument){ + // summary: + // Executes a command in the Rich Text area + // command: + // The command to execute + // argument: + // An optional argument to the command + // tags: + // protected + var returnValue; + + //focus() is required for IE to work + //In addition, focus() makes sure after the execution of + //the command, the editor receives the focus as expected + this.focus(); + + command = this._normalizeCommand(command, argument); + + if(argument !== undefined){ + if(command === "heading"){ + throw new Error("unimplemented"); + }else if((command === "formatblock") && has("ie")){ + argument = '<'+argument+'>'; + } + } + + //Check to see if we have any over-rides for commands, they will be functions on this + //widget of the form _commandImpl. If we don't, fall through to the basic native + //exec command of the browser. + var implFunc = "_" + command + "Impl"; + if(this[implFunc]){ + returnValue = this[implFunc](argument); + }else{ + argument = arguments.length > 1 ? argument : null; + if(argument || command !== "createlink"){ + returnValue = this.document.execCommand(command, false, argument); + } + } + + this.onDisplayChanged(); + return returnValue; + }, + + queryCommandEnabled: function(/*String*/ command){ + // summary: + // Check whether a command is enabled or not. + // command: + // The command to execute + // tags: + // protected + if(this.disabled || !this._disabledOK){ return false; } + + command = this._normalizeCommand(command); + + //Check to see if we have any over-rides for commands, they will be functions on this + //widget of the form _commandEnabledImpl. If we don't, fall through to the basic native + //command of the browser. + var implFunc = "_" + command + "EnabledImpl"; + + if(this[implFunc]){ + return this[implFunc](command); + }else{ + return this._browserQueryCommandEnabled(command); + } + }, + + queryCommandState: function(command){ + // summary: + // Check the state of a given command and returns true or false. + // tags: + // protected + + if(this.disabled || !this._disabledOK){ return false; } + command = this._normalizeCommand(command); + try{ + return this.document.queryCommandState(command); + }catch(e){ + //Squelch, occurs if editor is hidden on FF 3 (and maybe others.) + return false; + } + }, + + queryCommandValue: function(command){ + // summary: + // Check the value of a given command. This matters most for + // custom selections and complex values like font value setting. + // tags: + // protected + + if(this.disabled || !this._disabledOK){ return false; } + var r; + command = this._normalizeCommand(command); + if(has("ie") && command === "formatblock"){ + r = this._native2LocalFormatNames[this.document.queryCommandValue(command)]; + }else if(has("mozilla") && command === "hilitecolor"){ + var oldValue; + try{ + oldValue = this.document.queryCommandValue("styleWithCSS"); + }catch(e){ + oldValue = false; + } + this.document.execCommand("styleWithCSS", false, true); + r = this.document.queryCommandValue(command); + this.document.execCommand("styleWithCSS", false, oldValue); + }else{ + r = this.document.queryCommandValue(command); + } + return r; + }, + + // Misc. + + _sCall: function(name, args){ + // summary: + // Run the named method of dijit._editor.selection over the + // current editor instance's window, with the passed args. + // tags: + // private + return win.withGlobal(this.window, name, selectionapi, args); + }, + + // FIXME: this is a TON of code duplication. Why? + + placeCursorAtStart: function(){ + // summary: + // Place the cursor at the start of the editing area. + // tags: + // private + + this.focus(); + + //see comments in placeCursorAtEnd + var isvalid=false; + if(has("mozilla")){ + // TODO: Is this branch even necessary? + var first=this.editNode.firstChild; + while(first){ + if(first.nodeType === 3){ + if(first.nodeValue.replace(/^\s+|\s+$/g, "").length>0){ + isvalid=true; + this._sCall("selectElement", [ first ]); + break; + } + }else if(first.nodeType === 1){ + isvalid=true; + var tg = first.tagName ? first.tagName.toLowerCase() : ""; + // Collapse before childless tags. + if(/br|input|img|base|meta|area|basefont|hr|link/.test(tg)){ + this._sCall("selectElement", [ first ]); + }else{ + // Collapse inside tags with children. + this._sCall("selectElementChildren", [ first ]); + } + break; + } + first = first.nextSibling; + } + }else{ + isvalid=true; + this._sCall("selectElementChildren", [ this.editNode ]); + } + if(isvalid){ + this._sCall("collapse", [ true ]); + } + }, + + placeCursorAtEnd: function(){ + // summary: + // Place the cursor at the end of the editing area. + // tags: + // private + + this.focus(); + + //In mozilla, if last child is not a text node, we have to use + // selectElementChildren on this.editNode.lastChild otherwise the + // cursor would be placed at the end of the closing tag of + //this.editNode.lastChild + var isvalid=false; + if(has("mozilla")){ + var last=this.editNode.lastChild; + while(last){ + if(last.nodeType === 3){ + if(last.nodeValue.replace(/^\s+|\s+$/g, "").length>0){ + isvalid=true; + this._sCall("selectElement", [ last ]); + break; + } + }else if(last.nodeType === 1){ + isvalid=true; + if(last.lastChild){ + this._sCall("selectElement", [ last.lastChild ]); + }else{ + this._sCall("selectElement", [ last ]); + } + break; + } + last = last.previousSibling; + } + }else{ + isvalid=true; + this._sCall("selectElementChildren", [ this.editNode ]); + } + if(isvalid){ + this._sCall("collapse", [ false ]); + } + }, + + getValue: function(/*Boolean?*/ nonDestructive){ + // summary: + // Return the current content of the editing area (post filters + // are applied). Users should call get('value') instead. + // nonDestructive: + // defaults to false. Should the post-filtering be run over a copy + // of the live DOM? Most users should pass "true" here unless they + // *really* know that none of the installed filters are going to + // mess up the editing session. + // tags: + // private + if(this.textarea){ + if(this.isClosed || !this.isLoaded){ + return this.textarea.value; + } + } + + return this._postFilterContent(null, nonDestructive); + }, + _getValueAttr: function(){ + // summary: + // Hook to make attr("value") work + return this.getValue(true); + }, + + setValue: function(/*String*/ html){ + // summary: + // This function sets the content. No undo history is preserved. + // Users should use set('value', ...) instead. + // tags: + // deprecated + + // TODO: remove this and getValue() for 2.0, and move code to _setValueAttr() + + if(!this.isLoaded){ + // try again after the editor is finished loading + this.onLoadDeferred.addCallback(lang.hitch(this, function(){ + this.setValue(html); + })); + return; + } + this._cursorToStart = true; + if(this.textarea && (this.isClosed || !this.isLoaded)){ + this.textarea.value=html; + }else{ + html = this._preFilterContent(html); + var node = this.isClosed ? this.domNode : this.editNode; + if(html && has("mozilla") && html.toLowerCase() === "<p></p>"){ + html = "<p> </p>"; // + } + + // Use to avoid webkit problems where editor is disabled until the user clicks it + if(!html && has("webkit")){ + html = " "; // + } + node.innerHTML = html; + this._preDomFilterContent(node); + } + + this.onDisplayChanged(); + this._set("value", this.getValue(true)); + }, + + replaceValue: function(/*String*/ html){ + // summary: + // This function set the content while trying to maintain the undo stack + // (now only works fine with Moz, this is identical to setValue in all + // other browsers) + // tags: + // protected + + if(this.isClosed){ + this.setValue(html); + }else if(this.window && this.window.getSelection && !has("mozilla")){ // Safari + // look ma! it's a totally f'd browser! + this.setValue(html); + }else if(this.window && this.window.getSelection){ // Moz + html = this._preFilterContent(html); + this.execCommand("selectall"); + if(!html){ + this._cursorToStart = true; + html = " "; // + } + this.execCommand("inserthtml", html); + this._preDomFilterContent(this.editNode); + }else if(this.document && this.document.selection){//IE + //In IE, when the first element is not a text node, say + //an <a> tag, when replacing the content of the editing + //area, the <a> tag will be around all the content + //so for now, use setValue for IE too + this.setValue(html); + } + + this._set("value", this.getValue(true)); + }, + + _preFilterContent: function(/*String*/ html){ + // summary: + // Filter the input before setting the content of the editing + // area. DOM pre-filtering may happen after this + // string-based filtering takes place but as of 1.2, this is not + // guaranteed for operations such as the inserthtml command. + // tags: + // private + + var ec = html; + array.forEach(this.contentPreFilters, function(ef){ if(ef){ ec = ef(ec); } }); + return ec; + }, + _preDomFilterContent: function(/*DomNode*/ dom){ + // summary: + // filter the input's live DOM. All filter operations should be + // considered to be "live" and operating on the DOM that the user + // will be interacting with in their editing session. + // tags: + // private + dom = dom || this.editNode; + array.forEach(this.contentDomPreFilters, function(ef){ + if(ef && lang.isFunction(ef)){ + ef(dom); + } + }, this); + }, + + _postFilterContent: function( + /*DomNode|DomNode[]|String?*/ dom, + /*Boolean?*/ nonDestructive){ + // summary: + // filter the output after getting the content of the editing area + // + // description: + // post-filtering allows plug-ins and users to specify any number + // of transforms over the editor's content, enabling many common + // use-cases such as transforming absolute to relative URLs (and + // vice-versa), ensuring conformance with a particular DTD, etc. + // The filters are registered in the contentDomPostFilters and + // contentPostFilters arrays. Each item in the + // contentDomPostFilters array is a function which takes a DOM + // Node or array of nodes as its only argument and returns the + // same. It is then passed down the chain for further filtering. + // The contentPostFilters array behaves the same way, except each + // member operates on strings. Together, the DOM and string-based + // filtering allow the full range of post-processing that should + // be necessaray to enable even the most agressive of post-editing + // conversions to take place. + // + // If nonDestructive is set to "true", the nodes are cloned before + // filtering proceeds to avoid potentially destructive transforms + // to the content which may still needed to be edited further. + // Once DOM filtering has taken place, the serialized version of + // the DOM which is passed is run through each of the + // contentPostFilters functions. + // + // dom: + // a node, set of nodes, which to filter using each of the current + // members of the contentDomPostFilters and contentPostFilters arrays. + // + // nonDestructive: + // defaults to "false". If true, ensures that filtering happens on + // a clone of the passed-in content and not the actual node + // itself. + // + // tags: + // private + + var ec; + if(!lang.isString(dom)){ + dom = dom || this.editNode; + if(this.contentDomPostFilters.length){ + if(nonDestructive){ + dom = lang.clone(dom); + } + array.forEach(this.contentDomPostFilters, function(ef){ + dom = ef(dom); + }); + } + ec = htmlapi.getChildrenHtml(dom); + }else{ + ec = dom; + } + + if(!lang.trim(ec.replace(/^\xA0\xA0*/, '').replace(/\xA0\xA0*$/, '')).length){ + ec = ""; + } + + // if(has("ie")){ + // //removing appended <P> </P> for IE + // ec = ec.replace(/(?:<p> </p>[\n\r]*)+$/i,""); + // } + array.forEach(this.contentPostFilters, function(ef){ + ec = ef(ec); + }); + + return ec; + }, + + _saveContent: function(){ + // summary: + // Saves the content in an onunload event if the editor has not been closed + // tags: + // private + + var saveTextarea = dom.byId(dijit._scopeName + "._editor.RichText.value"); + if(saveTextarea){ + if(saveTextarea.value){ + saveTextarea.value += this._SEPARATOR; + } + saveTextarea.value += this.name + this._NAME_CONTENT_SEP + this.getValue(true); + } + }, + + + escapeXml: function(/*String*/ str, /*Boolean*/ noSingleQuotes){ + // summary: + // Adds escape sequences for special characters in XML. + // Optionally skips escapes for single quotes + // tags: + // private + + str = str.replace(/&/gm, "&").replace(/</gm, "<").replace(/>/gm, ">").replace(/"/gm, """); + if(!noSingleQuotes){ + str = str.replace(/'/gm, "'"); + } + return str; // string + }, + + getNodeHtml: function(/* DomNode */ node){ + // summary: + // Deprecated. Use dijit/_editor/html::_getNodeHtml() instead. + // tags: + // deprecated + kernel.deprecated('dijit.Editor::getNodeHtml is deprecated','use dijit/_editor/html::getNodeHtml instead', 2); + return htmlapi.getNodeHtml(node); // String + }, + + getNodeChildrenHtml: function(/* DomNode */ dom){ + // summary: + // Deprecated. Use dijit/_editor/html::getChildrenHtml() instead. + // tags: + // deprecated + kernel.deprecated('dijit.Editor::getNodeChildrenHtml is deprecated','use dijit/_editor/html::getChildrenHtml instead', 2); + return htmlapi.getChildrenHtml(dom); + }, + + close: function(/*Boolean?*/ save){ + // summary: + // Kills the editor and optionally writes back the modified contents to the + // element from which it originated. + // save: + // Whether or not to save the changes. If false, the changes are discarded. + // tags: + // private + + if(this.isClosed){ return; } + + if(!arguments.length){ save = true; } + if(save){ + this._set("value", this.getValue(true)); + } + + // line height is squashed for iframes + // FIXME: why was this here? if(this.iframe){ this.domNode.style.lineHeight = null; } + + if(this.interval){ clearInterval(this.interval); } + + if(this._webkitListener){ + //Cleaup of WebKit fix: #9532 + this.disconnect(this._webkitListener); + delete this._webkitListener; + } + + // Guard against memory leaks on IE (see #9268) + if(has("ie")){ + this.iframe.onfocus = null; + } + this.iframe._loadFunc = null; + + if(this._iframeRegHandle){ + this._iframeRegHandle.remove(); + delete this._iframeRegHandle; + } + + if(this.textarea){ + var s = this.textarea.style; + s.position = ""; + s.left = s.top = ""; + if(has("ie")){ + s.overflow = this.__overflow; + this.__overflow = null; + } + this.textarea.value = this.value; + domConstruct.destroy(this.domNode); + this.domNode = this.textarea; + }else{ + // Note that this destroys the iframe + this.domNode.innerHTML = this.value; + } + delete this.iframe; + + domClass.remove(this.domNode, this.baseClass); + this.isClosed = true; + this.isLoaded = false; + + delete this.editNode; + delete this.focusNode; + + if(this.window && this.window._frameElement){ + this.window._frameElement = null; + } + + this.window = null; + this.document = null; + this.editingArea = null; + this.editorObject = null; + }, + + destroy: function(){ + if(!this.isClosed){ this.close(false); } + if(this._updateTimer){ + clearTimeout(this._updateTimer); + } + this.inherited(arguments); + if(RichText._globalSaveHandler){ + delete RichText._globalSaveHandler[this.id]; + } + }, + + _removeMozBogus: function(/* String */ html){ + // summary: + // Post filter to remove unwanted HTML attributes generated by mozilla + // tags: + // private + return html.replace(/\stype="_moz"/gi, '').replace(/\s_moz_dirty=""/gi, '').replace(/_moz_resizing="(true|false)"/gi,''); // String + }, + _removeWebkitBogus: function(/* String */ html){ + // summary: + // Post filter to remove unwanted HTML attributes generated by webkit + // tags: + // private + html = html.replace(/\sclass="webkit-block-placeholder"/gi, ''); + html = html.replace(/\sclass="apple-style-span"/gi, ''); + // For some reason copy/paste sometime adds extra meta tags for charset on + // webkit (chrome) on mac.They need to be removed. See: #12007" + html = html.replace(/<meta charset=\"utf-8\" \/>/gi, ''); + return html; // String + }, + _normalizeFontStyle: function(/* String */ html){ + // summary: + // Convert 'strong' and 'em' to 'b' and 'i'. + // description: + // Moz can not handle strong/em tags correctly, so to help + // mozilla and also to normalize output, convert them to 'b' and 'i'. + // + // Note the IE generates 'strong' and 'em' rather than 'b' and 'i' + // tags: + // private + return html.replace(/<(\/)?strong([ \>])/gi, '<$1b$2') + .replace(/<(\/)?em([ \>])/gi, '<$1i$2' ); // String + }, + + _preFixUrlAttributes: function(/* String */ html){ + // summary: + // Pre-filter to do fixing to href attributes on <a> and <img> tags + // tags: + // private + return html.replace(/(?:(<a(?=\s).*?\shref=)("|')(.*?)\2)|(?:(<a\s.*?href=)([^"'][^ >]+))/gi, + '$1$4$2$3$5$2 _djrealurl=$2$3$5$2') + .replace(/(?:(<img(?=\s).*?\ssrc=)("|')(.*?)\2)|(?:(<img\s.*?src=)([^"'][^ >]+))/gi, + '$1$4$2$3$5$2 _djrealurl=$2$3$5$2'); // String + }, + + /***************************************************************************** + The following functions implement HTML manipulation commands for various + browser/contentEditable implementations. The goal of them is to enforce + standard behaviors of them. + ******************************************************************************/ + + /*** queryCommandEnabled implementations ***/ + + _browserQueryCommandEnabled: function(command){ + // summary: + // Implementation to call to the native queryCommandEnabled of the browser. + // command: + // The command to check. + // tags: + // protected + if(!command) { return false; } + var elem = has("ie") ? this.document.selection.createRange() : this.document; + try{ + return elem.queryCommandEnabled(command); + }catch(e){ + return false; + } + }, + + _createlinkEnabledImpl: function(/*===== argument =====*/){ + // summary: + // This function implements the test for if the create link + // command should be enabled or not. + // argument: + // arguments to the exec command, if any. + // tags: + // protected + var enabled = true; + if(has("opera")){ + var sel = this.window.getSelection(); + if(sel.isCollapsed){ + enabled = true; + }else{ + enabled = this.document.queryCommandEnabled("createlink"); + } + }else{ + enabled = this._browserQueryCommandEnabled("createlink"); + } + return enabled; + }, + + _unlinkEnabledImpl: function(/*===== argument =====*/){ + // summary: + // This function implements the test for if the unlink + // command should be enabled or not. + // argument: + // arguments to the exec command, if any. + // tags: + // protected + var enabled = true; + if(has("mozilla") || has("webkit")){ + enabled = this._sCall("hasAncestorElement", ["a"]); + }else{ + enabled = this._browserQueryCommandEnabled("unlink"); + } + return enabled; + }, + + _inserttableEnabledImpl: function(/*===== argument =====*/){ + // summary: + // This function implements the test for if the inserttable + // command should be enabled or not. + // argument: + // arguments to the exec command, if any. + // tags: + // protected + var enabled = true; + if(has("mozilla") || has("webkit")){ + enabled = true; + }else{ + enabled = this._browserQueryCommandEnabled("inserttable"); + } + return enabled; + }, + + _cutEnabledImpl: function(/*===== argument =====*/){ + // summary: + // This function implements the test for if the cut + // command should be enabled or not. + // argument: + // arguments to the exec command, if any. + // tags: + // protected + var enabled = true; + if(has("webkit")){ + // WebKit deems clipboard activity as a security threat and natively would return false + var sel = this.window.getSelection(); + if(sel){ sel = sel.toString(); } + enabled = !!sel; + }else{ + enabled = this._browserQueryCommandEnabled("cut"); + } + return enabled; + }, + + _copyEnabledImpl: function(/*===== argument =====*/){ + // summary: + // This function implements the test for if the copy + // command should be enabled or not. + // argument: + // arguments to the exec command, if any. + // tags: + // protected + var enabled = true; + if(has("webkit")){ + // WebKit deems clipboard activity as a security threat and natively would return false + var sel = this.window.getSelection(); + if(sel){ sel = sel.toString(); } + enabled = !!sel; + }else{ + enabled = this._browserQueryCommandEnabled("copy"); + } + return enabled; + }, + + _pasteEnabledImpl: function(/*===== argument =====*/){ + // summary:c + // This function implements the test for if the paste + // command should be enabled or not. + // argument: + // arguments to the exec command, if any. + // tags: + // protected + var enabled = true; + if(has("webkit")){ + return true; + }else{ + enabled = this._browserQueryCommandEnabled("paste"); + } + return enabled; + }, + + /*** execCommand implementations ***/ + + _inserthorizontalruleImpl: function(argument){ + // summary: + // This function implements the insertion of HTML 'HR' tags. + // into a point on the page. IE doesn't to it right, so + // we have to use an alternate form + // argument: + // arguments to the exec command, if any. + // tags: + // protected + if(has("ie")){ + return this._inserthtmlImpl("<hr>"); + } + return this.document.execCommand("inserthorizontalrule", false, argument); + }, + + _unlinkImpl: function(argument){ + // summary: + // This function implements the unlink of an 'a' tag. + // argument: + // arguments to the exec command, if any. + // tags: + // protected + if((this.queryCommandEnabled("unlink")) && (has("mozilla") || has("webkit"))){ + var a = this._sCall("getAncestorElement", [ "a" ]); + this._sCall("selectElement", [ a ]); + return this.document.execCommand("unlink", false, null); + } + return this.document.execCommand("unlink", false, argument); + }, + + _hilitecolorImpl: function(argument){ + // summary: + // This function implements the hilitecolor command + // argument: + // arguments to the exec command, if any. + // tags: + // protected + var returnValue; + var isApplied = this._handleTextColorOrProperties("hilitecolor", argument); + if(!isApplied){ + if(has("mozilla")){ + // mozilla doesn't support hilitecolor properly when useCSS is + // set to false (bugzilla #279330) + this.document.execCommand("styleWithCSS", false, true); + console.log("Executing color command."); + returnValue = this.document.execCommand("hilitecolor", false, argument); + this.document.execCommand("styleWithCSS", false, false); + }else{ + returnValue = this.document.execCommand("hilitecolor", false, argument); + } + } + return returnValue; + }, + + _backcolorImpl: function(argument){ + // summary: + // This function implements the backcolor command + // argument: + // arguments to the exec command, if any. + // tags: + // protected + if(has("ie")){ + // Tested under IE 6 XP2, no problem here, comment out + // IE weirdly collapses ranges when we exec these commands, so prevent it + // var tr = this.document.selection.createRange(); + argument = argument ? argument : null; + } + var isApplied = this._handleTextColorOrProperties("backcolor", argument); + if(!isApplied){ + isApplied = this.document.execCommand("backcolor", false, argument); + } + return isApplied; + }, + + _forecolorImpl: function(argument){ + // summary: + // This function implements the forecolor command + // argument: + // arguments to the exec command, if any. + // tags: + // protected + if(has("ie")){ + // Tested under IE 6 XP2, no problem here, comment out + // IE weirdly collapses ranges when we exec these commands, so prevent it + // var tr = this.document.selection.createRange(); + argument = argument? argument : null; + } + var isApplied = false; + isApplied = this._handleTextColorOrProperties("forecolor", argument); + if(!isApplied){ + isApplied = this.document.execCommand("forecolor", false, argument); + } + return isApplied; + }, + + _inserthtmlImpl: function(argument){ + // summary: + // This function implements the insertion of HTML content into + // a point on the page. + // argument: + // The content to insert, if any. + // tags: + // protected + argument = this._preFilterContent(argument); + var rv = true; + if(has("ie")){ + var insertRange = this.document.selection.createRange(); + if(this.document.selection.type.toUpperCase() === 'CONTROL'){ + var n=insertRange.item(0); + while(insertRange.length){ + insertRange.remove(insertRange.item(0)); + } + n.outerHTML=argument; + }else{ + insertRange.pasteHTML(argument); + } + insertRange.select(); + //insertRange.collapse(true); + }else if(has("mozilla") && !argument.length){ + //mozilla can not inserthtml an empty html to delete current selection + //so we delete the selection instead in this case + this._sCall("remove"); // FIXME + }else{ + rv = this.document.execCommand("inserthtml", false, argument); + } + return rv; + }, + + _boldImpl: function(argument){ + // summary: + // This function implements an over-ride of the bold command. + // argument: + // Not used, operates by selection. + // tags: + // protected + var applied = false; + if(has("ie")){ + this._adaptIESelection(); + applied = this._adaptIEFormatAreaAndExec("bold"); + } + if(!applied){ + applied = this.document.execCommand("bold", false, argument); + } + return applied; + }, + + _italicImpl: function(argument){ + // summary: + // This function implements an over-ride of the italic command. + // argument: + // Not used, operates by selection. + // tags: + // protected + var applied = false; + if(has("ie")){ + this._adaptIESelection(); + applied = this._adaptIEFormatAreaAndExec("italic"); + } + if(!applied){ + applied = this.document.execCommand("italic", false, argument); + } + return applied; + }, + + _underlineImpl: function(argument){ + // summary: + // This function implements an over-ride of the underline command. + // argument: + // Not used, operates by selection. + // tags: + // protected + var applied = false; + if(has("ie")){ + this._adaptIESelection(); + applied = this._adaptIEFormatAreaAndExec("underline"); + } + if(!applied){ + applied = this.document.execCommand("underline", false, argument); + } + return applied; + }, + + _strikethroughImpl: function(argument){ + // summary: + // This function implements an over-ride of the strikethrough command. + // argument: + // Not used, operates by selection. + // tags: + // protected + var applied = false; + if(has("ie")){ + this._adaptIESelection(); + applied = this._adaptIEFormatAreaAndExec("strikethrough"); + } + if(!applied){ + applied = this.document.execCommand("strikethrough", false, argument); + } + return applied; + }, + + _superscriptImpl: function(argument){ + // summary: + // This function implements an over-ride of the superscript command. + // argument: + // Not used, operates by selection. + // tags: + // protected + var applied = false; + if(has("ie")){ + this._adaptIESelection(); + applied = this._adaptIEFormatAreaAndExec("superscript"); + } + if(!applied){ + applied = this.document.execCommand("superscript", false, argument); + } + return applied; + }, + + _subscriptImpl: function(argument){ + // summary: + // This function implements an over-ride of the superscript command. + // argument: + // Not used, operates by selection. + // tags: + // protected + var applied = false; + if(has("ie")){ + this._adaptIESelection(); + applied = this._adaptIEFormatAreaAndExec("subscript"); + + } + if(!applied){ + applied = this.document.execCommand("subscript", false, argument); + } + return applied; + }, + + _fontnameImpl: function(argument){ + // summary: + // This function implements the fontname command + // argument: + // arguments to the exec command, if any. + // tags: + // protected + var isApplied; + if(has("ie")){ + isApplied = this._handleTextColorOrProperties("fontname", argument); + } + if(!isApplied){ + isApplied = this.document.execCommand("fontname", false, argument); + } + return isApplied; + }, + + _fontsizeImpl: function(argument){ + // summary: + // This function implements the fontsize command + // argument: + // arguments to the exec command, if any. + // tags: + // protected + var isApplied; + if(has("ie")){ + isApplied = this._handleTextColorOrProperties("fontsize", argument); + } + if(!isApplied){ + isApplied = this.document.execCommand("fontsize", false, argument); + } + return isApplied; + }, + + _insertorderedlistImpl: function(argument){ + // summary: + // This function implements the insertorderedlist command + // argument: + // arguments to the exec command, if any. + // tags: + // protected + var applied = false; + if(has("ie")){ + applied = this._adaptIEList("insertorderedlist", argument); + } + if(!applied){ + applied = this.document.execCommand("insertorderedlist", false, argument); + } + return applied; + }, + + _insertunorderedlistImpl: function(argument){ + // summary: + // This function implements the insertunorderedlist command + // argument: + // arguments to the exec command, if any. + // tags: + // protected + var applied = false; + if(has("ie")){ + applied = this._adaptIEList("insertunorderedlist", argument); + } + if(!applied){ + applied = this.document.execCommand("insertunorderedlist", false, argument); + } + return applied; + }, + + getHeaderHeight: function(){ + // summary: + // A function for obtaining the height of the header node + return this._getNodeChildrenHeight(this.header); // Number + }, + + getFooterHeight: function(){ + // summary: + // A function for obtaining the height of the footer node + return this._getNodeChildrenHeight(this.footer); // Number + }, + + _getNodeChildrenHeight: function(node){ + // summary: + // An internal function for computing the cumulative height of all child nodes of 'node' + // node: + // The node to process the children of; + var h = 0; + if(node && node.childNodes){ + // IE didn't compute it right when position was obtained on the node directly is some cases, + // so we have to walk over all the children manually. + var i; + for(i = 0; i < node.childNodes.length; i++){ + var size = domGeometry.position(node.childNodes[i]); + h += size.h; + } + } + return h; // Number + }, + + _isNodeEmpty: function(node, startOffset){ + // summary: + // Function to test if a node is devoid of real content. + // node: + // The node to check. + // tags: + // private. + if(node.nodeType === 1/*element*/){ + if(node.childNodes.length > 0){ + return this._isNodeEmpty(node.childNodes[0], startOffset); + } + return true; + }else if(node.nodeType === 3/*text*/){ + return (node.nodeValue.substring(startOffset) === ""); + } + return false; + }, + + _removeStartingRangeFromRange: function(node, range){ + // summary: + // Function to adjust selection range by removing the current + // start node. + // node: + // The node to remove from the starting range. + // range: + // The range to adapt. + // tags: + // private + if(node.nextSibling){ + range.setStart(node.nextSibling,0); + }else{ + var parent = node.parentNode; + while(parent && parent.nextSibling == null){ + //move up the tree until we find a parent that has another node, that node will be the next node + parent = parent.parentNode; + } + if(parent){ + range.setStart(parent.nextSibling,0); + } + } + return range; + }, + + _adaptIESelection: function(){ + // summary: + // Function to adapt the IE range by removing leading 'newlines' + // Needed to fix issue with bold/italics/underline not working if + // range included leading 'newlines'. + // In IE, if a user starts a selection at the very end of a line, + // then the native browser commands will fail to execute correctly. + // To work around the issue, we can remove all empty nodes from + // the start of the range selection. + var selection = rangeapi.getSelection(this.window); + if(selection && selection.rangeCount && !selection.isCollapsed){ + var range = selection.getRangeAt(0); + var firstNode = range.startContainer; + var startOffset = range.startOffset; + + while(firstNode.nodeType === 3/*text*/ && startOffset >= firstNode.length && firstNode.nextSibling){ + //traverse the text nodes until we get to the one that is actually highlighted + startOffset = startOffset - firstNode.length; + firstNode = firstNode.nextSibling; + } + + //Remove the starting ranges until the range does not start with an empty node. + var lastNode=null; + while(this._isNodeEmpty(firstNode, startOffset) && firstNode !== lastNode){ + lastNode =firstNode; //this will break the loop in case we can't find the next sibling + range = this._removeStartingRangeFromRange(firstNode, range); //move the start container to the next node in the range + firstNode = range.startContainer; + startOffset = 0; //start at the beginning of the new starting range + } + selection.removeAllRanges();// this will work as long as users cannot select multiple ranges. I have not been able to do that in the editor. + selection.addRange(range); + } + }, + + _adaptIEFormatAreaAndExec: function(command){ + // summary: + // Function to handle IE's quirkiness regarding how it handles + // format commands on a word. This involves a lit of node splitting + // and format cloning. + // command: + // The format command, needed to check if the desired + // command is true or not. + var selection = rangeapi.getSelection(this.window); + var doc = this.document; + var rs, ret, range, txt, startNode, endNode, breaker, sNode; + if(command && selection && selection.isCollapsed){ + var isApplied = this.queryCommandValue(command); + if(isApplied){ + + // We have to split backwards until we hit the format + var nNames = this._tagNamesForCommand(command); + range = selection.getRangeAt(0); + var fs = range.startContainer; + if(fs.nodeType === 3){ + var offset = range.endOffset; + if(fs.length < offset){ + //We are not looking from the right node, try to locate the correct one + ret = this._adjustNodeAndOffset(rs, offset); + fs = ret.node; + offset = ret.offset; + } + } + var topNode; + while(fs && fs !== this.editNode){ + // We have to walk back and see if this is still a format or not. + // Hm, how do I do this? + var tName = fs.tagName? fs.tagName.toLowerCase() : ""; + if(array.indexOf(nNames, tName) > -1){ + topNode = fs; + break; + } + fs = fs.parentNode; + } + + // Okay, we have a stopping place, time to split things apart. + if(topNode){ + // Okay, we know how far we have to split backwards, so we have to split now. + rs = range.startContainer; + var newblock = doc.createElement(topNode.tagName); + domConstruct.place(newblock, topNode, "after"); + if(rs && rs.nodeType === 3){ + // Text node, we have to split it. + var nodeToMove, tNode; + var endOffset = range.endOffset; + if(rs.length < endOffset){ + //We are not splitting the right node, try to locate the correct one + ret = this._adjustNodeAndOffset(rs, endOffset); + rs = ret.node; + endOffset = ret.offset; + } + + txt = rs.nodeValue; + startNode = doc.createTextNode(txt.substring(0, endOffset)); + var endText = txt.substring(endOffset, txt.length); + if(endText){ + endNode = doc.createTextNode(endText); + } + // Place the split, then remove original nodes. + domConstruct.place(startNode, rs, "before"); + if(endNode){ + breaker = doc.createElement("span"); + breaker.className = "ieFormatBreakerSpan"; + domConstruct.place(breaker, rs, "after"); + domConstruct.place(endNode, breaker, "after"); + endNode = breaker; + } + domConstruct.destroy(rs); + + // Okay, we split the text. Now we need to see if we're + // parented to the block element we're splitting and if + // not, we have to split all the way up. Ugh. + var parentC = startNode.parentNode; + var tagList = []; + var tagData; + while(parentC !== topNode){ + var tg = parentC.tagName; + tagData = {tagName: tg}; + tagList.push(tagData); + + var newTg = doc.createElement(tg); + // Clone over any 'style' data. + if(parentC.style){ + if(newTg.style){ + if(parentC.style.cssText){ + newTg.style.cssText = parentC.style.cssText; + tagData.cssText = parentC.style.cssText; + } + } + } + // If font also need to clone over any font data. + if(parentC.tagName === "FONT"){ + if(parentC.color){ + newTg.color = parentC.color; + tagData.color = parentC.color; + } + if(parentC.face){ + newTg.face = parentC.face; + tagData.face = parentC.face; + } + if(parentC.size){ // this check was necessary on IE + newTg.size = parentC.size; + tagData.size = parentC.size; + } + } + if(parentC.className){ + newTg.className = parentC.className; + tagData.className = parentC.className; + } + + // Now move end node and every sibling + // after it over into the new tag. + if(endNode){ + nodeToMove = endNode; + while(nodeToMove){ + tNode = nodeToMove.nextSibling; + newTg.appendChild(nodeToMove); + nodeToMove = tNode; + } + } + if(newTg.tagName == parentC.tagName){ + breaker = doc.createElement("span"); + breaker.className = "ieFormatBreakerSpan"; + domConstruct.place(breaker, parentC, "after"); + domConstruct.place(newTg, breaker, "after"); + }else{ + domConstruct.place(newTg, parentC, "after"); + } + startNode = parentC; + endNode = newTg; + parentC = parentC.parentNode; + } + + // Lastly, move the split out all the split tags + // to the new block as they should now be split properly. + if(endNode){ + nodeToMove = endNode; + if(nodeToMove.nodeType === 1 || (nodeToMove.nodeType === 3 && nodeToMove.nodeValue)){ + // Non-blank text and non-text nodes need to clear out that blank space + // before moving the contents. + newblock.innerHTML = ""; + } + while(nodeToMove){ + tNode = nodeToMove.nextSibling; + newblock.appendChild(nodeToMove); + nodeToMove = tNode; + } + } + + // We had intermediate tags, we have to now recreate them inbetween the split + // and restore what styles, classnames, etc, we can. + if(tagList.length){ + tagData = tagList.pop(); + var newContTag = doc.createElement(tagData.tagName); + if(tagData.cssText && newContTag.style){ + newContTag.style.cssText = tagData.cssText; + } + if(tagData.className){ + newContTag.className = tagData.className; + } + if(tagData.tagName === "FONT"){ + if(tagData.color){ + newContTag.color = tagData.color; + } + if(tagData.face){ + newContTag.face = tagData.face; + } + if(tagData.size){ + newContTag.size = tagData.size; + } + } + domConstruct.place(newContTag, newblock, "before"); + while(tagList.length){ + tagData = tagList.pop(); + var newTgNode = doc.createElement(tagData.tagName); + if(tagData.cssText && newTgNode.style){ + newTgNode.style.cssText = tagData.cssText; + } + if(tagData.className){ + newTgNode.className = tagData.className; + } + if(tagData.tagName === "FONT"){ + if(tagData.color){ + newTgNode.color = tagData.color; + } + if(tagData.face){ + newTgNode.face = tagData.face; + } + if(tagData.size){ + newTgNode.size = tagData.size; + } + } + newContTag.appendChild(newTgNode); + newContTag = newTgNode; + } + + // Okay, everything is theoretically split apart and removed from the content + // so insert the dummy text to select, select it, then + // clear to position cursor. + sNode = doc.createTextNode("."); + breaker.appendChild(sNode); + newContTag.appendChild(sNode); + win.withGlobal(this.window, lang.hitch(this, function(){ + var newrange = rangeapi.create(); + newrange.setStart(sNode, 0); + newrange.setEnd(sNode, sNode.length); + selection.removeAllRanges(); + selection.addRange(newrange); + selectionapi.collapse(false); + sNode.parentNode.innerHTML = ""; + })); + }else{ + // No extra tags, so we have to insert a breaker point and rely + // on filters to remove it later. + breaker = doc.createElement("span"); + breaker.className="ieFormatBreakerSpan"; + sNode = doc.createTextNode("."); + breaker.appendChild(sNode); + domConstruct.place(breaker, newblock, "before"); + win.withGlobal(this.window, lang.hitch(this, function(){ + var newrange = rangeapi.create(); + newrange.setStart(sNode, 0); + newrange.setEnd(sNode, sNode.length); + selection.removeAllRanges(); + selection.addRange(newrange); + selectionapi.collapse(false); + sNode.parentNode.innerHTML = ""; + })); + } + if(!newblock.firstChild){ + // Empty, we don't need it. Split was at end or similar + // So, remove it. + domConstruct.destroy(newblock); + } + return true; + } + } + return false; + }else{ + range = selection.getRangeAt(0); + rs = range.startContainer; + if(rs && rs.nodeType === 3){ + // Text node, we have to split it. + win.withGlobal(this.window, lang.hitch(this, function(){ + var offset = range.startOffset; + if(rs.length < offset){ + //We are not splitting the right node, try to locate the correct one + ret = this._adjustNodeAndOffset(rs, offset); + rs = ret.node; + offset = ret.offset; + } + txt = rs.nodeValue; + startNode = doc.createTextNode(txt.substring(0, offset)); + var endText = txt.substring(offset); + if(endText !== ""){ + endNode = doc.createTextNode(txt.substring(offset)); + } + // Create a space, we'll select and bold it, so + // the whole word doesn't get bolded + breaker = doc.createElement("span"); + sNode = doc.createTextNode("."); + breaker.appendChild(sNode); + if(startNode.length){ + domConstruct.place(startNode, rs, "after"); + }else{ + startNode = rs; + } + domConstruct.place(breaker, startNode, "after"); + if(endNode){ + domConstruct.place(endNode, breaker, "after"); + } + domConstruct.destroy(rs); + var newrange = rangeapi.create(); + newrange.setStart(sNode, 0); + newrange.setEnd(sNode, sNode.length); + selection.removeAllRanges(); + selection.addRange(newrange); + doc.execCommand(command); + domConstruct.place(breaker.firstChild, breaker, "before"); + domConstruct.destroy(breaker); + newrange.setStart(sNode, 0); + newrange.setEnd(sNode, sNode.length); + selection.removeAllRanges(); + selection.addRange(newrange); + selectionapi.collapse(false); + sNode.parentNode.innerHTML = ""; + })); + return true; + } + } + }else{ + return false; + } + }, + + _adaptIEList: function(command /*===== , argument =====*/){ + // summary: + // This function handles normalizing the IE list behavior as + // much as possible. + // command: + // The list command to execute. + // argument: + // Any additional argument. + // tags: + // private + var selection = rangeapi.getSelection(this.window); + if(selection.isCollapsed){ + // In the case of no selection, lets commonize the behavior and + // make sure that it indents if needed. + if(selection.rangeCount && !this.queryCommandValue(command)){ + var range = selection.getRangeAt(0); + var sc = range.startContainer; + if(sc && sc.nodeType == 3){ + // text node. Lets see if there is a node before it that isn't + // some sort of breaker. + if(!range.startOffset){ + // We're at the beginning of a text area. It may have been br split + // Who knows? In any event, we must create the list manually + // or IE may shove too much into the list element. It seems to + // grab content before the text node too if it's br split. + // Why can't IE work like everyone else? + win.withGlobal(this.window, lang.hitch(this, function(){ + // Create a space, we'll select and bold it, so + // the whole word doesn't get bolded + var lType = "ul"; + if(command === "insertorderedlist"){ + lType = "ol"; + } + var list = domConstruct.create(lType); + var li = domConstruct.create("li", null, list); + domConstruct.place(list, sc, "before"); + // Move in the text node as part of the li. + li.appendChild(sc); + // We need a br after it or the enter key handler + // sometimes throws errors. + domConstruct.create("br", null, list, "after"); + // Okay, now lets move our cursor to the beginning. + var newrange = rangeapi.create(); + newrange.setStart(sc, 0); + newrange.setEnd(sc, sc.length); + selection.removeAllRanges(); + selection.addRange(newrange); + selectionapi.collapse(true); + })); + return true; + } + } + } + } + return false; + }, + + _handleTextColorOrProperties: function(command, argument){ + // summary: + // This function handles appplying text color as best it is + // able to do so when the selection is collapsed, making the + // behavior cross-browser consistent. It also handles the name + // and size for IE. + // command: + // The command. + // argument: + // Any additional arguments. + // tags: + // private + var selection = rangeapi.getSelection(this.window); + var doc = this.document; + var rs, ret, range, txt, startNode, endNode, breaker, sNode; + argument = argument || null; + if(command && selection && selection.isCollapsed){ + if(selection.rangeCount){ + range = selection.getRangeAt(0); + rs = range.startContainer; + if(rs && rs.nodeType === 3){ + // Text node, we have to split it. + win.withGlobal(this.window, lang.hitch(this, function(){ + var offset = range.startOffset; + if(rs.length < offset){ + //We are not splitting the right node, try to locate the correct one + ret = this._adjustNodeAndOffset(rs, offset); + rs = ret.node; + offset = ret.offset; + } + txt = rs.nodeValue; + startNode = doc.createTextNode(txt.substring(0, offset)); + var endText = txt.substring(offset); + if(endText !== ""){ + endNode = doc.createTextNode(txt.substring(offset)); + } + // Create a space, we'll select and bold it, so + // the whole word doesn't get bolded + breaker = domConstruct.create("span"); + sNode = doc.createTextNode("."); + breaker.appendChild(sNode); + // Create a junk node to avoid it trying to stlye the breaker. + // This will get destroyed later. + var extraSpan = domConstruct.create("span"); + breaker.appendChild(extraSpan); + if(startNode.length){ + domConstruct.place(startNode, rs, "after"); + }else{ + startNode = rs; + } + domConstruct.place(breaker, startNode, "after"); + if(endNode){ + domConstruct.place(endNode, breaker, "after"); + } + domConstruct.destroy(rs); + var newrange = rangeapi.create(); + newrange.setStart(sNode, 0); + newrange.setEnd(sNode, sNode.length); + selection.removeAllRanges(); + selection.addRange(newrange); + if(has("webkit")){ + // WebKit is frustrating with positioning the cursor. + // It stinks to have a selected space, but there really + // isn't much choice here. + var style = "color"; + if(command === "hilitecolor" || command === "backcolor"){ + style = "backgroundColor"; + } + domStyle.set(breaker, style, argument); + selectionapi.remove(); + domConstruct.destroy(extraSpan); + breaker.innerHTML = " "; // + selectionapi.selectElement(breaker); + this.focus(); + }else{ + this.execCommand(command, argument); + domConstruct.place(breaker.firstChild, breaker, "before"); + domConstruct.destroy(breaker); + newrange.setStart(sNode, 0); + newrange.setEnd(sNode, sNode.length); + selection.removeAllRanges(); + selection.addRange(newrange); + selectionapi.collapse(false); + sNode.parentNode.removeChild(sNode); + } + })); + return true; + } + } + } + return false; + }, + + _adjustNodeAndOffset: function(/*DomNode*/node, /*Int*/offset){ + // summary: + // In the case there are multiple text nodes in a row the offset may not be within the node. + // If the offset is larger than the node length, it will attempt to find + // the next text sibling until it locates the text node in which the offset refers to + // node: + // The node to check. + // offset: + // The position to find within the text node + // tags: + // private. + while(node.length < offset && node.nextSibling && node.nextSibling.nodeType === 3){ + //Adjust the offset and node in the case of multiple text nodes in a row + offset = offset - node.length; + node = node.nextSibling; + } + return {"node": node, "offset": offset}; + }, + + _tagNamesForCommand: function(command){ + // summary: + // Function to return the tab names that are associated + // with a particular style. + // command: String + // The command to return tags for. + // tags: + // private + if(command === "bold"){ + return ["b", "strong"]; + }else if(command === "italic"){ + return ["i","em"]; + }else if(command === "strikethrough"){ + return ["s", "strike"]; + }else if(command === "superscript"){ + return ["sup"]; + }else if(command === "subscript"){ + return ["sub"]; + }else if(command === "underline"){ + return ["u"]; + } + return []; + }, + + _stripBreakerNodes: function(node){ + // summary: + // Function for stripping out the breaker spans inserted by the formatting command. + // Registered as a filter for IE, handles the breaker spans needed to fix up + // How bold/italic/etc, work when selection is collapsed (single cursor). + win.withGlobal(this.window, lang.hitch(this, function(){ + var breakers = query(".ieFormatBreakerSpan", node); + var i; + for(i = 0; i < breakers.length; i++){ + var b = breakers[i]; + while(b.firstChild){ + domConstruct.place(b.firstChild, b, "before"); + } + domConstruct.destroy(b); + } + })); + return node; + } +}); + +return RichText; + +}); diff --git a/js/dojo/dijit/_editor/_Plugin.js b/js/dojo/dijit/_editor/_Plugin.js new file mode 100644 index 0000000..a0af5de --- /dev/null +++ b/js/dojo/dijit/_editor/_Plugin.js @@ -0,0 +1,295 @@ +//>>built +define("dijit/_editor/_Plugin", [ + "dojo/_base/connect", // connect.connect + "dojo/_base/declare", // declare + "dojo/_base/lang", // lang.mixin, lang.hitch + "../form/Button" +], function(connect, declare, lang, Button){ + +// module: +// dijit/_editor/_Plugin +// summary: +// Base class for a "plugin" to the editor, which is usually +// a single button on the Toolbar and some associated code + + +var _Plugin = declare("dijit._editor._Plugin", null, { + // summary: + // Base class for a "plugin" to the editor, which is usually + // a single button on the Toolbar and some associated code + + constructor: function(/*Object?*/args){ + this.params = args || {}; + lang.mixin(this, this.params); + this._connects=[]; + this._attrPairNames = {}; + }, + + // editor: [const] dijit.Editor + // Points to the parent editor + editor: null, + + // iconClassPrefix: [const] String + // The CSS class name for the button node is formed from `iconClassPrefix` and `command` + iconClassPrefix: "dijitEditorIcon", + + // button: dijit._Widget? + // Pointer to `dijit.form.Button` or other widget (ex: `dijit.form.FilteringSelect`) + // that is added to the toolbar to control this plugin. + // If not specified, will be created on initialization according to `buttonClass` + button: null, + + // command: String + // String like "insertUnorderedList", "outdent", "justifyCenter", etc. that represents an editor command. + // Passed to editor.execCommand() if `useDefaultCommand` is true. + command: "", + + // useDefaultCommand: Boolean + // If true, this plugin executes by calling Editor.execCommand() with the argument specified in `command`. + useDefaultCommand: true, + + // buttonClass: Widget Class + // Class of widget (ex: dijit.form.Button or dijit.form.FilteringSelect) + // that is added to the toolbar to control this plugin. + // This is used to instantiate the button, unless `button` itself is specified directly. + buttonClass: Button, + + // disabled: Boolean + // Flag to indicate if this plugin has been disabled and should do nothing + // helps control button state, among other things. Set via the setter api. + disabled: false, + + getLabel: function(/*String*/key){ + // summary: + // Returns the label to use for the button + // tags: + // private + return this.editor.commands[key]; // String + }, + + _initButton: function(){ + // summary: + // Initialize the button or other widget that will control this plugin. + // This code only works for plugins controlling built-in commands in the editor. + // tags: + // protected extension + if(this.command.length){ + var label = this.getLabel(this.command), + editor = this.editor, + className = this.iconClassPrefix+" "+this.iconClassPrefix + this.command.charAt(0).toUpperCase() + this.command.substr(1); + if(!this.button){ + var props = lang.mixin({ + label: label, + dir: editor.dir, + lang: editor.lang, + showLabel: false, + iconClass: className, + dropDown: this.dropDown, + tabIndex: "-1" + }, this.params || {}); + this.button = new this.buttonClass(props); + } + } + if(this.get("disabled") && this.button){ + this.button.set("disabled", this.get("disabled")); + } + }, + + destroy: function(){ + // summary: + // Destroy this plugin + + var h; + while(h = this._connects.pop()){ h.remove(); } + if(this.dropDown){ + this.dropDown.destroyRecursive(); + } + }, + + connect: function(o, f, tf){ + // summary: + // Make a connect.connect() that is automatically disconnected when this plugin is destroyed. + // Similar to `dijit._Widget.connect`. + // tags: + // protected + this._connects.push(connect.connect(o, f, this, tf)); + }, + + updateState: function(){ + // summary: + // Change state of the plugin to respond to events in the editor. + // description: + // This is called on meaningful events in the editor, such as change of selection + // or caret position (but not simple typing of alphanumeric keys). It gives the + // plugin a chance to update the CSS of its button. + // + // For example, the "bold" plugin will highlight/unhighlight the bold button depending on whether the + // characters next to the caret are bold or not. + // + // Only makes sense when `useDefaultCommand` is true, as it calls Editor.queryCommandEnabled(`command`). + var e = this.editor, + c = this.command, + checked, enabled; + if(!e || !e.isLoaded || !c.length){ return; } + var disabled = this.get("disabled"); + if(this.button){ + try{ + enabled = !disabled && e.queryCommandEnabled(c); + if(this.enabled !== enabled){ + this.enabled = enabled; + this.button.set('disabled', !enabled); + } + if(typeof this.button.checked == 'boolean'){ + checked = e.queryCommandState(c); + if(this.checked !== checked){ + this.checked = checked; + this.button.set('checked', e.queryCommandState(c)); + } + } + }catch(e){ + console.log(e); // FIXME: we shouldn't have debug statements in our code. Log as an error? + } + } + }, + + setEditor: function(/*dijit.Editor*/ editor){ + // summary: + // Tell the plugin which Editor it is associated with. + + // TODO: refactor code to just pass editor to constructor. + + // FIXME: detach from previous editor!! + this.editor = editor; + + // FIXME: prevent creating this if we don't need to (i.e., editor can't handle our command) + this._initButton(); + + // Processing for buttons that execute by calling editor.execCommand() + if(this.button && this.useDefaultCommand){ + if(this.editor.queryCommandAvailable(this.command)){ + this.connect(this.button, "onClick", + lang.hitch(this.editor, "execCommand", this.command, this.commandArg) + ); + }else{ + // hide button because editor doesn't support command (due to browser limitations) + this.button.domNode.style.display = "none"; + } + } + + this.connect(this.editor, "onNormalizedDisplayChanged", "updateState"); + }, + + setToolbar: function(/*dijit.Toolbar*/ toolbar){ + // summary: + // Tell the plugin to add it's controller widget (often a button) + // to the toolbar. Does nothing if there is no controller widget. + + // TODO: refactor code to just pass toolbar to constructor. + + if(this.button){ + toolbar.addChild(this.button); + } + // console.debug("adding", this.button, "to:", toolbar); + }, + + set: function(/* attribute */ name, /* anything */ value){ + // summary: + // Set a property on a plugin + // name: + // The property to set. + // value: + // The value to set in the property. + // description: + // Sets named properties on a plugin which may potentially be handled by a + // setter in the plugin. + // For example, if the plugin has a properties "foo" + // and "bar" and a method named "_setFooAttr", calling: + // | plugin.set("foo", "Howdy!"); + // would be equivalent to writing: + // | plugin._setFooAttr("Howdy!"); + // and: + // | plugin.set("bar", 3); + // would be equivalent to writing: + // | plugin.bar = 3; + // + // set() may also be called with a hash of name/value pairs, ex: + // | plugin.set({ + // | foo: "Howdy", + // | bar: 3 + // | }) + // This is equivalent to calling set(foo, "Howdy") and set(bar, 3) + if(typeof name === "object"){ + for(var x in name){ + this.set(x, name[x]); + } + return this; + } + var names = this._getAttrNames(name); + if(this[names.s]){ + // use the explicit setter + var result = this[names.s].apply(this, Array.prototype.slice.call(arguments, 1)); + }else{ + this._set(name, value); + } + return result || this; + }, + + get: function(name){ + // summary: + // Get a property from a plugin. + // name: + // The property to get. + // description: + // Get a named property from a plugin. The property may + // potentially be retrieved via a getter method. If no getter is defined, this + // just retrieves the object's property. + // For example, if the plugin has a properties "foo" + // and "bar" and a method named "_getFooAttr", calling: + // | plugin.get("foo"); + // would be equivalent to writing: + // | plugin._getFooAttr(); + // and: + // | plugin.get("bar"); + // would be equivalent to writing: + // | plugin.bar; + var names = this._getAttrNames(name); + return this[names.g] ? this[names.g]() : this[name]; + }, + + _setDisabledAttr: function(disabled){ + // summary: + // Function to set the plugin state and call updateState to make sure the + // button is updated appropriately. + this.disabled = disabled; + this.updateState(); + }, + + _getAttrNames: function(name){ + // summary: + // Helper function for get() and set(). + // Caches attribute name values so we don't do the string ops every time. + // tags: + // private + + var apn = this._attrPairNames; + if(apn[name]){ return apn[name]; } + var uc = name.charAt(0).toUpperCase() + name.substr(1); + return (apn[name] = { + s: "_set"+uc+"Attr", + g: "_get"+uc+"Attr" + }); + }, + + _set: function(/*String*/ name, /*anything*/ value){ + // summary: + // Helper function to set new value for specified attribute + this[name] = value; + } +}); + +// Hash mapping plugin name to factory, used for registering plugins +_Plugin.registry = {}; + +return _Plugin; + +}); diff --git a/js/dojo/dijit/_editor/html.js b/js/dojo/dijit/_editor/html.js new file mode 100644 index 0000000..2e8d088 --- /dev/null +++ b/js/dojo/dijit/_editor/html.js @@ -0,0 +1,195 @@ +//>>built +define("dijit/_editor/html", [ + "dojo/_base/lang", // lang.isString + "dojo/_base/sniff", // has("ie") + ".." // for exporting symbols to dijit._editor (remove for 2.0) +], function(lang, has, dijit){ + +// module: +// dijit/_editor/html +// summary: +// Utility functions used by editor + +lang.getObject("_editor", true, dijit); + +dijit._editor.escapeXml=function(/*String*/str, /*Boolean?*/noSingleQuotes){ + // summary: + // Adds escape sequences for special characters in XML: &<>"' + // Optionally skips escapes for single quotes + str = str.replace(/&/gm, "&").replace(/</gm, "<").replace(/>/gm, ">").replace(/"/gm, """); + if(!noSingleQuotes){ + str = str.replace(/'/gm, "'"); + } + return str; // string +}; + +dijit._editor.getNodeHtml=function(/* DomNode */node){ + var output; + switch(node.nodeType){ + case 1: //element node + var lName = node.nodeName.toLowerCase(); + if(!lName || lName.charAt(0) == "/"){ + // IE does some strange things with malformed HTML input, like + // treating a close tag </span> without an open tag <span>, as + // a new tag with tagName of /span. Corrupts output HTML, remove + // them. Other browsers don't prefix tags that way, so will + // never show up. + return ""; + } + output = '<' + lName; + + //store the list of attributes and sort it to have the + //attributes appear in the dictionary order + var attrarray = []; + var attr; + if(has("ie") && node.outerHTML){ + var s = node.outerHTML; + s = s.substr(0, s.indexOf('>')) + .replace(/(['"])[^"']*\1/g, ''); //to make the following regexp safe + var reg = /(\b\w+)\s?=/g; + var m, key; + while((m = reg.exec(s))){ + key = m[1]; + if(key.substr(0,3) != '_dj'){ + if(key == 'src' || key == 'href'){ + if(node.getAttribute('_djrealurl')){ + attrarray.push([key,node.getAttribute('_djrealurl')]); + continue; + } + } + var val, match; + switch(key){ + case 'style': + val = node.style.cssText.toLowerCase(); + break; + case 'class': + val = node.className; + break; + case 'width': + if(lName === "img"){ + // This somehow gets lost on IE for IMG tags and the like + // and we have to find it in outerHTML, known IE oddity. + match=/width=(\S+)/i.exec(s); + if(match){ + val = match[1]; + } + break; + } + case 'height': + if(lName === "img"){ + // This somehow gets lost on IE for IMG tags and the like + // and we have to find it in outerHTML, known IE oddity. + match=/height=(\S+)/i.exec(s); + if(match){ + val = match[1]; + } + break; + } + default: + val = node.getAttribute(key); + } + if(val != null){ + attrarray.push([key, val.toString()]); + } + } + } + }else{ + var i = 0; + while((attr = node.attributes[i++])){ + //ignore all attributes starting with _dj which are + //internal temporary attributes used by the editor + var n = attr.name; + if(n.substr(0,3) != '_dj' /*&& + (attr.specified == undefined || attr.specified)*/){ + var v = attr.value; + if(n == 'src' || n == 'href'){ + if(node.getAttribute('_djrealurl')){ + v = node.getAttribute('_djrealurl'); + } + } + attrarray.push([n,v]); + } + } + } + attrarray.sort(function(a,b){ + return a[0] < b[0] ? -1 : (a[0] == b[0] ? 0 : 1); + }); + var j = 0; + while((attr = attrarray[j++])){ + output += ' ' + attr[0] + '="' + + (lang.isString(attr[1]) ? dijit._editor.escapeXml(attr[1], true) : attr[1]) + '"'; + } + if(lName === "script"){ + // Browsers handle script tags differently in how you get content, + // but innerHTML always seems to work, so insert its content that way + // Yes, it's bad to allow script tags in the editor code, but some people + // seem to want to do it, so we need to at least return them right. + // other plugins/filters can strip them. + output += '>' + node.innerHTML +'</' + lName + '>'; + }else{ + if(node.childNodes.length){ + output += '>' + dijit._editor.getChildrenHtml(node)+'</' + lName +'>'; + }else{ + switch(lName){ + case 'br': + case 'hr': + case 'img': + case 'input': + case 'base': + case 'meta': + case 'area': + case 'basefont': + // These should all be singly closed + output += ' />'; + break; + default: + // Assume XML style separate closure for everything else. + output += '></' + lName + '>'; + } + } + } + break; + case 4: // cdata + case 3: // text + // FIXME: + output = dijit._editor.escapeXml(node.nodeValue, true); + break; + case 8: //comment + // FIXME: + output = '<!--' + dijit._editor.escapeXml(node.nodeValue, true) + '-->'; + break; + default: + output = "<!-- Element not recognized - Type: " + node.nodeType + " Name: " + node.nodeName + "-->"; + } + return output; +}; + +dijit._editor.getChildrenHtml = function(/* DomNode */dom){ + // summary: + // Returns the html content of a DomNode and children + var out = ""; + if(!dom){ return out; } + var nodes = dom["childNodes"] || dom; + + //IE issue. + //If we have an actual node we can check parent relationships on for IE, + //We should check, as IE sometimes builds invalid DOMS. If no parent, we can't check + //And should just process it and hope for the best. + var checkParent = !has("ie") || nodes !== dom; + + var node, i = 0; + while((node = nodes[i++])){ + //IE is broken. DOMs are supposed to be a tree. But in the case of malformed HTML, IE generates a graph + //meaning one node ends up with multiple references (multiple parents). This is totally wrong and invalid, but + //such is what it is. We have to keep track and check for this because otherise the source output HTML will have dups. + //No other browser generates a graph. Leave it to IE to break a fundamental DOM rule. So, we check the parent if we can + //If we can't, nothing more we can do other than walk it. + if(!checkParent || node.parentNode == dom){ + out += dijit._editor.getNodeHtml(node); + } + } + return out; // String +}; + +return dijit._editor; +}); diff --git a/js/dojo/dijit/_editor/nls/FontChoice.js b/js/dojo/dijit/_editor/nls/FontChoice.js new file mode 100644 index 0000000..24017f3 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/FontChoice.js @@ -0,0 +1,63 @@ +//>>built +define("dijit/_editor/nls/FontChoice", { root: +//begin v1.x content +({ + fontSize: "Size", + fontName: "Font", + formatBlock: "Format", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "cursive", + fantasy: "fantasy", + + noFormat: "None", + p: "Paragraph", + h1: "Heading", + h2: "Subheading", + h3: "Sub-subheading", + pre: "Pre-formatted", + + 1: "xx-small", + 2: "x-small", + 3: "small", + 4: "medium", + 5: "large", + 6: "x-large", + 7: "xx-large" +}) +//end v1.x content +, +"zh": true, +"zh-tw": true, +"tr": true, +"th": true, +"sv": true, +"sl": true, +"sk": true, +"ru": true, +"ro": true, +"pt": true, +"pt-pt": true, +"pl": true, +"nl": true, +"nb": true, +"ko": true, +"kk": true, +"ja": true, +"it": true, +"hu": true, +"hr": true, +"he": true, +"fr": true, +"fi": true, +"es": true, +"el": true, +"de": true, +"da": true, +"cs": true, +"ca": true, +"az": true, +"ar": true +}); diff --git a/js/dojo/dijit/_editor/nls/LinkDialog.js b/js/dojo/dijit/_editor/nls/LinkDialog.js new file mode 100644 index 0000000..fbef40c --- /dev/null +++ b/js/dojo/dijit/_editor/nls/LinkDialog.js @@ -0,0 +1,49 @@ +//>>built +define("dijit/_editor/nls/LinkDialog", { root: +//begin v1.x content +({ + createLinkTitle: "Link Properties", + insertImageTitle: "Image Properties", + url: "URL:", + text: "Description:", + target: "Target:", + set: "Set", + currentWindow: "Current Window", + parentWindow: "Parent Window", + topWindow: "Topmost Window", + newWindow: "New Window" +}) +//end v1.x content +, +"zh": true, +"zh-tw": true, +"tr": true, +"th": true, +"sv": true, +"sl": true, +"sk": true, +"ru": true, +"ro": true, +"pt": true, +"pt-pt": true, +"pl": true, +"nl": true, +"nb": true, +"ko": true, +"kk": true, +"ja": true, +"it": true, +"hu": true, +"hr": true, +"he": true, +"fr": true, +"fi": true, +"es": true, +"el": true, +"de": true, +"da": true, +"cs": true, +"ca": true, +"az": true, +"ar": true +}); diff --git a/js/dojo/dijit/_editor/nls/ar/FontChoice.js b/js/dojo/dijit/_editor/nls/ar/FontChoice.js new file mode 100644 index 0000000..7e413e7 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ar/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/ar/FontChoice", //begin v1.x content +({ + fontSize: "الحجم", + fontName: "طاقم طباعة", + formatBlock: "النسق", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "أحادي المسافة", + cursive: "كتابة بحروف متصلة", + fantasy: "خيالي", + + noFormat: "لا شيء", + p: "فقرة", + h1: "عنوان", + h2: "عنوان فرعي", + h3: "فرعي-عنوان فرعي", + pre: "منسق بصفة مسبقة", + + 1: "صغير جدا جدا", + 2: "صغير جدا", + 3: "صغير", + 4: "متوسط", + 5: "كبير", + 6: "كبير جدا", + 7: "كبير جدا جدا" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ar/LinkDialog.js b/js/dojo/dijit/_editor/nls/ar/LinkDialog.js new file mode 100644 index 0000000..1bf2c20 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ar/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/ar/LinkDialog", //begin v1.x content +({ + createLinkTitle: "خصائص الوصلة", + insertImageTitle: "خصائص الصورة", + url: "عنوان URL:", + text: "الوصف:", + target: "الهدف:", + set: "تحديد", + currentWindow: "النافذة الحالية", + parentWindow: "النافذة الرئيسية", + topWindow: "النافذة العلوية", + newWindow: "نافذة جديدة" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ar/commands.js b/js/dojo/dijit/_editor/nls/ar/commands.js new file mode 100644 index 0000000..b97ef80 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ar/commands.js @@ -0,0 +1,55 @@ +//>>built +define( +"dijit/_editor/nls/ar/commands", //begin v1.x content +({ + 'bold': 'عري~ض', + 'copy': 'نسخ', + 'cut': 'قص', + 'delete': 'حذف', + 'indent': 'ازاحة للداخل', + 'insertHorizontalRule': 'مسطرة أفقية', + 'insertOrderedList': 'كشف مرقم', + 'insertUnorderedList': 'كشف نقطي', + 'italic': '~مائل', + 'justifyCenter': 'محاذاة في الوسط', + 'justifyFull': 'ضبط', + 'justifyLeft': 'محاذاة الى اليسار', + 'justifyRight': 'محاذاة الى اليمين', + 'outdent': 'ازاحة للخارج', + 'paste': 'لصق', + 'redo': 'اعادة', + 'removeFormat': 'ازالة النسق', + 'selectAll': 'اختيار كل', + 'strikethrough': 'تشطيب', + 'subscript': 'رمز سفلي', + 'superscript': 'رمز علوي', + 'underline': '~تسطير', + 'undo': 'تراجع', + 'unlink': 'ازالة وصلة', + 'createLink': 'تكوين وصلة', + 'toggleDir': 'تبديل الاتجاه', + 'insertImage': 'ادراج صورة', + 'insertTable': 'ادراج/تحرير جدول', + 'toggleTableBorder': 'تبديل حدود الجدول', + 'deleteTable': 'حذف جدول', + 'tableProp': 'خصائص الجدول', + 'htmlToggle': 'مصدر HTML', + 'foreColor': 'لون الواجهة الأمامية', + 'hiliteColor': 'لون الخلفية', + 'plainFormatBlock': 'نمط الفقرة', + 'formatBlock': 'نمط الفقرة', + 'fontSize': 'حجم طاقم الطباعة', + 'fontName': 'اسم طاقم الطباعة', + 'tabIndent': 'ازاحة علامة الجدولة للداخل', + "fullScreen": "تبديل الشاشة الكاملة", + "viewSource": "مشاهدة مصدر HTML", + "print": "طباعة", + "newPage": "صفحة جديدة", + /* Error messages */ + 'systemShortcut': 'يكون التصرف "${0}" متاحا فقط ببرنامج الاستعراض الخاص بك باستخدام المسار المختصر للوحة المفاتيح. استخدم ${1}.', + 'ctrlKey':'ctrl+${0}', + 'appleKey':'\u2318${0}' // "command" or open-apple key on Macintosh +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/az/FontChoice.js b/js/dojo/dijit/_editor/nls/az/FontChoice.js new file mode 100644 index 0000000..5d39e89 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/az/FontChoice.js @@ -0,0 +1,28 @@ +//>>built +define( +"dijit/_editor/nls/az/FontChoice", //begin v1.x content +({ + "1" : "xx-kiçik", + "2" : "x-kiçik", + "formatBlock" : "Format", + "3" : "kiçik", + "4" : "orta", + "5" : "böyük", + "6" : "çox-böyük", + "7" : "ən böyük", + "fantasy" : "fantaziya", + "serif" : "serif", + "p" : "Abzas", + "pre" : "Əvvəldən düzəldilmiş", + "sans-serif" : "sans-serif", + "fontName" : "Şrift", + "h1" : "Başlıq", + "h2" : "Alt Başlıq", + "h3" : "Alt Alt Başlıq", + "monospace" : "Tək aralıqlı", + "fontSize" : "Ölçü", + "cursive" : "Əl yazısı", + "noFormat" : "Heç biri" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/az/LinkDialog.js b/js/dojo/dijit/_editor/nls/az/LinkDialog.js new file mode 100644 index 0000000..d913827 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/az/LinkDialog.js @@ -0,0 +1,17 @@ +//>>built +define( +"dijit/_editor/nls/az/LinkDialog", //begin v1.x content +({ + "text" : "Yazı:", + "insertImageTitle" : "Şəkil başlığı əlavə et", + "set" : "Yönəlt", + "newWindow" : "Yeni pəncərə", + "topWindow" : "Üst pəncərə", + "target" : "Hədəf:", + "createLinkTitle" : "Köprü başlığı yarat", + "parentWindow" : "Ana pəncərə", + "currentWindow" : "Hazırki pəncərə", + "url" : "URL:" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/az/commands.js b/js/dojo/dijit/_editor/nls/az/commands.js new file mode 100644 index 0000000..7c8dcef --- /dev/null +++ b/js/dojo/dijit/_editor/nls/az/commands.js @@ -0,0 +1,53 @@ +//>>built +define( +"dijit/_editor/nls/az/commands", //begin v1.x content +({ + "removeFormat" : "Formatı Sil", + "copy" :"Köçür", + "paste" :"Yapışdır", + "selectAll" :"Hamısını seç", + "insertOrderedList" :"Nömrəli siyahı", + "insertTable" :"Cədvəl əlavə et", + "print" :"Yazdır", + "underline" :"Altıxətli", + "foreColor" :"Ön plan rəngi", + "htmlToggle" :"HTML kodu", + "formatBlock" :"Abzas stili", + "newPage" :"Yeni səhifə", + "insertHorizontalRule" :"Üfüqi qayda", + "delete" :"Sil", + "insertUnorderedList" :"İşarələnmiş siyahı", + "tableProp" :"Cədvəl xüsusiyyətləri", + "insertImage" :"Şəkil əlavə et", + "superscript" :"Üst işarə", + "subscript" :"Alt işarə", + "createLink" :"Körpü yarat", + "undo" :"Geriyə al", + "fullScreen" :"Tam ekran aç", + "italic" :"İtalik", + "fontName" :"Yazı tipi", + "justifyLeft" :"Sol tərəfə Doğrult", + "unlink" :"Körpünü sil", + "toggleTableBorder" :"Cədvəl kənarlarını göstər/Gizlət", + "viewSource" :"HTML qaynaq kodunu göstər", + "fontSize" :"Yazı tipi böyüklüğü", + "systemShortcut" :"\"${0}\" prosesi yalnız printerinizdə klaviatura qısayolu ilə istifadə oluna bilər. Bundan istifadə edin", + "indent" :"Girinti", + "redo" :"Yenilə", + "strikethrough" :"Üstündən xətt çəkilmiş", + "justifyFull" :"Doğrult", + "justifyCenter" :"Ortaya doğrult", + "hiliteColor" :"Arxa plan rəngi", + "deleteTable" :"Cədvəli sil", + "outdent" :"Çıxıntı", + "cut" :"Kəs", + "plainFormatBlock" :"Abzas stili", + "toggleDir" :"İstiqaməti dəyişdir", + "bold" :"Qalın", + "tabIndent" :"Qulp girintisi", + "justifyRight" :"Sağa doğrult", + "appleKey" : "⌘${0}", + "ctrlKey" : "ctrl+${0}" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ca/FontChoice.js b/js/dojo/dijit/_editor/nls/ca/FontChoice.js new file mode 100644 index 0000000..c94133d --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ca/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/ca/FontChoice", //begin v1.x content +({ + fontSize: "Mida", + fontName: "Tipus de lletra", + formatBlock: "Format", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monoespai", + cursive: "Cursiva", + fantasy: "Fantasia", + + noFormat: "Cap", + p: "Paràgraf", + h1: "Títol", + h2: "Subtítol", + h3: "Subsubtítol", + pre: "Format previ", + + 1: "xx-petit", + 2: "x-petit", + 3: "petit", + 4: "mitjà", + 5: "gran", + 6: "x-gran", + 7: "xx-gran" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ca/LinkDialog.js b/js/dojo/dijit/_editor/nls/ca/LinkDialog.js new file mode 100644 index 0000000..eeeb285 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ca/LinkDialog.js @@ -0,0 +1,17 @@ +//>>built +define( +"dijit/_editor/nls/ca/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Propietats de l\'enllaç", + insertImageTitle: "Propietats de la imatge", + url: "URL:", + text: "Descripció:", + target: "Destinació:", + set: "Defineix", + currentWindow: "Finestra actual", + parentWindow: "Finestra pare", + topWindow: "Finestra superior", + newWindow: "Finestra nova" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ca/commands.js b/js/dojo/dijit/_editor/nls/ca/commands.js new file mode 100644 index 0000000..37798d7 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ca/commands.js @@ -0,0 +1,53 @@ +//>>built +define( +"dijit/_editor/nls/ca/commands", //begin v1.x content +({ + 'bold': 'Negreta', + 'copy': 'Copia', + 'cut': 'Retalla', + 'delete': 'Suprimeix', + 'indent': 'Sagnat', + 'insertHorizontalRule': 'Regla horitzontal', + 'insertOrderedList': 'Llista numerada', + 'insertUnorderedList': 'Llista de vinyetes', + 'italic': 'Cursiva', + 'justifyCenter': 'Centra', + 'justifyFull': 'Justifica', + 'justifyLeft': 'Alinea a l\'esquerra', + 'justifyRight': 'Alinea a la dreta', + 'outdent': 'Sagna a l\'esquerra', + 'paste': 'Enganxa', + 'redo': 'Refés', + 'removeFormat': 'Elimina el format', + 'selectAll': 'Selecciona-ho tot', + 'strikethrough': 'Ratllat', + 'subscript': 'Subíndex', + 'superscript': 'Superíndex', + 'underline': 'Subratllat', + 'undo': 'Desfés', + 'unlink': 'Elimina l\'enllaç', + 'createLink': 'Crea un enllaç', + 'toggleDir': 'Inverteix la direcció', + 'insertImage': 'Insereix imatge', + 'insertTable': 'Insereix/edita la taula', + 'toggleTableBorder': 'Inverteix els contorns de taula', + 'deleteTable': 'Suprimeix la taula', + 'tableProp': 'Propietat de taula', + 'htmlToggle': 'Font HTML', + 'foreColor': 'Color de primer pla', + 'hiliteColor': 'Color de fons', + 'plainFormatBlock': 'Estil de paràgraf', + 'formatBlock': 'Estil de paràgraf', + 'fontSize': 'Cos de la lletra', + 'fontName': 'Nom del tipus de lletra', + 'tabIndent': 'Sagnat', + "fullScreen": "Commuta pantalla completa", + "viewSource": "Visualitza font HTML", + "print": "Imprimeix", + "newPage": "Pàgina nova", + /* Error messages */ + 'systemShortcut': 'L\'acció "${0}" és l\'única disponible al navegador utilitzant una drecera del teclat. Utilitzeu ${1}.', + 'ctrlKey':'control+${0}' +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/commands.js b/js/dojo/dijit/_editor/nls/commands.js new file mode 100644 index 0000000..6d273ba --- /dev/null +++ b/js/dojo/dijit/_editor/nls/commands.js @@ -0,0 +1,86 @@ +//>>built +define("dijit/_editor/nls/commands", { root: +//begin v1.x content +({ + 'bold': 'Bold', + 'copy': 'Copy', + 'cut': 'Cut', + 'delete': 'Delete', + 'indent': 'Indent', + 'insertHorizontalRule': 'Horizontal Rule', + 'insertOrderedList': 'Numbered List', + 'insertUnorderedList': 'Bullet List', + 'italic': 'Italic', + 'justifyCenter': 'Align Center', + 'justifyFull': 'Justify', + 'justifyLeft': 'Align Left', + 'justifyRight': 'Align Right', + 'outdent': 'Outdent', + 'paste': 'Paste', + 'redo': 'Redo', + 'removeFormat': 'Remove Format', + 'selectAll': 'Select All', + 'strikethrough': 'Strikethrough', + 'subscript': 'Subscript', + 'superscript': 'Superscript', + 'underline': 'Underline', + 'undo': 'Undo', + 'unlink': 'Remove Link', + 'createLink': 'Create Link', + 'toggleDir': 'Toggle Direction', + 'insertImage': 'Insert Image', + 'insertTable': 'Insert/Edit Table', + 'toggleTableBorder': 'Toggle Table Border', + 'deleteTable': 'Delete Table', + 'tableProp': 'Table Property', + 'htmlToggle': 'HTML Source', + 'foreColor': 'Foreground Color', + 'hiliteColor': 'Background Color', + 'plainFormatBlock': 'Paragraph Style', + 'formatBlock': 'Paragraph Style', + 'fontSize': 'Font Size', + 'fontName': 'Font Name', + 'tabIndent': 'Tab Indent', + "fullScreen": "Toggle Full Screen", + "viewSource": "View HTML Source", + "print": "Print", + "newPage": "New Page", + /* Error messages */ + 'systemShortcut': 'The "${0}" action is only available in your browser using a keyboard shortcut. Use ${1}.', + 'ctrlKey':'ctrl+${0}', + 'appleKey':'\u2318${0}' // "command" or open-apple key on Macintosh +}) +//end v1.x content +, +"zh": true, +"zh-tw": true, +"tr": true, +"th": true, +"sv": true, +"sl": true, +"sk": true, +"ru": true, +"ro": true, +"pt": true, +"pt-pt": true, +"pl": true, +"nl": true, +"nb": true, +"ko": true, +"kk": true, +"ja": true, +"it": true, +"hu": true, +"hr": true, +"he": true, +"fr": true, +"fi": true, +"es": true, +"el": true, +"de": true, +"da": true, +"cs": true, +"ca": true, +"az": true, +"ar": true +}); diff --git a/js/dojo/dijit/_editor/nls/cs/FontChoice.js b/js/dojo/dijit/_editor/nls/cs/FontChoice.js new file mode 100644 index 0000000..b5d47f4 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/cs/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/cs/FontChoice", //begin v1.x content +({ + fontSize: "Velikost", + fontName: "Písmo", + formatBlock: "Formát", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "cursive", + fantasy: "fantasy", + + noFormat: "Žádný", + p: "Odstavec", + h1: "Nadpis", + h2: "Podnadpis", + h3: "Podnadpis 2", + pre: "Předformátované", + + 1: "extra malé", + 2: "velmi malé", + 3: "malé", + 4: "střední", + 5: "velké", + 6: "velmi velké", + 7: "extra velké" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/cs/LinkDialog.js b/js/dojo/dijit/_editor/nls/cs/LinkDialog.js new file mode 100644 index 0000000..08d658a --- /dev/null +++ b/js/dojo/dijit/_editor/nls/cs/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/cs/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Vlastnosti odkazu", + insertImageTitle: "Vlastnosti obrázku", + url: "Adresa URL:", + text: "Popis:", + target: "Cíl:", + set: "Nastavit", + currentWindow: "Aktuální okno", + parentWindow: "Nadřízené okno", + topWindow: "Okno nejvyšší úrovně", + newWindow: "Nové okno" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/cs/commands.js b/js/dojo/dijit/_editor/nls/cs/commands.js new file mode 100644 index 0000000..dbe020e --- /dev/null +++ b/js/dojo/dijit/_editor/nls/cs/commands.js @@ -0,0 +1,52 @@ +//>>built +define( +"dijit/_editor/nls/cs/commands", //begin v1.x content +({ + 'bold': 'Tučné', + 'copy': 'Kopírovat', + 'cut': 'Vyjmout', + 'delete': 'Odstranit', + 'indent': 'Odsadit', + 'insertHorizontalRule': 'Vodorovná čára', + 'insertOrderedList': 'Číslovaný seznam', + 'insertUnorderedList': 'Seznam s odrážkami', + 'italic': 'Kurzíva', + 'justifyCenter': 'Zarovnat na střed', + 'justifyFull': 'Do bloku', + 'justifyLeft': 'Zarovnat vlevo', + 'justifyRight': 'Zarovnat vpravo', + 'outdent': 'Předsadit', + 'paste': 'Vložit', + 'redo': 'Opakovat', + 'removeFormat': 'Odebrat formát', + 'selectAll': 'Vybrat vše', + 'strikethrough': 'Přeškrtnutí', + 'subscript': 'Dolní index', + 'superscript': 'Horní index', + 'underline': 'Podtržení', + 'undo': 'Zpět', + 'unlink': 'Odebrat odkaz', + 'createLink': 'Vytvořit odkaz', + 'toggleDir': 'Přepnout směr', + 'insertImage': 'Vložit obrázek', + 'insertTable': 'Vložit/upravit tabulku', + 'toggleTableBorder': 'Přepnout ohraničení tabulky', + 'deleteTable': 'Odstranit tabulku', + 'tableProp': 'Vlastnost tabulky', + 'htmlToggle': 'Zdroj HTML', + 'foreColor': 'Barva popředí', + 'hiliteColor': 'Barva pozadí', + 'plainFormatBlock': 'Styl odstavce', + 'formatBlock': 'Styl odstavce', + 'fontSize': 'Velikost písma', + 'fontName': 'Název písma', + 'tabIndent': 'Odsazení tabulátoru', + "fullScreen": "Přepnout celou obrazovku", + "viewSource": "Zobrazit zdroj HTML", + "print": "Tisk", + "newPage": "Nová stránka", + /* Error messages */ + 'systemShortcut': 'Akce "${0}" je v prohlížeči dostupná pouze prostřednictvím klávesové zkratky. Použijte klávesovou zkratku ${1}.' +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/da/FontChoice.js b/js/dojo/dijit/_editor/nls/da/FontChoice.js new file mode 100644 index 0000000..0ad073b --- /dev/null +++ b/js/dojo/dijit/_editor/nls/da/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/da/FontChoice", //begin v1.x content +({ + fontSize: "Størrelse", + fontName: "Skrifttype", + formatBlock: "Format", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "kursiv", + fantasy: "fantasy", + + noFormat: "Ingen", + p: "Afsnit", + h1: "Overskrift", + h2: "Underoverskrift", + h3: "Underunderoverskrift", + pre: "Forudformateret", + + 1: "xx-small", + 2: "x-small", + 3: "small", + 4: "medium", + 5: "large", + 6: "x-large", + 7: "xx-large" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/da/LinkDialog.js b/js/dojo/dijit/_editor/nls/da/LinkDialog.js new file mode 100644 index 0000000..d9c14b8 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/da/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/da/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Linkegenskaber", + insertImageTitle: "Billedegenskaber", + url: "URL:", + text: "Beskrivelse:", + target: "Mål:", + set: "Definér", + currentWindow: "Aktuelt vindue", + parentWindow: "Overordnet vindue", + topWindow: "Øverste vindue", + newWindow: "Nyt vindue" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/da/commands.js b/js/dojo/dijit/_editor/nls/da/commands.js new file mode 100644 index 0000000..ff00a52 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/da/commands.js @@ -0,0 +1,52 @@ +//>>built +define( +"dijit/_editor/nls/da/commands", //begin v1.x content +({ + 'bold': 'Fed', + 'copy': 'Kopiér', + 'cut': 'Klip', + 'delete': 'Slet', + 'indent': 'Indrykning', + 'insertHorizontalRule': 'Vandret linje', + 'insertOrderedList': 'Nummereret liste', + 'insertUnorderedList': 'Punktliste', + 'italic': 'Kursiv', + 'justifyCenter': 'Centreret', + 'justifyFull': 'Lige margener', + 'justifyLeft': 'Venstrejusteret', + 'justifyRight': 'Højrejusteret', + 'outdent': 'Udrykning', + 'paste': 'Sæt ind', + 'redo': 'Annullér Fortryd', + 'removeFormat': 'Fjern format', + 'selectAll': 'Markér alle', + 'strikethrough': 'Gennemstreget', + 'subscript': 'Sænket skrift', + 'superscript': 'Hævet skrift', + 'underline': 'Understreget', + 'undo': 'Fortryd', + 'unlink': 'Fjern link', + 'createLink': 'Opret link', + 'toggleDir': 'Skift retning', + 'insertImage': 'Indsæt billede', + 'insertTable': 'Indsæt/redigér tabel', + 'toggleTableBorder': 'Skift tabelramme', + 'deleteTable': 'Slet tabel', + 'tableProp': 'Tabelegenskab', + 'htmlToggle': 'HTML-kilde', + 'foreColor': 'Forgrundsfarve', + 'hiliteColor': 'Baggrundsfarve', + 'plainFormatBlock': 'Afsnitstypografi', + 'formatBlock': 'Afsnitstypografi', + 'fontSize': 'Skriftstørrelse', + 'fontName': 'Skriftnavn', + 'tabIndent': 'Indrykning med tabulator', + "fullScreen": "Aktivér/deaktivér fuldskærm", + "viewSource": "Vis HTML-kilde", + "print": "Udskriv", + "newPage": "Ny side", + /* Error messages */ + 'systemShortcut': 'Funktionen "${0}" kan kun bruges i din browser med en tastaturgenvej. Brug ${1}.' +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/de/FontChoice.js b/js/dojo/dijit/_editor/nls/de/FontChoice.js new file mode 100644 index 0000000..00730c7 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/de/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/de/FontChoice", //begin v1.x content +({ + fontSize: "Größe", + fontName: "Schriftart", + formatBlock: "Format", + + serif: "Serife", + "sans-serif": "Serifenlos", + monospace: "Monospaceschrift", + cursive: "Kursiv", + fantasy: "Fantasie", + + noFormat: "Keine Angabe", + p: "Absatz", + h1: "Überschrift", + h2: "Unterüberschrift", + h3: "Unterunterüberschrift", + pre: "Vorformatiert", + + 1: "XXS", + 2: "XS", + 3: "S", + 4: "M", + 5: "L", + 6: "XL", + 7: "XXL" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/de/LinkDialog.js b/js/dojo/dijit/_editor/nls/de/LinkDialog.js new file mode 100644 index 0000000..ce68a72 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/de/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/de/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Linkeigenschaften", + insertImageTitle: "Grafikeigenschaften", + url: "URL:", + text: "Beschreibung:", + target: "Ziel:", + set: "Festlegen", + currentWindow: "Aktuelles Fenster", + parentWindow: "Übergeordnetes Fenster", + topWindow: "Aktives Fenster", + newWindow: "Neues Fenster" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/de/commands.js b/js/dojo/dijit/_editor/nls/de/commands.js new file mode 100644 index 0000000..385d69b --- /dev/null +++ b/js/dojo/dijit/_editor/nls/de/commands.js @@ -0,0 +1,54 @@ +//>>built +define( +"dijit/_editor/nls/de/commands", //begin v1.x content +({ + 'bold': 'Fett', + 'copy': 'Kopieren', + 'cut': 'Ausschneiden', + 'delete': 'Löschen', + 'indent': 'Einrücken', + 'insertHorizontalRule': 'Horizontaler Strich', + 'insertOrderedList': 'Nummerierung', + 'insertUnorderedList': 'Aufzählungszeichen', + 'italic': 'Kursiv', + 'justifyCenter': 'Zentriert', + 'justifyFull': 'Blocksatz', + 'justifyLeft': 'Linksbündig', + 'justifyRight': 'Rechtsbündig', + 'outdent': 'Ausrücken', + 'paste': 'Einfügen', + 'redo': 'Wiederherstellen', + 'removeFormat': 'Formatierung entfernen', + 'selectAll': 'Alles auswählen', + 'strikethrough': 'Durchgestrichen', + 'subscript': 'Tiefgestellt', + 'superscript': 'Hochgestellt', + 'underline': 'Unterstrichen', + 'undo': 'Rückgängig', + 'unlink': 'Link entfernen', + 'createLink': 'Link erstellen', + 'toggleDir': 'Wechselrichtung', + 'insertImage': 'Grafik einfügen', + 'insertTable': 'Tabelle einfügen/bearbeiten', + 'toggleTableBorder': 'Tabellenumrandung ein-/ausschalten', + 'deleteTable': 'Tabelle löschen', + 'tableProp': 'Tabelleneigenschaft', + 'htmlToggle': 'HTML-Quelltext', + 'foreColor': 'Vordergrundfarbe', + 'hiliteColor': 'Hintergrundfarbe', + 'plainFormatBlock': 'Absatzstil', + 'formatBlock': 'Absatzstil', + 'fontSize': 'Schriftgröße', + 'fontName': 'Schriftartname', + 'tabIndent': 'Tabulatoreinrückung', + "fullScreen": "Gesamtanzeige", + "viewSource": "HTML-Quelle", + "print": "Drucken", + "newPage": "Neue Seite", + /* Error messages */ + 'systemShortcut': 'Die Aktion "${0}" ist nur über einen Direktaufruf in Ihrem Browser verfügbar. Verwenden Sie ${1}.', + 'ctrlKey':'Strg+${0}' +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/el/FontChoice.js b/js/dojo/dijit/_editor/nls/el/FontChoice.js new file mode 100644 index 0000000..8d7c667 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/el/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/el/FontChoice", //begin v1.x content +({ + fontSize: "Μέγεθος", + fontName: "Γραμματοσειρά", + formatBlock: "Μορφή", + + serif: "με πατούρες (serif)", + "sans-serif": "χωρίς πατούρες (sans-serif)", + monospace: "σταθερού πλάτους", + cursive: "πλάγιοι", + fantasy: "φαντασίας", + + noFormat: "Χωρίς", + p: "Παράγραφος", + h1: "Επικεφαλίδα", + h2: "Δευτερεύουσα επικεφαλίδα", + h3: "Δευτερεύουσα επικεφαλίδα τρίτου επιπέδου", + pre: "Προ-μορφοποιημένο", + + 1: "xx-μικρά", + 2: "x-μικρά", + 3: "μικρά", + 4: "μεσαία", + 5: "μεγάλα", + 6: "x-μεγάλα", + 7: "xx-μεγάλα" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/el/LinkDialog.js b/js/dojo/dijit/_editor/nls/el/LinkDialog.js new file mode 100644 index 0000000..cf021ea --- /dev/null +++ b/js/dojo/dijit/_editor/nls/el/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/el/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Ιδιότητες σύνδεσης", + insertImageTitle: "Ιδιότητες εικόνας", + url: "Διεύθυνση URL:", + text: "Περιγραφή:", + target: "Προορισμός:", + set: "Ορισμός", + currentWindow: "Τρέχον παράθυρο", + parentWindow: "Γονικό παράθυρο", + topWindow: "Παράθυρο σε πρώτο πλάνο", + newWindow: "Νέο παράθυρο" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/el/commands.js b/js/dojo/dijit/_editor/nls/el/commands.js new file mode 100644 index 0000000..be7e9b6 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/el/commands.js @@ -0,0 +1,53 @@ +//>>built +define( +"dijit/_editor/nls/el/commands", //begin v1.x content +({ + 'bold': 'Έντονα', + 'copy': 'Αντιγραφή', + 'cut': 'Αποκοπή', + 'delete': 'Διαγραφή', + 'indent': 'Εσοχή', + 'insertHorizontalRule': 'Οριζόντια γραμμή', + 'insertOrderedList': 'Αριθμημένη λίστα', + 'insertUnorderedList': 'Λίστα με κουκίδες', + 'italic': 'Πλάγια', + 'justifyCenter': 'Στοίχιση στο κέντρο', + 'justifyFull': 'Πλήρης στοίχιση', + 'justifyLeft': 'Στοίχιση αριστερά', + 'justifyRight': 'Στοίχιση δεξιά', + 'outdent': 'Μείωση περιθωρίου', + 'paste': 'Επικόλληση', + 'redo': 'Ακύρωση αναίρεσης', + 'removeFormat': 'Αφαίρεση μορφοποίησης', + 'selectAll': 'Επιλογή όλων', + 'strikethrough': 'Διαγράμμιση', + 'subscript': 'Δείκτης', + 'superscript': 'Εκθέτης', + 'underline': 'Υπογράμμιση', + 'undo': 'Αναίρεση', + 'unlink': 'Αφαίρεση σύνδεσης', + 'createLink': 'Δημιουργία σύνδεσης', + 'toggleDir': 'Εναλλαγή κατεύθυνσης', + 'insertImage': 'Εισαγωγή εικόνας', + 'insertTable': 'Εισαγωγή/Τροποποίηση πίνακα', + 'toggleTableBorder': 'Εναλλαγή εμφάνισης περιγράμματος πίνακα', + 'deleteTable': 'Διαγραφή πίνακα', + 'tableProp': 'Ιδιότητα πίνακα', + 'htmlToggle': 'Πρωτογενής κώδικας HTML', + 'foreColor': 'Χρώμα προσκηνίου', + 'hiliteColor': 'Χρώμα φόντου', + 'plainFormatBlock': 'Στυλ παραγράφου', + 'formatBlock': 'Στυλ παραγράφου', + 'fontSize': 'Μέγεθος γραμματοσειράς', + 'fontName': 'Όνομα γραμματοσειράς', + 'tabIndent': 'Εσοχή με το πλήκτρο Tab', + "fullScreen": "Εναλλαγή κατάστασης πλήρους οθόνης", + "viewSource": "Προβολή προέλευσης HTML", + "print": "Εκτύπωση", + "newPage": "Νέα σελίδα", + /* Error messages */ + 'systemShortcut': 'Σε αυτό το πρόγραμμα πλοήγησης, η ενέργεια "${0}" είναι διαθέσιμη μόνο με τη χρήση μιας συντόμευσης πληκτρολογίου. Χρησιμοποιήστε τη συντόμευση ${1}.' +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/es/FontChoice.js b/js/dojo/dijit/_editor/nls/es/FontChoice.js new file mode 100644 index 0000000..d943323 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/es/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/es/FontChoice", //begin v1.x content +({ + fontSize: "Tamaño", + fontName: "Font", + formatBlock: "Formato", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "espacio sencillo", + cursive: "cursiva", + fantasy: "fantasía", + + noFormat: "Ninguno", + p: "Párrafo", + h1: "Cabecera", + h2: "Subcabecera", + h3: "Sub-subcabecera", + pre: "Preformateado", + + 1: "xx-pequeño", + 2: "x-pequeño", + 3: "pequeño", + 4: "medio", + 5: "grande", + 6: "x-grande", + 7: "xx-grande" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/es/LinkDialog.js b/js/dojo/dijit/_editor/nls/es/LinkDialog.js new file mode 100644 index 0000000..0449920 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/es/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/es/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Propiedades del enlace", + insertImageTitle: "Propiedades de la imagen", + url: "URL:", + text: "Descripción:", + target: "Destino:", + set: "Establecer", + currentWindow: "Ventana actual", + parentWindow: "Ventana padre", + topWindow: "Ventana superior", + newWindow: "Nueva ventana" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/es/commands.js b/js/dojo/dijit/_editor/nls/es/commands.js new file mode 100644 index 0000000..661c432 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/es/commands.js @@ -0,0 +1,54 @@ +//>>built +define( +"dijit/_editor/nls/es/commands", //begin v1.x content +({ + 'bold': 'Negrita', + 'copy': 'Copiar', + 'cut': 'Cortar', + 'delete': 'Suprimir', + 'indent': 'Sangría', + 'insertHorizontalRule': 'Regla horizontal', + 'insertOrderedList': 'Lista numerada', + 'insertUnorderedList': 'Lista con viñetas', + 'italic': 'Cursiva', + 'justifyCenter': 'Alinear centro', + 'justifyFull': 'Justificar', + 'justifyLeft': 'Alinear izquierda', + 'justifyRight': 'Alinear derecha', + 'outdent': 'Anular sangría', + 'paste': 'Pegar', + 'redo': 'Rehacer', + 'removeFormat': 'Eliminar formato', + 'selectAll': 'Seleccionar todo', + 'strikethrough': 'Tachado', + 'subscript': 'Subíndice', + 'superscript': 'Superíndice', + 'underline': 'Subrayado', + 'undo': 'Deshacer', + 'unlink': 'Eliminar enlace', + 'createLink': 'Crear enlace', + 'toggleDir': 'Conmutar dirección', + 'insertImage': 'Insertar imagen', + 'insertTable': 'Insertar/Editar tabla', + 'toggleTableBorder': 'Conmutar borde de tabla', + 'deleteTable': 'Suprimir tabla', + 'tableProp': 'Propiedad de tabla', + 'htmlToggle': 'Fuente HTML', + 'foreColor': 'Color de primer plano', + 'hiliteColor': 'Color de segundo plano', + 'plainFormatBlock': 'Estilo de párrafo', + 'formatBlock': 'Estilo de párrafo', + 'fontSize': 'Tamaño de font', + 'fontName': 'Nombre de font', + 'tabIndent': 'Sangría de tabulador', + "fullScreen": "Conmutar pantalla completa", + "viewSource": "Ver fuente HTML", + "print": "Imprimir", + "newPage": "Nueva página", + /* Error messages */ + 'systemShortcut': 'La acción "${0}" sólo está disponible en su navegador mediante un atajo de teclado. Utilice ${1}.', + 'ctrlKey':'control+${0}' +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/fi/FontChoice.js b/js/dojo/dijit/_editor/nls/fi/FontChoice.js new file mode 100644 index 0000000..a69a9ba --- /dev/null +++ b/js/dojo/dijit/_editor/nls/fi/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/fi/FontChoice", //begin v1.x content +({ + fontSize: "Koko", + fontName: "Fontti", + formatBlock: "Muoto", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "cursive", + fantasy: "fantasy", + + noFormat: "Ei mitään", + p: "Kappale", + h1: "Otsikko", + h2: "Alatason otsikko", + h3: "Alimman tason otsikko", + pre: "Esimuotoiltu", + + 1: "xx-small", + 2: "x-small", + 3: "small", + 4: "medium", + 5: "large", + 6: "x-large", + 7: "xx-large" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/fi/LinkDialog.js b/js/dojo/dijit/_editor/nls/fi/LinkDialog.js new file mode 100644 index 0000000..8bab9c9 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/fi/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/fi/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Linkin ominaisuudet", + insertImageTitle: "Kuvan ominaisuudet", + url: "URL-osoite:", + text: "Kuvaus:", + target: "Kohde:", + set: "Aseta", + currentWindow: "Nykyinen ikkuna", + parentWindow: "Pääikkuna", + topWindow: "Päällimmäinen ikkuna", + newWindow: "Uusi ikkuna" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/fi/commands.js b/js/dojo/dijit/_editor/nls/fi/commands.js new file mode 100644 index 0000000..6fabc9b --- /dev/null +++ b/js/dojo/dijit/_editor/nls/fi/commands.js @@ -0,0 +1,53 @@ +//>>built +define( +"dijit/_editor/nls/fi/commands", //begin v1.x content +({ + 'bold': 'Lihavointi', + 'copy': 'Kopioi', + 'cut': 'Leikkaa', + 'delete': 'Poista', + 'indent': 'Sisennä', + 'insertHorizontalRule': 'Vaakasuuntainen viiva', + 'insertOrderedList': 'Numeroitu luettelo', + 'insertUnorderedList': 'Numeroimaton luettelo', + 'italic': 'Kursivointi', + 'justifyCenter': 'Tasaus keskelle', + 'justifyFull': 'Tasaus', + 'justifyLeft': 'Tasaus vasemmalle', + 'justifyRight': 'Tasaus oikealle', + 'outdent': 'Ulonna', + 'paste': 'Liitä', + 'redo': 'Tee uudelleen', + 'removeFormat': 'Poista muotoilu', + 'selectAll': 'Valitse kaikki', + 'strikethrough': 'Yliviivaus', + 'subscript': 'Alaindeksi', + 'superscript': 'Yläindeksi', + 'underline': 'Alleviivaus', + 'undo': 'Kumoa', + 'unlink': 'Poista linkki', + 'createLink': 'Luo linkki', + 'toggleDir': 'Vaihda suuntaa', + 'insertImage': 'Lisää kuva', + 'insertTable': 'Lisää taulukko/muokkaa taulukkoa', + 'toggleTableBorder': 'Ota taulukon kehys käyttöön/poista kehys käytöstä', + 'deleteTable': 'Poista taulukko', + 'tableProp': 'Taulukon ominaisuudet', + 'htmlToggle': 'HTML-lähde', + 'foreColor': 'Edustaväri', + 'hiliteColor': 'Taustaväri', + 'plainFormatBlock': 'Kappaletyyli', + 'formatBlock': 'Kappaletyyli', + 'fontSize': 'Fontin koko', + 'fontName': 'Fontin nimi', + 'tabIndent': 'Sarkainsisennys', + "fullScreen": "Vaihda koko näyttö", + "viewSource": "Näytä HTML-lähde", + "print": "Tulosta", + "newPage": "Uusi sivu", + /* Error messages */ + 'systemShortcut': 'Toiminto "${0}" on käytettävissä selaimessa vain näppäimistön pikatoiminnolla. Käytä seuraavaa: ${1}.' +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/fr/FontChoice.js b/js/dojo/dijit/_editor/nls/fr/FontChoice.js new file mode 100644 index 0000000..0f52049 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/fr/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/fr/FontChoice", //begin v1.x content +({ + fontSize: "Taille", + fontName: "Police", + formatBlock: "Mise en forme", + + serif: "serif", + "sans-serif": "sans serif", + monospace: "espacement fixe", + cursive: "cursive", + fantasy: "fantaisie", + + noFormat: "Néant", + p: "Paragraphe", + h1: "En-tête", + h2: "Sous-en-tête", + h3: "Sous-sous-en-tête", + pre: "Pré-mise en forme", + + 1: "xxs", + 2: "xs", + 3: "s", + 4: "m", + 5: "l", + 6: "xl", + 7: "xxl" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/fr/LinkDialog.js b/js/dojo/dijit/_editor/nls/fr/LinkDialog.js new file mode 100644 index 0000000..73038ac --- /dev/null +++ b/js/dojo/dijit/_editor/nls/fr/LinkDialog.js @@ -0,0 +1,17 @@ +//>>built +define( +"dijit/_editor/nls/fr/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Propriétés du lien", + insertImageTitle: "Propriétés de l'image", + url: "URL :", + text: "Description :", + target: "Cible :", + set: "Définir", + currentWindow: "Fenêtre actuelle", + parentWindow: "Fenêtre parent", + topWindow: "Fenêtre supérieure", + newWindow: "Nouvelle fenêtre" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/fr/commands.js b/js/dojo/dijit/_editor/nls/fr/commands.js new file mode 100644 index 0000000..73f5a18 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/fr/commands.js @@ -0,0 +1,52 @@ +//>>built +define( +"dijit/_editor/nls/fr/commands", //begin v1.x content +({ + 'bold': 'Gras', + 'copy': 'Copier', + 'cut': 'Couper', + 'delete': 'Supprimer', + 'indent': 'Retrait', + 'insertHorizontalRule': 'Règle horizontale', + 'insertOrderedList': 'Liste numérotée', + 'insertUnorderedList': 'Liste à puces', + 'italic': 'Italique', + 'justifyCenter': 'Aligner au centre', + 'justifyFull': 'Justifier', + 'justifyLeft': 'Aligner à gauche', + 'justifyRight': 'Aligner à droite', + 'outdent': 'Retrait négatif', + 'paste': 'Coller', + 'redo': 'Rétablir', + 'removeFormat': 'Supprimer la mise en forme', + 'selectAll': 'Sélectionner tout', + 'strikethrough': 'Barrer', + 'subscript': 'Indice', + 'superscript': 'Exposant', + 'underline': 'Souligner', + 'undo': 'Annuler', + 'unlink': 'Supprimer le lien', + 'createLink': 'Créer un lien', + 'toggleDir': 'Changer de sens', + 'insertImage': 'Insérer une image', + 'insertTable': 'Insérer/Modifier un tableau', + 'toggleTableBorder': 'Afficher/Masquer la bordure du tableau', + 'deleteTable': 'Supprimer le tableau', + 'tableProp': 'Propriété du tableau', + 'htmlToggle': 'Source HTML', + 'foreColor': 'Couleur d\'avant-plan', + 'hiliteColor': 'Couleur d\'arrière-plan', + 'plainFormatBlock': 'Style de paragraphe', + 'formatBlock': 'Style de paragraphe', + 'fontSize': 'Taille de police', + 'fontName': 'Nom de police', + 'tabIndent': 'Retrait de tabulation', + "fullScreen": "Basculer en plein écran", + "viewSource": "Afficher la source HTML", + "print": "Imprimer", + "newPage": "Nouvelle page", + /* Error messages */ + 'systemShortcut': 'L\'action "${0}" est disponible dans votre navigateur uniquement, par le biais d\'un raccourci-clavier. Utilisez ${1}.' +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/he/FontChoice.js b/js/dojo/dijit/_editor/nls/he/FontChoice.js new file mode 100644 index 0000000..4d397d7 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/he/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/he/FontChoice", //begin v1.x content +({ + fontSize: "גודל", + fontName: "גופן", + formatBlock: "עיצוב", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "cursive", + fantasy: "fantasy", + + noFormat: "ללא ", + p: "פיסקה", + h1: "כותרת", + h2: "תת-כותרת", + h3: "תת-תת-כותרת", + pre: "מעוצב מראש", + + 1: "קטן ביות", + 2: "קטן מאוד", + 3: "קטן", + 4: "בינוני", + 5: "גדול", + 6: "גדול מאוד", + 7: "גדול ביותר" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/he/LinkDialog.js b/js/dojo/dijit/_editor/nls/he/LinkDialog.js new file mode 100644 index 0000000..7611a12 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/he/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/he/LinkDialog", //begin v1.x content +({ + createLinkTitle: "תכונות קישור", + insertImageTitle: "תכונות תמונה", + url: "URL:", + text: "תיאור:", + target: "יעד:", + set: "הגדרה", + currentWindow: "חלון נוכחי", + parentWindow: "חלון אב", + topWindow: "חלון עליון", + newWindow: "חלון חדש" +}) +//end v1.x content +); + diff --git a/js/dojo/dijit/_editor/nls/he/commands.js b/js/dojo/dijit/_editor/nls/he/commands.js new file mode 100644 index 0000000..2636554 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/he/commands.js @@ -0,0 +1,54 @@ +//>>built +define( +"dijit/_editor/nls/he/commands", //begin v1.x content +({ + 'bold': 'מודגש', + 'copy': 'עותק', + 'cut': 'גזירה', + 'delete': 'מחיקה', + 'indent': 'הגדלת כניסה', + 'insertHorizontalRule': 'קו אופקי', + 'insertOrderedList': 'רשימה ממוספרת', + 'insertUnorderedList': 'רשימה עם תבליטים', + 'italic': 'נטוי', + 'justifyCenter': 'יישור למרכז', + 'justifyFull': 'יישור דו-צדדי', + 'justifyLeft': 'יישור לשמאל', + 'justifyRight': 'יישור לימין', + 'outdent': 'הקטנת כניסה', + 'paste': 'הדבקה', + 'redo': 'שחזור פעולה', + 'removeFormat': 'סילוק עיצוב', + 'selectAll': 'בחירת הכל', + 'strikethrough': 'קו חוצה', + 'subscript': 'כתב תחתי', + 'superscript': 'כתב עילי', + 'underline': 'קו תחתי', + 'undo': 'ביטול פעולה', + 'unlink': 'סילוק הקישור', + 'createLink': 'יצירת קישור', + 'toggleDir': 'מיתוג כיוון', + 'insertImage': 'הוספת תמונה', + 'insertTable': 'הוספת/עריכת טבלה', + 'toggleTableBorder': 'מיתוג גבול טבלה', + 'deleteTable': 'מחיקת טבלה', + 'tableProp': 'תכונת טבלה', + 'htmlToggle': 'מקור HTML', + 'foreColor': 'צבע חזית', + 'hiliteColor': 'צבע רקע', + 'plainFormatBlock': 'סגנון פיסקה', + 'formatBlock': 'סגנון פיסקה', + 'fontSize': 'גופן יחסי', + 'fontName': 'שם גופן', + 'tabIndent': 'כניסת טאב', + "fullScreen": "מיתוג מסך מלא", + "viewSource": "הצגת מקור HTML", + "print": "הדפסה", + "newPage": "דף חדש", + /* Error messages */ + 'systemShortcut': 'הפעולה "${0}" זמינה בדפדפן רק באמצעות קיצור דרך במקלדת. השתמשו בקיצור ${1}.', + 'ctrlKey':'ctrl+${0}', + 'appleKey':'\u2318${0}' // "command" or open-apple key on Macintosh +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/hr/FontChoice.js b/js/dojo/dijit/_editor/nls/hr/FontChoice.js new file mode 100644 index 0000000..b0697a5 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/hr/FontChoice.js @@ -0,0 +1,26 @@ +//>>built +define( +"dijit/_editor/nls/hr/FontChoice", ({ + fontSize: "Veličina", + fontName: "Font", + formatBlock: "Oblikovanje", + serif: "serif", + "sans-serif": "sans-serif", + monospace: "jednaki razmak", + cursive: "rukopisni", + fantasy: "fantastika", + noFormat: "Nijedan", + p: "Odlomak", + h1: "Naslov", + h2: "Podnaslov", + h3: "Pod-podnaslov", + pre: "Prethodno formatirano", + 1: "vrlo vrlo malo", + 2: "vrlo malo", + 3: "malo", + 4: "srednje", + 5: "veliko", + 6: "vrlo veliko", + 7: "vrlo vrlo veliko" +}) +); diff --git a/js/dojo/dijit/_editor/nls/hr/LinkDialog.js b/js/dojo/dijit/_editor/nls/hr/LinkDialog.js new file mode 100644 index 0000000..6d400a6 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/hr/LinkDialog.js @@ -0,0 +1,15 @@ +//>>built +define( +"dijit/_editor/nls/hr/LinkDialog", ({ + createLinkTitle: "Svojstva veze", + insertImageTitle: "Svojstva slike", + url: "URL:", + text: "Opis:", + target: "Cilj:", + set: "Postavi", + currentWindow: "Aktivni prozor", + parentWindow: "Nadređeni prozor", + topWindow: "Najviši prozor", + newWindow: "Novi prozor" +}) +); diff --git a/js/dojo/dijit/_editor/nls/hr/commands.js b/js/dojo/dijit/_editor/nls/hr/commands.js new file mode 100644 index 0000000..32d8fa4 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/hr/commands.js @@ -0,0 +1,52 @@ +//>>built +define( +"dijit/_editor/nls/hr/commands", ({ + 'bold': 'Podebljaj', + 'copy': 'Kopiraj', + 'cut': 'Izreži', + 'delete': 'Izbriši', + 'indent': 'Uvuci', + 'insertHorizontalRule': 'Vodoravno ravnalo', + 'insertOrderedList': 'Numerirani popis', + 'insertUnorderedList': 'Popis s grafičkim oznakama', + 'italic': 'Kurziv', + 'justifyCenter': 'Centriraj', + 'justifyFull': 'Poravnaj', + 'justifyLeft': 'Poravnaj lijevo', + 'justifyRight': 'Poravnaj desno', + 'outdent': 'Izvuci', + 'paste': 'Zalijepi', + 'redo': 'Ponovno napravi', + 'removeFormat': 'Ukloni oblikovanje', + 'selectAll': 'Izaberi sve', + 'strikethrough': 'Precrtaj', + 'subscript': 'Indeks', + 'superscript': 'Superskript', + 'underline': 'Podcrtaj', + 'undo': 'Poništi', + 'unlink': 'Ukloni vezu', + 'createLink': 'Kreiraj vezu', + 'toggleDir': 'Prebaci smjer', + 'insertImage': 'Umetni sliku', + 'insertTable': 'Umetni/Uredi tablicu', + 'toggleTableBorder': 'Prebaci rub tablice', + 'deleteTable': 'Izbriši tablicu', + 'tableProp': 'Svojstvo tablice', + 'htmlToggle': 'HTML izvor', + 'foreColor': 'Boja prednjeg plana', + 'hiliteColor': 'Boja pozadine', + 'plainFormatBlock': 'Stil odlomka', + 'formatBlock': 'Stil odlomka', + 'fontSize': 'Veličina fonta', + 'fontName': 'Ime fonta', + 'tabIndent': 'Tabulator uvlačenja', + "fullScreen": "Prebaci na potpun ekran", + "viewSource": "Pogledaj HTML izvor", + "print": "Ispis", + "newPage": "Nova stranica", + /* Error messages */ + 'systemShortcut': '"${0}" akcija je dostupna jedino u vašem pregledniku upotrebom prečice tipkovnice. Koristite ${1}.', + 'ctrlKey':'ctrl+${0}', + 'appleKey':'\u2318${0}' // "command" or open-apple key on Macintosh +}) +); diff --git a/js/dojo/dijit/_editor/nls/hu/FontChoice.js b/js/dojo/dijit/_editor/nls/hu/FontChoice.js new file mode 100644 index 0000000..1951dec --- /dev/null +++ b/js/dojo/dijit/_editor/nls/hu/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/hu/FontChoice", //begin v1.x content +({ + fontSize: "Méret", + fontName: "Betűtípus", + formatBlock: "Formátum", + + serif: "talpas", + "sans-serif": "talpatlan", + monospace: "rögzített szélességű", + cursive: "kurzív", + fantasy: "fantázia", + + noFormat: "Nincs", + p: "Bekezdés", + h1: "Címsor", + h2: "Alcím", + h3: "Al-alcím", + pre: "Előformázott", + + 1: "xx-kicsi", + 2: "x-kicsi", + 3: "kicsi", + 4: "közepes", + 5: "nagy", + 6: "x-nagy", + 7: "xx-nagy" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/hu/LinkDialog.js b/js/dojo/dijit/_editor/nls/hu/LinkDialog.js new file mode 100644 index 0000000..8a74653 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/hu/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/hu/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Hivatkozás tulajdonságai", + insertImageTitle: "Kép tulajdonságai", + url: "URL:", + text: "Leírás:", + target: "Cél:", + set: "Beállítás", + currentWindow: "Aktuális ablak", + parentWindow: "Szülő ablak", + topWindow: "Legfelső szintű ablak", + newWindow: "Új ablak" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/hu/commands.js b/js/dojo/dijit/_editor/nls/hu/commands.js new file mode 100644 index 0000000..e833021 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/hu/commands.js @@ -0,0 +1,52 @@ +//>>built +define( +"dijit/_editor/nls/hu/commands", //begin v1.x content +({ + 'bold': 'Félkövér', + 'copy': 'Másolás', + 'cut': 'Kivágás', + 'delete': 'Törlés', + 'indent': 'Behúzás', + 'insertHorizontalRule': 'Vízszintes vonalzó', + 'insertOrderedList': 'Számozott lista', + 'insertUnorderedList': 'Felsorolásjeles lista', + 'italic': 'Dőlt', + 'justifyCenter': 'Középre igazítás', + 'justifyFull': 'Sorkizárás', + 'justifyLeft': 'Balra igazítás', + 'justifyRight': 'Jobbra igazítás', + 'outdent': 'Negatív behúzás', + 'paste': 'Beillesztés', + 'redo': 'Újra', + 'removeFormat': 'Formázás eltávolítása', + 'selectAll': 'Összes kijelölése', + 'strikethrough': 'Áthúzott', + 'subscript': 'Alsó index', + 'superscript': 'Felső index', + 'underline': 'Aláhúzott', + 'undo': 'Visszavonás', + 'unlink': 'Hivatkozás eltávolítása', + 'createLink': 'Hivatkozás létrehozása', + 'toggleDir': 'Irány váltókapcsoló', + 'insertImage': 'Kép beszúrása', + 'insertTable': 'Táblázat beszúrása/szerkesztése', + 'toggleTableBorder': 'Táblázatszegély ki-/bekapcsolása', + 'deleteTable': 'Táblázat törlése', + 'tableProp': 'Táblázat tulajdonságai', + 'htmlToggle': 'HTML forrás', + 'foreColor': 'Előtérszín', + 'hiliteColor': 'Háttérszín', + 'plainFormatBlock': 'Bekezdés stílusa', + 'formatBlock': 'Bekezdés stílusa', + 'fontSize': 'Betűméret', + 'fontName': 'Betűtípus', + 'tabIndent': 'Tab behúzás', + "fullScreen": "Váltás teljes képernyőre", + "viewSource": "HTML forrás megjelenítése", + "print": "Nyomtatás", + "newPage": "Új oldal", + /* Error messages */ + 'systemShortcut': 'A(z) "${0}" művelet a böngészőben csak billentyűparancs használatával érhető el. Használja a következőt: ${1}.' +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/it/FontChoice.js b/js/dojo/dijit/_editor/nls/it/FontChoice.js new file mode 100644 index 0000000..b73dced --- /dev/null +++ b/js/dojo/dijit/_editor/nls/it/FontChoice.js @@ -0,0 +1,32 @@ +//>>built +define( +"dijit/_editor/nls/it/FontChoice", //begin v1.x content +({ + fontSize: "Dimensione", + fontName: "Carattere", + formatBlock: "Formato", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "spaziatura fissa", + cursive: "corsivo", + fantasy: "fantasy", + + noFormat: "Nessuna", + p: "Paragrafo", + h1: "Intestazione", + h2: "Sottointestazione", + h3: "Sottointestazione secondaria", + pre: "Preformattato", + + 1: "xx-small", + 2: "x-small", + 3: "small", + 4: "medium", + 5: "large", + 6: "x-large", + 7: "xx-large" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/it/LinkDialog.js b/js/dojo/dijit/_editor/nls/it/LinkDialog.js new file mode 100644 index 0000000..a2ddf0b --- /dev/null +++ b/js/dojo/dijit/_editor/nls/it/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/it/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Proprietà collegamento", + insertImageTitle: "Proprietà immagine", + url: "URL:", + text: "Descrizione:", + target: "Destinazione:", + set: "Imposta", + currentWindow: "Finestra corrente", + parentWindow: "Finestra parent", + topWindow: "Finestra in primo piano", + newWindow: "Nuova finestra" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/it/commands.js b/js/dojo/dijit/_editor/nls/it/commands.js new file mode 100644 index 0000000..2050c30 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/it/commands.js @@ -0,0 +1,53 @@ +//>>built +define( +"dijit/_editor/nls/it/commands", //begin v1.x content +({ + 'bold': 'Grassetto', + 'copy': 'Copia', + 'cut': 'Taglia', + 'delete': 'Elimina', + 'indent': 'Rientra', + 'insertHorizontalRule': 'Righello orizzontale', + 'insertOrderedList': 'Elenco numerato', + 'insertUnorderedList': 'Elenco puntato', + 'italic': 'Corsivo', + 'justifyCenter': 'Allinea al centro', + 'justifyFull': 'Giustifica', + 'justifyLeft': 'Allinea a sinistra', + 'justifyRight': 'Allinea a destra', + 'outdent': 'Rimuovi rientro', + 'paste': 'Incolla', + 'redo': 'Ripristina', + 'removeFormat': 'Rimuovi formato', + 'selectAll': 'Seleziona tutto', + 'strikethrough': 'Barrato', + 'subscript': 'Pedice', + 'superscript': 'Apice', + 'underline': 'Sottolineato', + 'undo': 'Annulla', + 'unlink': 'Rimuovi collegamento', + 'createLink': 'Crea collegamento', + 'toggleDir': 'Inverti direzione', + 'insertImage': 'Inserisci immagine', + 'insertTable': 'Inserisci/Modifica tabella', + 'toggleTableBorder': 'Mostra/Nascondi margine tabella', + 'deleteTable': 'Elimina tabella', + 'tableProp': 'Proprietà tabella', + 'htmlToggle': 'Origine HTML', + 'foreColor': 'Colore primo piano', + 'hiliteColor': 'Colore sfondo', + 'plainFormatBlock': 'Stile paragrafo', + 'formatBlock': 'Stile paragrafo', + 'fontSize': 'Dimensione carattere', + 'fontName': 'Nome carattere', + 'tabIndent': 'Rientranza tabulazione', + "fullScreen": "Attiva/Disattiva schermo intero", + "viewSource": "Visualizza origine HTML", + "print": "Stampa", + "newPage": "Nuova pagina", + /* Error messages */ + 'systemShortcut': 'Azione "${0}" disponibile sul proprio browser solo mediante i tasti di scelta rapida della tastiera. Utilizzare ${1}.' +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ja/FontChoice.js b/js/dojo/dijit/_editor/nls/ja/FontChoice.js new file mode 100644 index 0000000..9e6c20e --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ja/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/ja/FontChoice", //begin v1.x content +({ + fontSize: "サイズ", + fontName: "フォント", + formatBlock: "フォーマット", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "cursive", + fantasy: "fantasy", + + noFormat: "なし", + p: "段落", + h1: "見出し", + h2: "副見出し", + h3: "副見出しの副見出し", + pre: "事前フォーマット済み", + + 1: "超極小", + 2: "極小", + 3: "小", + 4: "標準", + 5: "大", + 6: "特大", + 7: "超特大" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ja/LinkDialog.js b/js/dojo/dijit/_editor/nls/ja/LinkDialog.js new file mode 100644 index 0000000..51d4457 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ja/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/ja/LinkDialog", //begin v1.x content +({ + createLinkTitle: "リンク・プロパティー", + insertImageTitle: "イメージ・プロパティー", + url: "URL:", + text: "説明:", + target: "ターゲット:", + set: "設定", + currentWindow: "現行ウィンドウ", + parentWindow: "親ウィンドウ", + topWindow: "最上位ウィンドウ", + newWindow: "新規ウィンドウ" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ja/commands.js b/js/dojo/dijit/_editor/nls/ja/commands.js new file mode 100644 index 0000000..b7b4c53 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ja/commands.js @@ -0,0 +1,53 @@ +//>>built +define( +"dijit/_editor/nls/ja/commands", //begin v1.x content +({ + 'bold': '太字', + 'copy': 'コピー', + 'cut': '切り取り', + 'delete': '削除', + 'indent': 'インデント', + 'insertHorizontalRule': '水平罫線', + 'insertOrderedList': '番号付きリスト', + 'insertUnorderedList': '黒丸付きリスト', + 'italic': 'イタリック', + 'justifyCenter': '中央揃え', + 'justifyFull': '両端揃え', + 'justifyLeft': '左揃え', + 'justifyRight': '右揃え', + 'outdent': 'アウトデント', + 'paste': '貼り付け', + 'redo': 'やり直し', + 'removeFormat': '書式のクリア', + 'selectAll': 'すべて選択', + 'strikethrough': '取り消し線', + 'subscript': '下付き文字', + 'superscript': '上付き文字', + 'underline': '下線', + 'undo': '元に戻す', + 'unlink': 'リンクの削除', + 'createLink': 'リンクの作成', + 'toggleDir': '方向の切り替え', + 'insertImage': 'イメージの挿入', + 'insertTable': 'テーブルの挿入/編集', + 'toggleTableBorder': 'テーブル・ボーダーの切り替え', + 'deleteTable': 'テーブルの削除', + 'tableProp': 'テーブル・プロパティー', + 'htmlToggle': 'HTML ソース', + 'foreColor': '前景色', + 'hiliteColor': 'マーカー', + 'plainFormatBlock': '段落スタイル', + 'formatBlock': '段落スタイル', + 'fontSize': 'フォント・サイズ', + 'fontName': 'フォント名', + 'tabIndent': 'タブ・インデント', + "fullScreen": "全画面表示に切り替え", + "viewSource": "HTML ソースの表示", + "print": "印刷", + "newPage": "新規ページ", + /* Error messages */ + 'systemShortcut': '"${0}" アクションを使用できるのは、ブラウザーでキーボード・ショートカットを使用する場合のみです。${1} を使用してください。', + 'ctrlKey':'Ctrl+${0}' +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/kk/FontChoice.js b/js/dojo/dijit/_editor/nls/kk/FontChoice.js new file mode 100644 index 0000000..3418ba8 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/kk/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/kk/FontChoice", //begin v1.x content +({ + fontSize: "Өлшемі", + fontName: "Қаріп", + formatBlock: "Пішім", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "көлбеу", + fantasy: "қиял-ғажайып", + + noFormat: "Ешбір", + p: "Еже", + h1: "Үстіңгі деректеме", + h2: "Ішкі тақырып", + h3: "Ішкі-ішкі тақырып", + pre: "Алдын ала пішімделген", + + 1: "xx-кіші", + 2: "x-кіші", + 3: "кіші", + 4: "орташа", + 5: "үлкен", + 6: "x-үлкен", + 7: "xx-үлкен" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/kk/LinkDialog.js b/js/dojo/dijit/_editor/nls/kk/LinkDialog.js new file mode 100644 index 0000000..afcbe40 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/kk/LinkDialog.js @@ -0,0 +1,17 @@ +//>>built +define( +"dijit/_editor/nls/kk/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Сілтеме сипаттары", + insertImageTitle: "Сурет сипаттары", + url: "URL мекенжайы:", + text: "Сипаттама:", + target: "Мақсат:", + set: "Орнату", + currentWindow: "Ағымдағы терезе", + parentWindow: "Басты терезе", + topWindow: "Ең жоғарғы терезе", + newWindow: "Жаңа терезе" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/kk/commands.js b/js/dojo/dijit/_editor/nls/kk/commands.js new file mode 100644 index 0000000..8fc5d40 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/kk/commands.js @@ -0,0 +1,52 @@ +//>>built +define( +"dijit/_editor/nls/kk/commands", //begin v1.x content +({ + 'bold': 'Қалың', + 'copy': 'Көшіру', + 'cut': 'Қиып алу', + 'delete': 'Жою', + 'indent': 'Шегіндіру', + 'insertHorizontalRule': 'Көлденең сызғыш', + 'insertOrderedList': 'Нөмірленген тізім', + 'insertUnorderedList': 'Таңбалауыш тізім', + 'italic': 'Көлбеу', + 'justifyCenter': 'Ортасы бойынша туралау', + 'justifyFull': 'Туралау', + 'justifyLeft': 'Сол жақ бойынша туралау', + 'justifyRight': 'Оң жақ бойынша туралау', + 'outdent': 'Шығыңқы', + 'paste': 'Қою', + 'redo': 'Қайтару', + 'removeFormat': 'Пішімді алып тастау', + 'selectAll': 'Барлығын таңдау', + 'strikethrough': 'Сызылған', + 'subscript': 'Жоласты', + 'superscript': 'Жолүсті', + 'underline': 'Асты сызылған', + 'undo': 'Болдырмау ', + 'unlink': 'Сілтемені жою', + 'createLink': 'Сілтеме жасау', + 'toggleDir': 'Бағытты қосу', + 'insertImage': 'Сурет кірістіру', + 'insertTable': 'Кестені кірістіру/өңдеу', + 'toggleTableBorder': 'Кесте жиегін қосу', + 'deleteTable': 'Кестені жою', + 'tableProp': 'Кесте сипаты', + 'htmlToggle': 'HTML көзі', + 'foreColor': 'Алды түсі', + 'hiliteColor': 'Өң түсі', + 'plainFormatBlock': 'Еже мәнері', + 'formatBlock': 'Еже мәнері', + 'fontSize': 'Қаріп өлшемі', + 'fontName': 'Қаріп атауы', + 'tabIndent': 'Қойынды шегінісі', + "fullScreen": "Толық экранды қосу", + "viewSource": "HTML көзін қарау", + "print": "Басып шығару", + "newPage": "Жаңа бет", + /* Error messages */ + 'systemShortcut': '"${0}" әрекеті шолғышта тек пернелер тіркесімі арқылы қол жетімді. ${1} пайдаланыңыз.' +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ko/FontChoice.js b/js/dojo/dijit/_editor/nls/ko/FontChoice.js new file mode 100644 index 0000000..6c0d979 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ko/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/ko/FontChoice", //begin v1.x content +({ + fontSize: "크기", + fontName: "글꼴", + formatBlock: "서식", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "cursive", + fantasy: "fantasy", + + noFormat: "없음", + p: "단락", + h1: "제목", + h2: "부제목", + h3: "하위 부제목", + pre: "서식이 지정됨", + + 1: "가장 작게", + 2: "조금 작게", + 3: "작게", + 4: "중간", + 5: "크게", + 6: "조금 크게", + 7: "가장 크게" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ko/LinkDialog.js b/js/dojo/dijit/_editor/nls/ko/LinkDialog.js new file mode 100644 index 0000000..6455638 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ko/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/ko/LinkDialog", //begin v1.x content +({ + createLinkTitle: "링크 등록 정보", + insertImageTitle: "이미지 등록 정보", + url: "URL:", + text: "설명:", + target: "대상", + set: "설정", + currentWindow: "현재 창", + parentWindow: "상위 창", + topWindow: "최상위 창", + newWindow: "새 창" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ko/commands.js b/js/dojo/dijit/_editor/nls/ko/commands.js new file mode 100644 index 0000000..57f008d --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ko/commands.js @@ -0,0 +1,52 @@ +//>>built +define( +"dijit/_editor/nls/ko/commands", //begin v1.x content +({ + 'bold': '굵게', + 'copy': '복사', + 'cut': '잘라내기', + 'delete': '삭제', + 'indent': '들여쓰기', + 'insertHorizontalRule': '수평 자', + 'insertOrderedList': '번호 목록', + 'insertUnorderedList': '글머리표 목록', + 'italic': '기울임꼴', + 'justifyCenter': '가운데 맞춤', + 'justifyFull': '양쪽 맞춤', + 'justifyLeft': '왼쪽 맞춤', + 'justifyRight': '오른쪽 맞춤', + 'outdent': '내어쓰기', + 'paste': '붙여넣기', + 'redo': '다시 실행', + 'removeFormat': '형식 제거', + 'selectAll': '모두 선택', + 'strikethrough': '취소선', + 'subscript': '아래첨자', + 'superscript': '위첨자', + 'underline': '밑줄', + 'undo': '실행 취소', + 'unlink': '링크 제거', + 'createLink': '링크 작성', + 'toggleDir': '방향 토글', + 'insertImage': '이미지 삽입', + 'insertTable': '테이블 삽입/편집', + 'toggleTableBorder': '테이블 외곽선 토글', + 'deleteTable': '테이블 삭제', + 'tableProp': '테이블 특성', + 'htmlToggle': 'HTML 소스', + 'foreColor': '전경색', + 'hiliteColor': '배경색', + 'plainFormatBlock': '단락 양식', + 'formatBlock': '단락 양식', + 'fontSize': '글꼴 크기', + 'fontName': '글꼴 이름', + 'tabIndent': '탭 들여쓰기', + "fullScreen": "전체 화면 토글", + "viewSource": "HTML 소스 보기", + "print": "인쇄", + "newPage": "새 페이지", + /* Error messages */ + 'systemShortcut': '"${0}" 조치는 브라우저에서 키보드 단축키를 통해서만 사용 가능합니다. ${1}을(를) 사용하십시오.' +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/nb/FontChoice.js b/js/dojo/dijit/_editor/nls/nb/FontChoice.js new file mode 100644 index 0000000..f406a2c --- /dev/null +++ b/js/dojo/dijit/_editor/nls/nb/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/nb/FontChoice", //begin v1.x content +({ + fontSize: "Størrelse", + fontName: "Skrift", + formatBlock: "Format", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "kursiv", + fantasy: "fantasi", + + noFormat: "Ingen", + p: "Avsnitt", + h1: "Overskrift", + h2: "Undertittel", + h3: "Under-undertittel", + pre: "Forhåndsformatert", + + 1: "xx-liten", + 2: "x-liten", + 3: "liten", + 4: "middels", + 5: "stor", + 6: "x-stor", + 7: "xx-stor" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/nb/LinkDialog.js b/js/dojo/dijit/_editor/nls/nb/LinkDialog.js new file mode 100644 index 0000000..50b8aa4 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/nb/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/nb/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Koblingsegenskaper", + insertImageTitle: "Bildeegenskaper", + url: "URL:", + text: "Beskrivelse:", + target: "Mål:", + set: "Definer", + currentWindow: "Gjeldende vindu", + parentWindow: "Overordnet vindu", + topWindow: "Øverste vindu", + newWindow: "Nytt vindu" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/nb/commands.js b/js/dojo/dijit/_editor/nls/nb/commands.js new file mode 100644 index 0000000..bc6db32 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/nb/commands.js @@ -0,0 +1,54 @@ +//>>built +define( +"dijit/_editor/nls/nb/commands", //begin v1.x content +({ + 'bold': 'Fet', + 'copy': 'Kopier', + 'cut': 'Klipp ut', + 'delete': 'Slett', + 'indent': 'Innrykk', + 'insertHorizontalRule': 'Vannrett strek', + 'insertOrderedList': 'Nummerert liste', + 'insertUnorderedList': 'Punktliste', + 'italic': 'Kursiv', + 'justifyCenter': 'Midtstill', + 'justifyFull': 'Juster', + 'justifyLeft': 'Venstrejuster', + 'justifyRight': 'Høyrejuster', + 'outdent': 'Fjern innrykk', + 'paste': 'Lim inn', + 'redo': 'Gjør om', + 'removeFormat': 'Fjern format', + 'selectAll': 'Velg alle', + 'strikethrough': 'Gjennomstreking', + 'subscript': 'Senket skrift', + 'superscript': 'Hevet skrift', + 'underline': 'Understreking', + 'undo': 'Angre', + 'unlink': 'Fjern kobling', + 'createLink': 'Opprett kobling', + 'toggleDir': 'Bytt retning', + 'insertImage': 'Sett inn bilde', + 'insertTable': 'Sett inn/rediger tabell', + 'toggleTableBorder': 'Bytt tabellkant', + 'deleteTable': 'Slett tabell', + 'tableProp': 'Tabellegenskap', + 'htmlToggle': 'HTML-kilde', + 'foreColor': 'Forgrunnsfarge', + 'hiliteColor': 'Bakgrunnsfarge', + 'plainFormatBlock': 'Avsnittsstil', + 'formatBlock': 'Avsnittsstil', + 'fontSize': 'Skriftstørrelse', + 'fontName': 'Skriftnavn', + 'tabIndent': 'Tabulatorinnrykk', + "fullScreen": "Slå på/av full skjerm", + "viewSource": "Vis HTML-kilde", + "print": "Skriv ut", + "newPage": "Ny side", + /* Error messages */ + 'systemShortcut': 'Handlingen "${0}" er bare tilgjengelig i nettleseren ved hjelp av en tastatursnarvei. Bruk ${1}.', + 'ctrlKey':'ctrl+${0}', + 'appleKey':'\u2318${0}' // "command" or open-apple key on Macintosh +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/nl/FontChoice.js b/js/dojo/dijit/_editor/nls/nl/FontChoice.js new file mode 100644 index 0000000..137a7b1 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/nl/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/nl/FontChoice", //begin v1.x content +({ + fontSize: "Grootte", + fontName: "Lettertype", + formatBlock: "Opmaak", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "cursief", + fantasy: "fantasy", + + noFormat: "Geen", + p: "Alinea", + h1: "Kop", + h2: "Subkop", + h3: "Sub-subkop", + pre: "Vooraf opgemaakt", + + 1: "xx-klein", + 2: "x-klein", + 3: "klein", + 4: "gemiddeld", + 5: "groot", + 6: "x-groot", + 7: "xx-groot" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/nl/LinkDialog.js b/js/dojo/dijit/_editor/nls/nl/LinkDialog.js new file mode 100644 index 0000000..3dda59e --- /dev/null +++ b/js/dojo/dijit/_editor/nls/nl/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/nl/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Linkeigenschappen", + insertImageTitle: "Afbeeldingseigenschappen", + url: "URL:", + text: "Beschrijving:", + target: "Doel:", + set: "Instellen", + currentWindow: "Huidig venster", + parentWindow: "Hoofdvenster", + topWindow: "Bovenste venster", + newWindow: "Nieuw venster" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/nl/commands.js b/js/dojo/dijit/_editor/nls/nl/commands.js new file mode 100644 index 0000000..e9c7a03 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/nl/commands.js @@ -0,0 +1,52 @@ +//>>built +define( +"dijit/_editor/nls/nl/commands", //begin v1.x content +({ + 'bold': 'Vet', + 'copy': 'Kopiëren', + 'cut': 'Knippen', + 'delete': 'Wissen', + 'indent': 'Inspringen', + 'insertHorizontalRule': 'Horizontale liniaal', + 'insertOrderedList': 'Genummerde lijst', + 'insertUnorderedList': 'Lijst met opsommingstekens', + 'italic': 'Cursief', + 'justifyCenter': 'Centreren', + 'justifyFull': 'Uitvullen', + 'justifyLeft': 'Links uitlijnen', + 'justifyRight': 'Rechts uitlijnen', + 'outdent': 'Uitspringen', + 'paste': 'Plakken', + 'redo': 'Opnieuw', + 'removeFormat': 'Opmaak verwijderen', + 'selectAll': 'Alles selecteren', + 'strikethrough': 'Doorhalen', + 'subscript': 'Subscript', + 'superscript': 'Superscript', + 'underline': 'Onderstrepen', + 'undo': 'Ongedaan maken', + 'unlink': 'Link verwijderen', + 'createLink': 'Link maken', + 'toggleDir': 'Schrijfrichting wijzigen', + 'insertImage': 'Afbeelding invoegen', + 'insertTable': 'Tabel invoegen/bewerken', + 'toggleTableBorder': 'Tabelkader wijzigen', + 'deleteTable': 'Tabel wissen', + 'tableProp': 'Tabeleigenschap', + 'htmlToggle': 'HTML-bron', + 'foreColor': 'Voorgrondkleur', + 'hiliteColor': 'Achtergrondkleur', + 'plainFormatBlock': 'Alineastijl', + 'formatBlock': 'Alineastijl', + 'fontSize': 'Lettergrootte', + 'fontName': 'Lettertype', + 'tabIndent': 'Inspringen', + "fullScreen": "Volledig scherm in-/uitschakelen", + "viewSource": "HTML-bron bekijken", + "print": "Afdrukken", + "newPage": "Nieuwe pagina", + /* Error messages */ + 'systemShortcut': 'De actie "${0}" is alleen beschikbaar in uw browser via een sneltoetscombinatie. Gebruik ${1}.' +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/pl/FontChoice.js b/js/dojo/dijit/_editor/nls/pl/FontChoice.js new file mode 100644 index 0000000..bd49898 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/pl/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/pl/FontChoice", //begin v1.x content +({ + fontSize: "Wielkość", + fontName: "Czcionka", + formatBlock: "Format", + + serif: "szeryfowa", + "sans-serif": "bezszeryfowa", + monospace: "czcionka o stałej szerokości", + cursive: "kursywa", + fantasy: "fantazyjna", + + noFormat: "Brak", + p: "Akapit", + h1: "Nagłówek", + h2: "Nagłówek 2-go poziomu", + h3: "Nagłówek 3-go poziomu", + pre: "Wstępnie sformatowane", + + 1: "najmniejsza", + 2: "mniejsza", + 3: "mała", + 4: "średnia", + 5: "duża", + 6: "większa", + 7: "największa" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/pl/LinkDialog.js b/js/dojo/dijit/_editor/nls/pl/LinkDialog.js new file mode 100644 index 0000000..f4ec0be --- /dev/null +++ b/js/dojo/dijit/_editor/nls/pl/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/pl/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Właściwości odsyłacza", + insertImageTitle: "Właściwości obrazu", + url: "Adres URL:", + text: "Opis:", + target: "Cel:", + set: "Ustaw", + currentWindow: "Bieżące okno", + parentWindow: "Okno macierzyste", + topWindow: "Okno najwyższego poziomu", + newWindow: "Nowe okno" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/pl/commands.js b/js/dojo/dijit/_editor/nls/pl/commands.js new file mode 100644 index 0000000..079dcf6 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/pl/commands.js @@ -0,0 +1,54 @@ +//>>built +define( +"dijit/_editor/nls/pl/commands", //begin v1.x content +({ + 'bold': 'Pogrubienie', + 'copy': 'Kopiuj', + 'cut': 'Wytnij', + 'delete': 'Usuń', + 'indent': 'Wcięcie', + 'insertHorizontalRule': 'Linia pozioma', + 'insertOrderedList': 'Lista numerowana', + 'insertUnorderedList': 'Lista wypunktowana', + 'italic': 'Kursywa', + 'justifyCenter': 'Wyrównaj do środka', + 'justifyFull': 'Wyrównaj do lewej i prawej', + 'justifyLeft': 'Wyrównaj do lewej', + 'justifyRight': 'Wyrównaj do prawej', + 'outdent': 'Usuń wcięcie', + 'paste': 'Wklej', + 'redo': 'Ponów', + 'removeFormat': 'Usuń formatowanie', + 'selectAll': 'Wybierz wszystko', + 'strikethrough': 'Przekreślenie', + 'subscript': 'Indeks dolny', + 'superscript': 'Indeks górny', + 'underline': 'Podkreślenie', + 'undo': 'Cofnij', + 'unlink': 'Usuń odsyłacz', + 'createLink': 'Utwórz odsyłacz', + 'toggleDir': 'Przełącz kierunek', + 'insertImage': 'Wstaw obraz', + 'insertTable': 'Wstaw/edytuj tabelę', + 'toggleTableBorder': 'Przełącz ramkę tabeli', + 'deleteTable': 'Usuń tabelę', + 'tableProp': 'Właściwość tabeli', + 'htmlToggle': 'Kod źródłowy HTML', + 'foreColor': 'Kolor pierwszego planu', + 'hiliteColor': 'Kolor tła', + 'plainFormatBlock': 'Styl akapitu', + 'formatBlock': 'Styl akapitu', + 'fontSize': 'Wielkość czcionki', + 'fontName': 'Nazwa czcionki', + 'tabIndent': 'Wcięcie o tabulator', + "fullScreen": "Przełącz pełny ekran", + "viewSource": "Wyświetl kod źródłowy HTML", + "print": "Drukuj", + "newPage": "Nowa strona", + /* Error messages */ + 'systemShortcut': 'Działanie ${0} jest dostępne w tej przeglądarce wyłącznie przy użyciu skrótu klawiaturowego. Należy użyć klawiszy ${1}.', + 'ctrlKey':'Ctrl+${0}' +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/pt-pt/FontChoice.js b/js/dojo/dijit/_editor/nls/pt-pt/FontChoice.js new file mode 100644 index 0000000..836d72d --- /dev/null +++ b/js/dojo/dijit/_editor/nls/pt-pt/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/pt-pt/FontChoice", //begin v1.x content +({ + fontSize: "Tamanho", + fontName: "Tipo de letra", + formatBlock: "Formato", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "cursive", + fantasy: "fantasy", + + noFormat: "Nenhum", + p: "Parágrafo", + h1: "Título", + h2: "Sub-título", + h3: "Sub-subtítulo", + pre: "Pré-formatado", + + 1: "xxs", + 2: "xs", + 3: "small", + 4: "medium", + 5: "large", + 6: "xl", + 7: "xxl" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/pt-pt/LinkDialog.js b/js/dojo/dijit/_editor/nls/pt-pt/LinkDialog.js new file mode 100644 index 0000000..4a09e7a --- /dev/null +++ b/js/dojo/dijit/_editor/nls/pt-pt/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/pt-pt/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Propriedades da ligação", + insertImageTitle: "Propriedades da imagem", + url: "URL:", + text: "Descrição:", + target: "Destino:", + set: "Definir", + currentWindow: "Janela actual", + parentWindow: "Janela ascendente", + topWindow: "Janela superior", + newWindow: "Nova janela" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/pt-pt/commands.js b/js/dojo/dijit/_editor/nls/pt-pt/commands.js new file mode 100644 index 0000000..03e64fe --- /dev/null +++ b/js/dojo/dijit/_editor/nls/pt-pt/commands.js @@ -0,0 +1,53 @@ +//>>built +define( +"dijit/_editor/nls/pt-pt/commands", //begin v1.x content +({ + 'bold': 'Negrito', + 'copy': 'Copiar', + 'cut': 'Cortar', + 'delete': 'Eliminar', + 'indent': 'Indentar', + 'insertHorizontalRule': 'Régua horizontal', + 'insertOrderedList': 'Lista numerada', + 'insertUnorderedList': 'Lista marcada', + 'italic': 'Itálico', + 'justifyCenter': 'Alinhar ao centro', + 'justifyFull': 'Justificar', + 'justifyLeft': 'Alinhar à esquerda', + 'justifyRight': 'Alinhar à direita', + 'outdent': 'Recuar', + 'paste': 'Colar', + 'redo': 'Repetir', + 'removeFormat': 'Remover formato', + 'selectAll': 'Seleccionar tudo', + 'strikethrough': 'Rasurado', + 'subscript': 'Inferior à linha', + 'superscript': 'Superior à linha', + 'underline': 'Sublinhado', + 'undo': 'Anular', + 'unlink': 'Remover ligação', + 'createLink': 'Criar ligação', + 'toggleDir': 'Alternar direcção', + 'insertImage': 'Inserir imagem', + 'insertTable': 'Inserir/Editar tabela', + 'toggleTableBorder': 'Alternar contorno da tabela', + 'deleteTable': 'Eliminar tabela', + 'tableProp': 'Propriedades da tabela', + 'htmlToggle': 'Código-fonte de HTML', + 'foreColor': 'Cor de primeiro plano', + 'hiliteColor': 'Cor de segundo plano', + 'plainFormatBlock': 'Estilo de parágrafo', + 'formatBlock': 'Estilo de parágrafo', + 'fontSize': 'Tamanho do tipo de letra', + 'fontName': 'Nome do tipo de letra', + 'tabIndent': 'Indentar com a tecla Tab', + "fullScreen": "Alternar ecrã completo", + "viewSource": "Ver origem HTML", + "print": "Imprimir", + "newPage": "Nova página", + /* Error messages */ + 'systemShortcut': 'A acção "${0}" apenas está disponível no navegador utilizando um atalho de teclado. Utilize ${1}.' +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/pt/FontChoice.js b/js/dojo/dijit/_editor/nls/pt/FontChoice.js new file mode 100644 index 0000000..e8684fe --- /dev/null +++ b/js/dojo/dijit/_editor/nls/pt/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/pt/FontChoice", //begin v1.x content +({ + fontSize: "Tamanho", + fontName: "Fonte", + formatBlock: "Formatar", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "espaço simples", + cursive: "cursiva", + fantasy: "fantasy", + + noFormat: "Nenhuma", + p: "Parágrafo", + h1: "Título", + h2: "Subtítulo", + h3: "Sub-subtítulo", + pre: "Pré-formatado", + + 1: "extra-extra-pequeno", + 2: "extra-pequeno", + 3: "pequena", + 4: "médio", + 5: "grande", + 6: "extra-grande", + 7: "extra-extra-grande" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/pt/LinkDialog.js b/js/dojo/dijit/_editor/nls/pt/LinkDialog.js new file mode 100644 index 0000000..2a855ff --- /dev/null +++ b/js/dojo/dijit/_editor/nls/pt/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/pt/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Propriedades de Link", + insertImageTitle: "Propriedades de Imagem", + url: "URL:", + text: "Descrição:", + target: "Destino:", + set: "Definir", + currentWindow: "Janela Atual", + parentWindow: "Janela Pai", + topWindow: "Primeira Janela", + newWindow: "Nova Janela" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/pt/commands.js b/js/dojo/dijit/_editor/nls/pt/commands.js new file mode 100644 index 0000000..4772dc4 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/pt/commands.js @@ -0,0 +1,52 @@ +//>>built +define( +"dijit/_editor/nls/pt/commands", //begin v1.x content +({ + 'bold': 'Negrito', + 'copy': 'Copiar', + 'cut': 'Recortar', + 'delete': 'Excluir', + 'indent': 'Recuar', + 'insertHorizontalRule': 'Régua Horizontal', + 'insertOrderedList': 'Lista Numerada', + 'insertUnorderedList': 'Lista com Marcadores', + 'italic': 'Itálico', + 'justifyCenter': 'Alinhar pelo Centro', + 'justifyFull': 'Justificar', + 'justifyLeft': 'Alinhar à Esquerda', + 'justifyRight': 'Alinhar à Direita', + 'outdent': 'Não chanfrado', + 'paste': 'Colar', + 'redo': 'Refazer', + 'removeFormat': 'Remover Formato', + 'selectAll': 'Selecionar Todos', + 'strikethrough': 'Tachado', + 'subscript': 'Subscrito', + 'superscript': 'Sobrescrito', + 'underline': 'Sublinhado', + 'undo': 'Desfazer', + 'unlink': 'Remover Link', + 'createLink': 'Criar Link', + 'toggleDir': 'Comutar Direção', + 'insertImage': 'Inserir Imagem', + 'insertTable': 'Inserir/Editar Tabela', + 'toggleTableBorder': 'Alternar Moldura da Tabela', + 'deleteTable': 'Excluir Tabela', + 'tableProp': 'Propriedade da Tabela', + 'htmlToggle': 'Origem HTML', + 'foreColor': 'Cor do Primeiro Plano', + 'hiliteColor': 'Cor do Segundo Plano', + 'plainFormatBlock': 'Estilo de Parágrafo', + 'formatBlock': 'Estilo de Parágrafo', + 'fontSize': 'Tamanho da Fonte', + 'fontName': 'Nome da Fonte', + 'tabIndent': 'Recuo de Guia', + "fullScreen": "Comutar Tela Cheia", + "viewSource": "Visualizar Origem HTML", + "print": "Imprimir", + "newPage": "Nova Página", + /* Error messages */ + 'systemShortcut': 'A ação "${0}" está disponível em seu navegador apenas usando um atalho de teclado. Use ${1}.' +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ro/FontChoice.js b/js/dojo/dijit/_editor/nls/ro/FontChoice.js new file mode 100644 index 0000000..3f21bdf --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ro/FontChoice.js @@ -0,0 +1,32 @@ +//>>built +define( +"dijit/_editor/nls/ro/FontChoice", //begin v1.x content +({ + fontSize: "Dimensiune", + fontName: "Font", + formatBlock: "Format", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "cursive", + fantasy: "fantasy", + + noFormat: "Fără", + p: "Paragraf", + h1: "Titlu", + h2: "Subtitlu", + h3: "Sub-subtitlu", + pre: "Preformatat", + + 1: "xxs (xx-small)", + 2: "xs (x-small)", + 3: "s (small)", + 4: "m (medium)", + 5: "l (large)", + 6: "xl (x-large)", + 7: "xxl (xx-large)" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ro/LinkDialog.js b/js/dojo/dijit/_editor/nls/ro/LinkDialog.js new file mode 100644 index 0000000..506311e --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ro/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/ro/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Proprietăţi legătură", + insertImageTitle: "Proprietăţi imagine", + url: "URL:", + text: "Descriere:", + target: "Destinaţie:", + set: "Setare", + currentWindow: "Fereastra curentă", + parentWindow: "Fereastra părinte", + topWindow: "Fereastra cea mai de sus", + newWindow: "Fereastra nouă" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ro/commands.js b/js/dojo/dijit/_editor/nls/ro/commands.js new file mode 100644 index 0000000..6e63611 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ro/commands.js @@ -0,0 +1,52 @@ +//>>built +define( +"dijit/_editor/nls/ro/commands", //begin v1.x content +({ + 'bold': 'Aldin', + 'copy': 'Copiere', + 'cut': 'Tăiere', + 'delete': 'Ştergere', + 'indent': 'Micşorare indent', + 'insertHorizontalRule': 'Linie delimitatoare', + 'insertOrderedList': 'Listă numerotată', + 'insertUnorderedList': 'Listă cu marcator', + 'italic': 'Cursiv', + 'justifyCenter': 'Aliniere centru', + 'justifyFull': 'Aliniere stânga-dreapta', + 'justifyLeft': 'Aliniere stânga', + 'justifyRight': 'Aliniere dreapta', + 'outdent': 'Mărire indent', + 'paste': 'Lipire', + 'redo': 'Refacere acţiune', + 'removeFormat': 'Înlăturare format', + 'selectAll': 'Selectează tot', + 'strikethrough': 'Tăiere text cu o linie', + 'subscript': 'Scriere indice inferior', + 'superscript': 'Scriere indice superior', + 'underline': 'Subliniere', + 'undo': 'Anulare acţiune', + 'unlink': 'Înlăturare legătură', + 'createLink': 'Creare legătură', + 'toggleDir': 'Comutare direcţie', + 'insertImage': 'Inserare imagine', + 'insertTable': 'Inserare/Editare tabelă', + 'toggleTableBorder': 'Comutare bordură tabelă', + 'deleteTable': 'Ştergere tabelă', + 'tableProp': 'Proprietate tabelă', + 'htmlToggle': 'Sursă HTML', + 'foreColor': 'Culoare de prim-plan', + 'hiliteColor': 'Culoare de fundal', + 'plainFormatBlock': 'Stil paragraf', + 'formatBlock': 'Stil paragraf', + 'fontSize': 'Dimensiune font', + 'fontName': 'Nume font', + 'tabIndent': 'Indentare Tab', + "fullScreen": "Comutare ecran complet", + "viewSource": "Vizualizara sursă HTML", + "print": "Tipărire", + "newPage": "Pagină nouă", + /* Error messages */ + 'systemShortcut': 'Acţiunea "${0}" este disponibilă în browser doar utilizând o comandă rapidă de la tastatură. Utilizaţi ${1}.' +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ru/FontChoice.js b/js/dojo/dijit/_editor/nls/ru/FontChoice.js new file mode 100644 index 0000000..f5b8387 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ru/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/ru/FontChoice", //begin v1.x content +({ + fontSize: "Размер", + fontName: "Шрифт", + formatBlock: "Формат", + + serif: "с засечками", + "sans-serif": "без засечек", + monospace: "непропорциональный", + cursive: "курсив", + fantasy: "артистический", + + noFormat: "Нет", + p: "Абзац", + h1: "Заголовок", + h2: "Подзаголовок", + h3: "Вложенный подзаголовок", + pre: "Заранее отформатированный", + + 1: "самый маленький", + 2: "очень маленький", + 3: "маленький", + 4: "средний", + 5: "большой", + 6: "очень большой", + 7: "самый большой" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ru/LinkDialog.js b/js/dojo/dijit/_editor/nls/ru/LinkDialog.js new file mode 100644 index 0000000..e552630 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ru/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/ru/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Свойства ссылки", + insertImageTitle: "Свойства изображения", + url: "URL:", + text: "Описание:", + target: "Целевой объект:", + set: "Задать", + currentWindow: "Текущее окно", + parentWindow: "Родительское окно", + topWindow: "Верхнее окно", + newWindow: "Новое окно" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/ru/commands.js b/js/dojo/dijit/_editor/nls/ru/commands.js new file mode 100644 index 0000000..407137f --- /dev/null +++ b/js/dojo/dijit/_editor/nls/ru/commands.js @@ -0,0 +1,53 @@ +//>>built +define( +"dijit/_editor/nls/ru/commands", //begin v1.x content +({ + 'bold': 'Полужирный', + 'copy': 'Копировать', + 'cut': 'Вырезать', + 'delete': 'Удалить', + 'indent': 'Отступ', + 'insertHorizontalRule': 'Горизонтальная линейка', + 'insertOrderedList': 'Нумерованный список', + 'insertUnorderedList': 'Список с маркерами', + 'italic': 'Курсив', + 'justifyCenter': 'По центру', + 'justifyFull': 'По ширине', + 'justifyLeft': 'По левому краю', + 'justifyRight': 'По правому краю', + 'outdent': 'Втяжка', + 'paste': 'Вставить', + 'redo': 'Повторить', + 'removeFormat': 'Удалить формат', + 'selectAll': 'Выбрать все', + 'strikethrough': 'Перечеркивание', + 'subscript': 'Нижний индекс', + 'superscript': 'Верхний индекс', + 'underline': 'Подчеркивание', + 'undo': 'Отменить', + 'unlink': 'Удалить ссылку', + 'createLink': 'Создать ссылку', + 'toggleDir': 'Изменить направление', + 'insertImage': 'Вставить изображение', + 'insertTable': 'Вставить/изменить таблицу', + 'toggleTableBorder': 'Переключить рамку таблицы', + 'deleteTable': 'Удалить таблицу', + 'tableProp': 'Свойства таблицы', + 'htmlToggle': 'Код HTML', + 'foreColor': 'Цвет текста', + 'hiliteColor': 'Цвет фона', + 'plainFormatBlock': 'Стиль абзаца', + 'formatBlock': 'Стиль абзаца', + 'fontSize': 'Размер шрифта', + 'fontName': 'Название шрифта', + 'tabIndent': 'Табуляция', + "fullScreen": "Переключить полноэкранный режим", + "viewSource": "Показать исходный код HTML", + "print": "Печать", + "newPage": "Создать страницу", + /* Error messages */ + 'systemShortcut': 'Действие "${0}" можно выполнить в браузере только путем нажатия клавиш ${1}.' +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/sk/FontChoice.js b/js/dojo/dijit/_editor/nls/sk/FontChoice.js new file mode 100644 index 0000000..7091261 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/sk/FontChoice.js @@ -0,0 +1,32 @@ +//>>built +define( +"dijit/_editor/nls/sk/FontChoice", //begin v1.x content +({ + fontSize: "Veľkosť", + fontName: "Písmo", + formatBlock: "Formát", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "cursive", + fantasy: "fantasy", + + noFormat: "Žiadny", + p: "Odsek", + h1: "Hlavička", + h2: "Podhlavička", + h3: "Pod-podhlavička", + pre: "Predformátované", + + 1: "xx-small", + 2: "x-small", + 3: "small", + 4: "medium", + 5: "large", + 6: "x-large", + 7: "xx-large" +}) +//end v1.x content +); + diff --git a/js/dojo/dijit/_editor/nls/sk/LinkDialog.js b/js/dojo/dijit/_editor/nls/sk/LinkDialog.js new file mode 100644 index 0000000..d288077 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/sk/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/sk/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Pripojiť vlastnosti", + insertImageTitle: "Vlastnosti obrázka ", + url: "URL:", + text: "Opis:", + target: "Cieľ:", + set: "Nastaviť", + currentWindow: "Aktuálne okno ", + parentWindow: "Rodičovské okno ", + topWindow: "Najvrchnejšie okno ", + newWindow: "Nové okno " +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/sk/commands.js b/js/dojo/dijit/_editor/nls/sk/commands.js new file mode 100644 index 0000000..d13c8e3 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/sk/commands.js @@ -0,0 +1,53 @@ +//>>built +define( +"dijit/_editor/nls/sk/commands", //begin v1.x content +({ + 'bold': 'Tučné písmo', + 'copy': 'Kopírovať', + 'cut': 'Vystrihnúť', + 'delete': 'Vymazať', + 'indent': 'Odsadiť', + 'insertHorizontalRule': 'Horizontálna čiara', + 'insertOrderedList': 'Číslovaný zoznam', + 'insertUnorderedList': 'Zoznam s odrážkami', + 'italic': 'Kurzíva', + 'justifyCenter': 'Zarovnať na stred', + 'justifyFull': 'Zarovnať podľa okraja', + 'justifyLeft': 'Zarovnať doľava', + 'justifyRight': 'Zarovnať doprava', + 'outdent': 'Predsadiť', + 'paste': 'Nalepiť', + 'redo': 'Znova vykonať', + 'removeFormat': 'Odstrániť formát', + 'selectAll': 'Vybrať všetko', + 'strikethrough': 'Prečiarknuť', + 'subscript': 'Dolný index', + 'superscript': 'Horný index', + 'underline': 'Podčiarknuť', + 'undo': 'Vrátiť späť', + 'unlink': 'Odstrániť prepojenie', + 'createLink': 'Vytvoriť prepojenie', + 'toggleDir': 'Prepnúť smer', + 'insertImage': 'Vložiť obrázok', + 'insertTable': 'Vložiť/upraviť tabuľku', + 'toggleTableBorder': 'Prepnúť rámček tabuľky', + 'deleteTable': 'Vymazať tabuľku', + 'tableProp': 'Vlastnosť tabuľky', + 'htmlToggle': 'Zdroj HTML', + 'foreColor': 'Farba popredia', + 'hiliteColor': 'Farba pozadia', + 'plainFormatBlock': 'Štýl odseku', + 'formatBlock': 'Štýl odseku', + 'fontSize': 'Veľkosť písma', + 'fontName': 'Názov písma', + 'tabIndent': 'Odsadenie tabulátora', + "fullScreen": "Zobraziť na celú obrazovku", + "viewSource": "Zobraziť zdrojový kód HTML ", + "print": "Tlačiť", + "newPage": "Nová stránka ", + /* Error messages */ + 'systemShortcut': 'Akcia "${0}" je vo vašom prehliadači dostupná len s použitím klávesovej skratky. Použite ${1}.' +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/sl/FontChoice.js b/js/dojo/dijit/_editor/nls/sl/FontChoice.js new file mode 100644 index 0000000..998e208 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/sl/FontChoice.js @@ -0,0 +1,32 @@ +//>>built +define( +"dijit/_editor/nls/sl/FontChoice", //begin v1.x content +({ + fontSize: "Velikost", + fontName: "Pisava", + formatBlock: "Oblika", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "cursive", + fantasy: "fantasy", + + noFormat: "Brez", + p: "Odstavek", + h1: "Naslovni slog", + h2: "Podnaslovni slog", + h3: "Pod-podnaslovni slog", + pre: "Vnaprej oblikovan", + + 1: "xx-majhno", + 2: "x-majhno", + 3: "majhno", + 4: "srednje", + 5: "veliko", + 6: "x-veliko", + 7: "xx-veliko" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/sl/LinkDialog.js b/js/dojo/dijit/_editor/nls/sl/LinkDialog.js new file mode 100644 index 0000000..fddc381 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/sl/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/sl/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Lastnosti povezave", + insertImageTitle: "Lastnosti slike", + url: "URL:", + text: "Opis:", + target: "Cilj:", + set: "Nastavi", + currentWindow: "Trenutno okno", + parentWindow: "Nadrejeno okno", + topWindow: "Okno na vrhu", + newWindow: "Novo okno" +}) +//end v1.x content +); + diff --git a/js/dojo/dijit/_editor/nls/sl/commands.js b/js/dojo/dijit/_editor/nls/sl/commands.js new file mode 100644 index 0000000..87b2e18 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/sl/commands.js @@ -0,0 +1,52 @@ +//>>built +define( +"dijit/_editor/nls/sl/commands", //begin v1.x content +({ + 'bold': 'Krepko', + 'copy': 'Prekopiraj', + 'cut': 'Izreži', + 'delete': 'Izbriši', + 'indent': 'Zamik', + 'insertHorizontalRule': 'Vodoravno ravnilo', + 'insertOrderedList': 'Oštevilčen seznam', + 'insertUnorderedList': 'Naštevni seznam', + 'italic': 'Ležeče', + 'justifyCenter': 'Poravnaj na sredino', + 'justifyFull': 'Poravnaj obojestransko', + 'justifyLeft': 'Poravnaj levo', + 'justifyRight': 'Poravnaj desno', + 'outdent': 'Primakni', + 'paste': 'Prilepi', + 'redo': 'Znova uveljavi', + 'removeFormat': 'Odstrani oblikovanje', + 'selectAll': 'Izberi vse', + 'strikethrough': 'Prečrtano', + 'subscript': 'Podpisano', + 'superscript': 'Nadpisano', + 'underline': 'Podčrtano', + 'undo': 'Razveljavi', + 'unlink': 'Odstrani povezavo', + 'createLink': 'Ustvari povezavo', + 'toggleDir': 'Preklopi smer', + 'insertImage': 'Vstavi sliko', + 'insertTable': 'Vstavi/uredi tabelo', + 'toggleTableBorder': 'Preklopi na rob tabele', + 'deleteTable': 'Izbriši tabelo', + 'tableProp': 'Lastnost tabele', + 'htmlToggle': 'Izvorna koda HTML', + 'foreColor': 'Barva ospredja', + 'hiliteColor': 'Barva ozadja', + 'plainFormatBlock': 'Slog odstavka', + 'formatBlock': 'Slog odstavka', + 'fontSize': 'Velikost pisave', + 'fontName': 'Ime pisave', + 'tabIndent': 'Zamik tabulatorja', + "fullScreen": "Preklopi na celozaslonski način", + "viewSource": "Prikaži izvorno kodo HTML", + "print": "Natisni", + "newPage": "Nova stran", + /* Error messages */ + 'systemShortcut': 'Dejanje "${0}" lahko v vašem brskalniku uporabite samo z bližnjico na tipkovnici. Uporabite ${1}.' +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/sv/FontChoice.js b/js/dojo/dijit/_editor/nls/sv/FontChoice.js new file mode 100644 index 0000000..dfd430c --- /dev/null +++ b/js/dojo/dijit/_editor/nls/sv/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/sv/FontChoice", //begin v1.x content +({ + fontSize: "Storlek", + fontName: "Teckensnitt", + formatBlock: "Format", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "kursivt", + fantasy: "fantasy", + + noFormat: "Ingen", + p: "Stycke", + h1: "Rubrik", + h2: "Underrubrik", + h3: "Underunderrubrik", + pre: "Förformaterat", + + 1: "mycket, mycket litet", + 2: "mycket litet", + 3: "litet", + 4: "medelstort", + 5: "stort", + 6: "extra stort", + 7: "extra extra stort" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/sv/LinkDialog.js b/js/dojo/dijit/_editor/nls/sv/LinkDialog.js new file mode 100644 index 0000000..acdd6fd --- /dev/null +++ b/js/dojo/dijit/_editor/nls/sv/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/sv/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Länkegenskaper", + insertImageTitle: "Bildegenskaper", + url: "URL-adress:", + text: "Beskrivning:", + target: "Mål:", + set: "Ange", + currentWindow: "aktuellt fönster", + parentWindow: "överordnat fönster", + topWindow: "översta fönstret", + newWindow: "nytt fönster" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/sv/commands.js b/js/dojo/dijit/_editor/nls/sv/commands.js new file mode 100644 index 0000000..b7e20ad --- /dev/null +++ b/js/dojo/dijit/_editor/nls/sv/commands.js @@ -0,0 +1,55 @@ +//>>built +define( +"dijit/_editor/nls/sv/commands", //begin v1.x content +({ + 'bold': 'Fetstil', + 'copy': 'Kopiera', + 'cut': 'Klipp ut', + 'delete': 'Ta bort', + 'indent': 'Indrag', + 'insertHorizontalRule': 'Horisontell linjal', + 'insertOrderedList': 'Numrerad lista', + 'insertUnorderedList': 'Punktlista', + 'italic': 'Kursiv', + 'justifyCenter': 'Centrera', + 'justifyFull': 'Marginaljustera', + 'justifyLeft': 'Vänsterjustera', + 'justifyRight': 'Högerjustera', + 'outdent': 'Utdrag', + 'paste': 'Klistra in', + 'redo': 'Gör om', + 'removeFormat': 'Ta bort format', + 'selectAll': 'Markera allt', + 'strikethrough': 'Genomstruken', + 'subscript': 'Nedsänkt', + 'superscript': 'Upphöjt', + 'underline': 'Understrykning', + 'undo': 'Ångra', + 'unlink': 'Ta bort länk', + 'createLink': 'Skapa länk', + 'toggleDir': 'Växla riktning', + 'insertImage': 'Infoga bild', + 'insertTable': 'Infoga/redigera tabell', + 'toggleTableBorder': 'Aktivera/avaktivera tabellram', + 'deleteTable': 'Ta bort tabell', + 'tableProp': 'Tabellegenskap', + 'htmlToggle': 'HTML-källkod', + 'foreColor': 'Förgrundsfärg', + 'hiliteColor': 'Bakgrundsfärg', + 'plainFormatBlock': 'Styckeformat', + 'formatBlock': 'Styckeformat', + 'fontSize': 'Teckenstorlek', + 'fontName': 'Teckensnittsnamn', + 'tabIndent': 'Tabbindrag', + "fullScreen": "Växla helskärm", + "viewSource": "Visa HTML-kod", + "print": "Skriv ut", + "newPage": "Ny sida", + /* Error messages */ + 'systemShortcut': 'Åtgärden "${0}" är endast tillgänglig i webbläsaren med hjälp av ett kortkommando. Använd ${1}.', + 'ctrlKey':'Ctrl+${0}', + 'appleKey':'\u2318+${0}' // "command" or open-apple key on Macintosh +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/th/FontChoice.js b/js/dojo/dijit/_editor/nls/th/FontChoice.js new file mode 100644 index 0000000..a7ce676 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/th/FontChoice.js @@ -0,0 +1,32 @@ +//>>built +define( +"dijit/_editor/nls/th/FontChoice", //begin v1.x content +({ + fontSize: "ขนาด", + fontName: "ฟอนต์", + formatBlock: "รูปแบบ", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "monospace", + cursive: "cursive", + fantasy: "fantasy", + + noFormat: "ไม่มี", + p: "ย่อหน้า", + h1: "ส่วนหัว", + h2: "ส่วนหัวย่อย", + h3: "ส่วนย่อยของส่วนหัวย่อย", + pre: "การกำหนดรูปแบบล่วงหน้า", + + 1: "xx-small", + 2: "x-small", + 3: "small", + 4: "medium", + 5: "large", + 6: "x-large", + 7: "xx-large" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/th/LinkDialog.js b/js/dojo/dijit/_editor/nls/th/LinkDialog.js new file mode 100644 index 0000000..f9855a7 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/th/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/th/LinkDialog", //begin v1.x content +({ + createLinkTitle: "คุณสมบัติลิงก์", + insertImageTitle: "คุณสมบัติอิมเมจ", + url: "URL:", + text: "รายละเอียด:", + target: "เป้าหมาย:", + set: "ตั้งค่า", + currentWindow: "หน้าต่างปัจจุบัน", + parentWindow: "หน้าต่างหลัก", + topWindow: "หน้าต่างบนสุด", + newWindow: "หน้าต่างใหม่" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/th/commands.js b/js/dojo/dijit/_editor/nls/th/commands.js new file mode 100644 index 0000000..58c5259 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/th/commands.js @@ -0,0 +1,53 @@ +//>>built +define( +"dijit/_editor/nls/th/commands", //begin v1.x content +({ + 'bold': 'ตัวหนา', + 'copy': 'คัดลอก', + 'cut': 'ตัด', + 'delete': 'ลบ', + 'indent': 'เพิ่มการเยื้อง', + 'insertHorizontalRule': 'ไม้บรรทัดแนวนอน', + 'insertOrderedList': 'ลำดับเลข', + 'insertUnorderedList': 'หัวข้อย่อย', + 'italic': 'ตัวเอียง', + 'justifyCenter': 'จัดกึ่งกลาง', + 'justifyFull': 'จัดชิดขอบ', + 'justifyLeft': 'จัดชิดซ้าย', + 'justifyRight': 'จัดชิดขวา', + 'outdent': 'ลดการเยื้อง', + 'paste': 'วาง', + 'redo': 'ทำซ้ำ', + 'removeFormat': 'ลบรูปแบบออก', + 'selectAll': 'เลือกทั้งหมด', + 'strikethrough': 'ขีดทับ', + 'subscript': 'ตัวห้อย', + 'superscript': 'ตัวยก', + 'underline': 'ขีดเส้นใต้', + 'undo': 'เลิกทำ', + 'unlink': 'ลบลิงก์ออก', + 'createLink': 'สร้างลิงก์', + 'toggleDir': 'สลับทิศทาง', + 'insertImage': 'แทรกอิมเมจ', + 'insertTable': 'แทรก/แก้ไขตาราง', + 'toggleTableBorder': 'สลับเส้นขอบตาราง', + 'deleteTable': 'ลบตาราง', + 'tableProp': 'คุณสมบัติตาราง', + 'htmlToggle': 'ซอร์ส HTML', + 'foreColor': 'สีพื้นหน้า', + 'hiliteColor': 'สีพื้นหลัง', + 'plainFormatBlock': 'ลักษณะย่อหน้า', + 'formatBlock': 'ลักษณะย่อหน้า', + 'fontSize': 'ขนาดฟอนต์', + 'fontName': 'ชื่อฟอนต์', + 'tabIndent': 'เยื้องแท็บ', + "fullScreen": "สลับจอภาพแบบเต็ม", + "viewSource": "ดูซอร์ส HTML", + "print": "พิมพ์", + "newPage": "หน้าใหม่", + /* Error messages */ + 'systemShortcut': 'การดำเนินการ"${0}" ใช้งานได้เฉพาะกับเบราว์เซอร์ของคุณโดยใช้แป้นพิมพ์ลัด ใช้ ${1}' +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/tr/FontChoice.js b/js/dojo/dijit/_editor/nls/tr/FontChoice.js new file mode 100644 index 0000000..2d085a4 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/tr/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/tr/FontChoice", //begin v1.x content +({ + fontSize: "Boyut", + fontName: "Yazı Tipi", + formatBlock: "Biçim", + + serif: "serif", + "sans-serif": "sans-serif", + monospace: "tek aralıklı", + cursive: "el yazısı", + fantasy: "fantazi", + + noFormat: "Yok", + p: "Paragraf", + h1: "Başlık", + h2: "Alt Başlık", + h3: "Alt Alt Başlık", + pre: "Önceden Biçimlendirilmiş", + + 1: "xx-küçük", + 2: "x-küçük", + 3: "küçük", + 4: "orta", + 5: "büyük", + 6: "x-büyük", + 7: "xx-büyük" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/tr/LinkDialog.js b/js/dojo/dijit/_editor/nls/tr/LinkDialog.js new file mode 100644 index 0000000..dd611b2 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/tr/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/tr/LinkDialog", //begin v1.x content +({ + createLinkTitle: "Bağlantı Özellikleri", + insertImageTitle: "Resim Özellikleri", + url: "URL:", + text: "Açıklama:", + target: "Hedef:", + set: "Ayarla", + currentWindow: "Geçerli Pencere", + parentWindow: "Üst Pencere", + topWindow: "En Üst Pencere", + newWindow: "Yeni Pencere" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/tr/commands.js b/js/dojo/dijit/_editor/nls/tr/commands.js new file mode 100644 index 0000000..1f8ce11 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/tr/commands.js @@ -0,0 +1,53 @@ +//>>built +define( +"dijit/_editor/nls/tr/commands", //begin v1.x content +({ + 'bold': 'Kalın', + 'copy': 'Kopyala', + 'cut': 'Kes', + 'delete': 'Sil', + 'indent': 'Girinti', + 'insertHorizontalRule': 'Yatay Kural', + 'insertOrderedList': 'Numaralı Liste', + 'insertUnorderedList': 'Madde İşaretli Liste', + 'italic': 'İtalik', + 'justifyCenter': 'Ortaya Hizala', + 'justifyFull': 'Yasla', + 'justifyLeft': 'Sola Hizala', + 'justifyRight': 'Sağa Hizala', + 'outdent': 'Çıkıntı', + 'paste': 'Yapıştır', + 'redo': 'Yinele', + 'removeFormat': 'Biçimi Kaldır', + 'selectAll': 'Tümünü Seç', + 'strikethrough': 'Üstü Çizili', + 'subscript': 'Alt Simge', + 'superscript': 'Üst Simge', + 'underline': 'Altı Çizili', + 'undo': 'Geri Al', + 'unlink': 'Bağlantıyı Kaldır', + 'createLink': 'Bağlantı Oluştur', + 'toggleDir': 'Yönü Değiştir', + 'insertImage': 'Resim Ekle', + 'insertTable': 'Tablo Ekle/Düzenle', + 'toggleTableBorder': 'Tablo Kenarlığını Göster/Gizle', + 'deleteTable': 'Tabloyu Sil', + 'tableProp': 'Tablo Özelliği', + 'htmlToggle': 'HTML Kaynağı', + 'foreColor': 'Ön Plan Rengi', + 'hiliteColor': 'Arka Plan Rengi', + 'plainFormatBlock': 'Paragraf Stili', + 'formatBlock': 'Paragraf Stili', + 'fontSize': 'Yazı Tipi Boyutu', + 'fontName': 'Yazı Tipi Adı', + 'tabIndent': 'Sekme Girintisi', + "fullScreen": "Tam Ekranı Aç/Kapat", + "viewSource": "HTML Kaynağını Görüntüle", + "print": "Yazdır", + "newPage": "Yeni Sayfa", + /* Error messages */ + 'systemShortcut': '"${0}" işlemi yalnızca tarayıcınızda bir klavye kısayoluyla birlikte kullanılabilir. Şunu kullanın: ${1}.' +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/zh-tw/FontChoice.js b/js/dojo/dijit/_editor/nls/zh-tw/FontChoice.js new file mode 100644 index 0000000..fd2d0d2 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/zh-tw/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/zh-tw/FontChoice", //begin v1.x content +({ + fontSize: "大小", + fontName: "字型", + formatBlock: "格式", + + serif: "新細明體", + "sans-serif": "新細明體", + monospace: "等寬", + cursive: "Cursive", + fantasy: "Fantasy", + + noFormat: "無", + p: "段落", + h1: "標題", + h2: "子標題", + h3: "次子標題", + pre: "預先格式化", + + 1: "最小", + 2: "較小", + 3: "小", + 4: "中", + 5: "大", + 6: "較大", + 7: "最大" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/zh-tw/LinkDialog.js b/js/dojo/dijit/_editor/nls/zh-tw/LinkDialog.js new file mode 100644 index 0000000..e585872 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/zh-tw/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/zh-tw/LinkDialog", //begin v1.x content +({ + createLinkTitle: "鏈結內容", + insertImageTitle: "影像內容", + url: "URL:", + text: "說明:", + target: "目標:", + set: "設定", + currentWindow: "現行視窗", + parentWindow: "上層視窗", + topWindow: "最上面的視窗", + newWindow: "新視窗" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/zh-tw/commands.js b/js/dojo/dijit/_editor/nls/zh-tw/commands.js new file mode 100644 index 0000000..74bde79 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/zh-tw/commands.js @@ -0,0 +1,52 @@ +//>>built +define( +"dijit/_editor/nls/zh-tw/commands", //begin v1.x content +({ + 'bold': '粗體', + 'copy': '複製', + 'cut': '剪下', + 'delete': '刪除', + 'indent': '縮排', + 'insertHorizontalRule': '水平尺規', + 'insertOrderedList': '編號清單', + 'insertUnorderedList': '項目符號清單', + 'italic': '斜體', + 'justifyCenter': '置中對齊', + 'justifyFull': '對齊', + 'justifyLeft': '靠左對齊', + 'justifyRight': '靠右對齊', + 'outdent': '凸排', + 'paste': '貼上', + 'redo': '重做', + 'removeFormat': '移除格式', + 'selectAll': '全選', + 'strikethrough': '刪除線', + 'subscript': '下標', + 'superscript': '上標', + 'underline': '底線', + 'undo': '復原', + 'unlink': '移除鏈結', + 'createLink': '建立鏈結', + 'toggleDir': '切換方向', + 'insertImage': '插入影像', + 'insertTable': '插入/編輯表格', + 'toggleTableBorder': '切換表格邊框', + 'deleteTable': '刪除表格', + 'tableProp': '表格內容', + 'htmlToggle': 'HTML 原始檔', + 'foreColor': '前景顏色', + 'hiliteColor': '背景顏色', + 'plainFormatBlock': '段落樣式', + 'formatBlock': '段落樣式', + 'fontSize': '字型大小', + 'fontName': '字型名稱', + 'tabIndent': '標籤縮排', + "fullScreen": "切換全螢幕", + "viewSource": "檢視 HTML 原始檔", + "print": "列印", + "newPage": "新頁面", + /* Error messages */ + 'systemShortcut': '"${0}" 動作在您的瀏覽器中,只能使用鍵盤快速鍵。請使用 ${1}。' +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/zh/FontChoice.js b/js/dojo/dijit/_editor/nls/zh/FontChoice.js new file mode 100644 index 0000000..c565ab0 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/zh/FontChoice.js @@ -0,0 +1,31 @@ +//>>built +define( +"dijit/_editor/nls/zh/FontChoice", //begin v1.x content +({ + fontSize: "大小", + fontName: "字体", + formatBlock: "格式", + + serif: "有衬线", + "sans-serif": "无衬线", + monospace: "等宽字体", + cursive: "草书", + fantasy: "虚线", + + noFormat: "无", + p: "段落", + h1: "标题", + h2: "子标题", + h3: "二级子标题", + pre: "预设有格式的", + + 1: "XXS 号", + 2: "XS 号", + 3: "S 号", + 4: "M 号", + 5: "L 号", + 6: "XL 号", + 7: "XXL 号" +}) +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/zh/LinkDialog.js b/js/dojo/dijit/_editor/nls/zh/LinkDialog.js new file mode 100644 index 0000000..16de874 --- /dev/null +++ b/js/dojo/dijit/_editor/nls/zh/LinkDialog.js @@ -0,0 +1,18 @@ +//>>built +define( +"dijit/_editor/nls/zh/LinkDialog", //begin v1.x content +({ + createLinkTitle: "链接属性", + insertImageTitle: "图像属性", + url: "URL:", + text: "描述:", + target: "目标:", + set: "设置", + currentWindow: "当前窗口", + parentWindow: "父窗口", + topWindow: "顶层窗口", + newWindow: "新建窗口" +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/nls/zh/commands.js b/js/dojo/dijit/_editor/nls/zh/commands.js new file mode 100644 index 0000000..459e83e --- /dev/null +++ b/js/dojo/dijit/_editor/nls/zh/commands.js @@ -0,0 +1,53 @@ +//>>built +define( +"dijit/_editor/nls/zh/commands", //begin v1.x content +({ + 'bold': '粗体', + 'copy': '复制', + 'cut': '剪切', + 'delete': '删除', + 'indent': '增加缩进', + 'insertHorizontalRule': '水平线', + 'insertOrderedList': '编号列表', + 'insertUnorderedList': '符号列表', + 'italic': '斜体', + 'justifyCenter': '居中', + 'justifyFull': '对齐', + 'justifyLeft': '左对齐', + 'justifyRight': '右对齐', + 'outdent': '减少缩进', + 'paste': '粘贴', + 'redo': '重做', + 'removeFormat': '除去格式', + 'selectAll': '全选', + 'strikethrough': '删除线', + 'subscript': '下标', + 'superscript': '上标', + 'underline': '下划线', + 'undo': '撤销', + 'unlink': '除去链接', + 'createLink': '创建链接', + 'toggleDir': '固定方向', + 'insertImage': '插入图像', + 'insertTable': '插入/编辑表', + 'toggleTableBorder': '切换表边框', + 'deleteTable': '删除表', + 'tableProp': '表属性', + 'htmlToggle': 'HTML 源代码', + 'foreColor': '前景色', + 'hiliteColor': '背景色', + 'plainFormatBlock': '段落样式', + 'formatBlock': '段落样式', + 'fontSize': '字体大小', + 'fontName': '字体名称', + 'tabIndent': '制表符缩进', + "fullScreen": "切换全屏幕", + "viewSource": "查看 HTML 源代码", + "print": "打印", + "newPage": "新建页面", + /* Error messages */ + 'systemShortcut': '只能在浏览器中通过键盘快捷方式执行“${0}”操作。使用 ${1}。' +}) + +//end v1.x content +); diff --git a/js/dojo/dijit/_editor/plugins/AlwaysShowToolbar.js b/js/dojo/dijit/_editor/plugins/AlwaysShowToolbar.js new file mode 100644 index 0000000..1f66aef --- /dev/null +++ b/js/dojo/dijit/_editor/plugins/AlwaysShowToolbar.js @@ -0,0 +1,200 @@ +//>>built +define("dijit/_editor/plugins/AlwaysShowToolbar", [ + "dojo/_base/declare", // declare + "dojo/dom-class", // domClass.add domClass.remove + "dojo/dom-construct", // domConstruct.place + "dojo/dom-geometry", + "dojo/_base/lang", // lang.hitch + "dojo/_base/sniff", // has("ie") has("opera") + "dojo/_base/window", // win.body + "../_Plugin" +], function(declare, domClass, domConstruct, domGeometry, lang, has, win, _Plugin){ + +/*===== + var _Plugin = dijit._editor._Plugin; +=====*/ + +// module: +// dijit/_editor/plugins/AlwaysShowToolbar +// summary: +// This plugin is required for Editors in auto-expand mode. +// It handles the auto-expansion as the user adds/deletes text, +// and keeps the editor's toolbar visible even when the top of the editor +// has scrolled off the top of the viewport (usually when editing a long +// document). + + +return declare("dijit._editor.plugins.AlwaysShowToolbar", _Plugin, { + // summary: + // This plugin is required for Editors in auto-expand mode. + // It handles the auto-expansion as the user adds/deletes text, + // and keeps the editor's toolbar visible even when the top of the editor + // has scrolled off the top of the viewport (usually when editing a long + // document). + // description: + // Specify this in extraPlugins (or plugins) parameter and also set + // height to "". + // example: + // | <div data-dojo-type="dijit.Editor" height="" + // | data-dojo-props="extraPlugins: [dijit._editor.plugins.AlwaysShowToolbar]"> + + // _handleScroll: Boolean + // Enables/disables the handler for scroll events + _handleScroll: true, + + setEditor: function(e){ + // Overrides _Plugin.setEditor(). + if(!e.iframe){ + console.log('Port AlwaysShowToolbar plugin to work with Editor without iframe'); + return; + } + + this.editor = e; + + e.onLoadDeferred.addCallback(lang.hitch(this, this.enable)); + }, + + enable: function(d){ + // summary: + // Enable plugin. Called when Editor has finished initializing. + // tags: + // private + + this._updateHeight(); + this.connect(window, 'onscroll', "globalOnScrollHandler"); + this.connect(this.editor, 'onNormalizedDisplayChanged', "_updateHeight"); + return d; + }, + + _updateHeight: function(){ + // summary: + // Updates the height of the editor area to fit the contents. + var e = this.editor; + if(!e.isLoaded){ return; } + if(e.height){ return; } + + var height = domGeometry.getMarginSize(e.editNode).h; + if(has("opera")){ + height = e.editNode.scrollHeight; + } + // console.debug('height',height); + // alert(this.editNode); + + //height maybe zero in some cases even though the content is not empty, + //we try the height of body instead + if(!height){ + height = domGeometry.getMarginSize(e.document.body).h; + } + + if(height == 0){ + console.debug("Can not figure out the height of the editing area!"); + return; //prevent setting height to 0 + } + if(has("ie") <= 7 && this.editor.minHeight){ + var min = parseInt(this.editor.minHeight); + if(height < min){ height = min; } + } + if(height != this._lastHeight){ + this._lastHeight = height; + // this.editorObject.style.height = this._lastHeight + "px"; + domGeometry.setMarginBox(e.iframe, { h: this._lastHeight }); + } + }, + + // _lastHeight: Integer + // Height in px of the editor at the last time we did sizing + _lastHeight: 0, + + globalOnScrollHandler: function(){ + // summary: + // Handler for scroll events that bubbled up to <html> + // tags: + // private + + var isIE6 = has("ie") < 7; + if(!this._handleScroll){ return; } + var tdn = this.editor.header; + if(!this._scrollSetUp){ + this._scrollSetUp = true; + this._scrollThreshold = domGeometry.position(tdn, true).y; +// var db = win.body; +// console.log("threshold:", this._scrollThreshold); + //what's this for?? comment out for now +// if((isIE6)&&(db)&&(domStyle.set or get TODO(db, "backgroundIimage")=="none")){ +// db.style.backgroundImage = "url(" + dojo.uri.moduleUri("dijit", "templates/blank.gif") + ")"; +// db.style.backgroundAttachment = "fixed"; +// } + } + + var scrollPos = domGeometry.docScroll().y; + var s = tdn.style; + + if(scrollPos > this._scrollThreshold && scrollPos < this._scrollThreshold+this._lastHeight){ + // dojo.debug(scrollPos); + if(!this._fixEnabled){ + var tdnbox = domGeometry.getMarginSize(tdn); + this.editor.iframe.style.marginTop = tdnbox.h+"px"; + + if(isIE6){ + s.left = domGeometry.position(tdn).x; + if(tdn.previousSibling){ + this._IEOriginalPos = ['after',tdn.previousSibling]; + }else if(tdn.nextSibling){ + this._IEOriginalPos = ['before',tdn.nextSibling]; + }else{ + this._IEOriginalPos = ['last',tdn.parentNode]; + } + win.body().appendChild(tdn); + domClass.add(tdn,'dijitIEFixedToolbar'); + }else{ + s.position = "fixed"; + s.top = "0px"; + } + + domGeometry.setMarginBox(tdn, { w: tdnbox.w }); + s.zIndex = 2000; + this._fixEnabled = true; + } + // if we're showing the floating toolbar, make sure that if + // we've scrolled past the bottom of the editor that we hide + // the toolbar for this instance of the editor. + + // TODO: when we get multiple editor toolbar support working + // correctly, ensure that we check this against the scroll + // position of the bottom-most editor instance. + var eHeight = (this.height) ? parseInt(this.editor.height) : this.editor._lastHeight; + s.display = (scrollPos > this._scrollThreshold+eHeight) ? "none" : ""; + }else if(this._fixEnabled){ + this.editor.iframe.style.marginTop = ''; + s.position = ""; + s.top = ""; + s.zIndex = ""; + s.display = ""; + if(isIE6){ + s.left = ""; + domClass.remove(tdn,'dijitIEFixedToolbar'); + if(this._IEOriginalPos){ + domConstruct.place(tdn, this._IEOriginalPos[1], this._IEOriginalPos[0]); + this._IEOriginalPos = null; + }else{ + domConstruct.place(tdn, this.editor.iframe, 'before'); + } + } + s.width = ""; + this._fixEnabled = false; + } + }, + + destroy: function(){ + // Overrides _Plugin.destroy(). TODO: call this.inherited() rather than repeating code. + this._IEOriginalPos = null; + this._handleScroll = false; + this.inherited(arguments); + + if(has("ie") < 7){ + domClass.remove(this.editor.header, 'dijitIEFixedToolbar'); + } + } +}); + +}); diff --git a/js/dojo/dijit/_editor/plugins/EnterKeyHandling.js b/js/dojo/dijit/_editor/plugins/EnterKeyHandling.js new file mode 100644 index 0000000..a7f36c8 --- /dev/null +++ b/js/dojo/dijit/_editor/plugins/EnterKeyHandling.js @@ -0,0 +1,626 @@ +//>>built +define("dijit/_editor/plugins/EnterKeyHandling", [ + "dojo/_base/declare", // declare + "dojo/dom-construct", // domConstruct.destroy domConstruct.place + "dojo/_base/event", // event.stop + "dojo/keys", // keys.ENTER + "dojo/_base/lang", + "dojo/_base/sniff", // has("ie") has("mozilla") has("webkit") + "dojo/_base/window", // win.global win.withGlobal + "dojo/window", // winUtils.scrollIntoView + "../_Plugin", + "../RichText", + "../range", + "../selection" +], function(declare, domConstruct, event, keys, lang, has, win, winUtils, _Plugin, RichText, rangeapi, selectionapi){ + +/*===== + var _Plugin = dijit._editor._Plugin; +=====*/ + +// module: +// dijit/_editor/plugins/EnterKeyHandling +// summary: +// This plugin tries to make all browsers behave consistently with regard to +// how ENTER behaves in the editor window. It traps the ENTER key and alters +// the way DOM is constructed in certain cases to try to commonize the generated +// DOM and behaviors across browsers. + + +return declare("dijit._editor.plugins.EnterKeyHandling", _Plugin, { + // summary: + // This plugin tries to make all browsers behave consistently with regard to + // how ENTER behaves in the editor window. It traps the ENTER key and alters + // the way DOM is constructed in certain cases to try to commonize the generated + // DOM and behaviors across browsers. + // + // description: + // This plugin has three modes: + // + // * blockNodeForEnter=BR + // * blockNodeForEnter=DIV + // * blockNodeForEnter=P + // + // In blockNodeForEnter=P, the ENTER key starts a new + // paragraph, and shift-ENTER starts a new line in the current paragraph. + // For example, the input: + // + // | first paragraph <shift-ENTER> + // | second line of first paragraph <ENTER> + // | second paragraph + // + // will generate: + // + // | <p> + // | first paragraph + // | <br/> + // | second line of first paragraph + // | </p> + // | <p> + // | second paragraph + // | </p> + // + // In BR and DIV mode, the ENTER key conceptually goes to a new line in the + // current paragraph, and users conceptually create a new paragraph by pressing ENTER twice. + // For example, if the user enters text into an editor like this: + // + // | one <ENTER> + // | two <ENTER> + // | three <ENTER> + // | <ENTER> + // | four <ENTER> + // | five <ENTER> + // | six <ENTER> + // + // It will appear on the screen as two 'paragraphs' of three lines each. Markupwise, this generates: + // + // BR: + // | one<br/> + // | two<br/> + // | three<br/> + // | <br/> + // | four<br/> + // | five<br/> + // | six<br/> + // + // DIV: + // | <div>one</div> + // | <div>two</div> + // | <div>three</div> + // | <div> </div> + // | <div>four</div> + // | <div>five</div> + // | <div>six</div> + + // blockNodeForEnter: String + // This property decides the behavior of Enter key. It can be either P, + // DIV, BR, or empty (which means disable this feature). Anything else + // will trigger errors. The default is 'BR' + // + // See class description for more details. + blockNodeForEnter: 'BR', + + constructor: function(args){ + if(args){ + if("blockNodeForEnter" in args){ + args.blockNodeForEnter = args.blockNodeForEnter.toUpperCase(); + } + lang.mixin(this,args); + } + }, + + setEditor: function(editor){ + // Overrides _Plugin.setEditor(). + if(this.editor === editor){ return; } + this.editor = editor; + if(this.blockNodeForEnter == 'BR'){ + // While Moz has a mode tht mostly works, it's still a little different, + // So, try to just have a common mode and be consistent. Which means + // we need to enable customUndo, if not already enabled. + this.editor.customUndo = true; + editor.onLoadDeferred.addCallback(lang.hitch(this,function(d){ + this.connect(editor.document, "onkeypress", function(e){ + if(e.charOrCode == keys.ENTER){ + // Just do it manually. The handleEnterKey has a shift mode that + // Always acts like <br>, so just use it. + var ne = lang.mixin({},e); + ne.shiftKey = true; + if(!this.handleEnterKey(ne)){ + event.stop(e); + } + } + }); + return d; + })); + }else if(this.blockNodeForEnter){ + // add enter key handler + // FIXME: need to port to the new event code!! + var h = lang.hitch(this,this.handleEnterKey); + editor.addKeyHandler(13, 0, 0, h); //enter + editor.addKeyHandler(13, 0, 1, h); //shift+enter + this.connect(this.editor,'onKeyPressed','onKeyPressed'); + } + }, + onKeyPressed: function(){ + // summary: + // Handler for keypress events. + // tags: + // private + if(this._checkListLater){ + if(win.withGlobal(this.editor.window, 'isCollapsed', dijit)){ + var liparent=win.withGlobal(this.editor.window, 'getAncestorElement', selection, ['LI']); + if(!liparent){ + // circulate the undo detection code by calling RichText::execCommand directly + RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter); + // set the innerHTML of the new block node + var block = win.withGlobal(this.editor.window, 'getAncestorElement', selection, [this.blockNodeForEnter]); + if(block){ + block.innerHTML=this.bogusHtmlContent; + if(has("ie")){ + // move to the start by moving backwards one char + var r = this.editor.document.selection.createRange(); + r.move('character',-1); + r.select(); + } + }else{ + console.error('onKeyPressed: Cannot find the new block node'); // FIXME + } + }else{ + if(has("mozilla")){ + if(liparent.parentNode.parentNode.nodeName == 'LI'){ + liparent=liparent.parentNode.parentNode; + } + } + var fc=liparent.firstChild; + if(fc && fc.nodeType == 1 && (fc.nodeName == 'UL' || fc.nodeName == 'OL')){ + liparent.insertBefore(fc.ownerDocument.createTextNode('\xA0'),fc); + var newrange = rangeapi.create(this.editor.window); + newrange.setStart(liparent.firstChild,0); + var selection = rangeapi.getSelection(this.editor.window, true); + selection.removeAllRanges(); + selection.addRange(newrange); + } + } + } + this._checkListLater = false; + } + if(this._pressedEnterInBlock){ + // the new created is the original current P, so we have previousSibling below + if(this._pressedEnterInBlock.previousSibling){ + this.removeTrailingBr(this._pressedEnterInBlock.previousSibling); + } + delete this._pressedEnterInBlock; + } + }, + + // bogusHtmlContent: [private] String + // HTML to stick into a new empty block + bogusHtmlContent: ' ', // + + // blockNodes: [private] Regex + // Regex for testing if a given tag is a block level (display:block) tag + blockNodes: /^(?:P|H1|H2|H3|H4|H5|H6|LI)$/, + + handleEnterKey: function(e){ + // summary: + // Handler for enter key events when blockNodeForEnter is DIV or P. + // description: + // Manually handle enter key event to make the behavior consistent across + // all supported browsers. See class description for details. + // tags: + // private + + var selection, range, newrange, startNode, endNode, brNode, doc=this.editor.document,br,rs,txt; + if(e.shiftKey){ // shift+enter always generates <br> + var parent = win.withGlobal(this.editor.window, "getParentElement", selectionapi); + var header = rangeapi.getAncestor(parent,this.blockNodes); + if(header){ + if(header.tagName == 'LI'){ + return true; // let browser handle + } + selection = rangeapi.getSelection(this.editor.window); + range = selection.getRangeAt(0); + if(!range.collapsed){ + range.deleteContents(); + selection = rangeapi.getSelection(this.editor.window); + range = selection.getRangeAt(0); + } + if(rangeapi.atBeginningOfContainer(header, range.startContainer, range.startOffset)){ + br=doc.createElement('br'); + newrange = rangeapi.create(this.editor.window); + header.insertBefore(br,header.firstChild); + newrange.setStartAfter(br); + selection.removeAllRanges(); + selection.addRange(newrange); + }else if(rangeapi.atEndOfContainer(header, range.startContainer, range.startOffset)){ + newrange = rangeapi.create(this.editor.window); + br=doc.createElement('br'); + header.appendChild(br); + header.appendChild(doc.createTextNode('\xA0')); + newrange.setStart(header.lastChild,0); + selection.removeAllRanges(); + selection.addRange(newrange); + }else{ + rs = range.startContainer; + if(rs && rs.nodeType == 3){ + // Text node, we have to split it. + txt = rs.nodeValue; + win.withGlobal(this.editor.window, function(){ + startNode = doc.createTextNode(txt.substring(0, range.startOffset)); + endNode = doc.createTextNode(txt.substring(range.startOffset)); + brNode = doc.createElement("br"); + + if(endNode.nodeValue == "" && has("webkit")){ + endNode = doc.createTextNode('\xA0') + } + domConstruct.place(startNode, rs, "after"); + domConstruct.place(brNode, startNode, "after"); + domConstruct.place(endNode, brNode, "after"); + domConstruct.destroy(rs); + newrange = rangeapi.create(); + newrange.setStart(endNode,0); + selection.removeAllRanges(); + selection.addRange(newrange); + }); + return false; + } + return true; // let browser handle + } + }else{ + selection = rangeapi.getSelection(this.editor.window); + if(selection.rangeCount){ + range = selection.getRangeAt(0); + if(range && range.startContainer){ + if(!range.collapsed){ + range.deleteContents(); + selection = rangeapi.getSelection(this.editor.window); + range = selection.getRangeAt(0); + } + rs = range.startContainer; + if(rs && rs.nodeType == 3){ + // Text node, we have to split it. + win.withGlobal(this.editor.window, lang.hitch(this, function(){ + var endEmpty = false; + + var offset = range.startOffset; + if(rs.length < offset){ + //We are not splitting the right node, try to locate the correct one + ret = this._adjustNodeAndOffset(rs, offset); + rs = ret.node; + offset = ret.offset; + } + txt = rs.nodeValue; + + startNode = doc.createTextNode(txt.substring(0, offset)); + endNode = doc.createTextNode(txt.substring(offset)); + brNode = doc.createElement("br"); + + if(!endNode.length){ + endNode = doc.createTextNode('\xA0'); + endEmpty = true; + } + + if(startNode.length){ + domConstruct.place(startNode, rs, "after"); + }else{ + startNode = rs; + } + domConstruct.place(brNode, startNode, "after"); + domConstruct.place(endNode, brNode, "after"); + domConstruct.destroy(rs); + newrange = rangeapi.create(); + newrange.setStart(endNode,0); + newrange.setEnd(endNode, endNode.length); + selection.removeAllRanges(); + selection.addRange(newrange); + if(endEmpty && !has("webkit")){ + selectionapi.remove(); + }else{ + selectionapi.collapse(true); + } + })); + }else{ + var targetNode; + if(range.startOffset >= 0){ + targetNode = rs.childNodes[range.startOffset]; + } + win.withGlobal(this.editor.window, lang.hitch(this, function(){ + var brNode = doc.createElement("br"); + var endNode = doc.createTextNode('\xA0'); + if(!targetNode){ + rs.appendChild(brNode); + rs.appendChild(endNode); + }else{ + domConstruct.place(brNode, targetNode, "before"); + domConstruct.place(endNode, brNode, "after"); + } + newrange = rangeapi.create(win.global); + newrange.setStart(endNode,0); + newrange.setEnd(endNode, endNode.length); + selection.removeAllRanges(); + selection.addRange(newrange); + selectionapi.collapse(true); + })); + } + } + }else{ + // don't change this: do not call this.execCommand, as that may have other logic in subclass + RichText.prototype.execCommand.call(this.editor, 'inserthtml', '<br>'); + } + } + return false; + } + var _letBrowserHandle = true; + + // first remove selection + selection = rangeapi.getSelection(this.editor.window); + range = selection.getRangeAt(0); + if(!range.collapsed){ + range.deleteContents(); + selection = rangeapi.getSelection(this.editor.window); + range = selection.getRangeAt(0); + } + + var block = rangeapi.getBlockAncestor(range.endContainer, null, this.editor.editNode); + var blockNode = block.blockNode; + + // if this is under a LI or the parent of the blockNode is LI, just let browser to handle it + if((this._checkListLater = (blockNode && (blockNode.nodeName == 'LI' || blockNode.parentNode.nodeName == 'LI')))){ + if(has("mozilla")){ + // press enter in middle of P may leave a trailing <br/>, let's remove it later + this._pressedEnterInBlock = blockNode; + } + // if this li only contains spaces, set the content to empty so the browser will outdent this item + if(/^(\s| | |\xA0|<span\b[^>]*\bclass=['"]Apple-style-span['"][^>]*>(\s| | |\xA0)<\/span>)?(<br>)?$/.test(blockNode.innerHTML)){ + // empty LI node + blockNode.innerHTML = ''; + if(has("webkit")){ // WebKit tosses the range when innerHTML is reset + newrange = rangeapi.create(this.editor.window); + newrange.setStart(blockNode, 0); + selection.removeAllRanges(); + selection.addRange(newrange); + } + this._checkListLater = false; // nothing to check since the browser handles outdent + } + return true; + } + + // text node directly under body, let's wrap them in a node + if(!block.blockNode || block.blockNode===this.editor.editNode){ + try{ + RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter); + }catch(e2){ /*squelch FF3 exception bug when editor content is a single BR*/ } + // get the newly created block node + // FIXME + block = {blockNode:win.withGlobal(this.editor.window, "getAncestorElement", selectionapi, [this.blockNodeForEnter]), + blockContainer: this.editor.editNode}; + if(block.blockNode){ + if(block.blockNode != this.editor.editNode && + (!(block.blockNode.textContent || block.blockNode.innerHTML).replace(/^\s+|\s+$/g, "").length)){ + this.removeTrailingBr(block.blockNode); + return false; + } + }else{ // we shouldn't be here if formatblock worked + block.blockNode = this.editor.editNode; + } + selection = rangeapi.getSelection(this.editor.window); + range = selection.getRangeAt(0); + } + + var newblock = doc.createElement(this.blockNodeForEnter); + newblock.innerHTML=this.bogusHtmlContent; + this.removeTrailingBr(block.blockNode); + var endOffset = range.endOffset; + var node = range.endContainer; + if(node.length < endOffset){ + //We are not checking the right node, try to locate the correct one + var ret = this._adjustNodeAndOffset(node, endOffset); + node = ret.node; + endOffset = ret.offset; + } + if(rangeapi.atEndOfContainer(block.blockNode, node, endOffset)){ + if(block.blockNode === block.blockContainer){ + block.blockNode.appendChild(newblock); + }else{ + domConstruct.place(newblock, block.blockNode, "after"); + } + _letBrowserHandle = false; + // lets move caret to the newly created block + newrange = rangeapi.create(this.editor.window); + newrange.setStart(newblock, 0); + selection.removeAllRanges(); + selection.addRange(newrange); + if(this.editor.height){ + winUtils.scrollIntoView(newblock); + } + }else if(rangeapi.atBeginningOfContainer(block.blockNode, + range.startContainer, range.startOffset)){ + domConstruct.place(newblock, block.blockNode, block.blockNode === block.blockContainer ? "first" : "before"); + if(newblock.nextSibling && this.editor.height){ + // position input caret - mostly WebKit needs this + newrange = rangeapi.create(this.editor.window); + newrange.setStart(newblock.nextSibling, 0); + selection.removeAllRanges(); + selection.addRange(newrange); + // browser does not scroll the caret position into view, do it manually + winUtils.scrollIntoView(newblock.nextSibling); + } + _letBrowserHandle = false; + }else{ //press enter in the middle of P/DIV/Whatever/ + if(block.blockNode === block.blockContainer){ + block.blockNode.appendChild(newblock); + }else{ + domConstruct.place(newblock, block.blockNode, "after"); + } + _letBrowserHandle = false; + + // Clone any block level styles. + if(block.blockNode.style){ + if(newblock.style){ + if(block.blockNode.style.cssText){ + newblock.style.cssText = block.blockNode.style.cssText; + } + } + } + + // Okay, we probably have to split. + rs = range.startContainer; + var firstNodeMoved; + if(rs && rs.nodeType == 3){ + // Text node, we have to split it. + var nodeToMove, tNode; + endOffset = range.endOffset; + if(rs.length < endOffset){ + //We are not splitting the right node, try to locate the correct one + ret = this._adjustNodeAndOffset(rs, endOffset); + rs = ret.node; + endOffset = ret.offset; + } + + txt = rs.nodeValue; + startNode = doc.createTextNode(txt.substring(0, endOffset)); + endNode = doc.createTextNode(txt.substring(endOffset, txt.length)); + + // Place the split, then remove original nodes. + domConstruct.place(startNode, rs, "before"); + domConstruct.place(endNode, rs, "after"); + domConstruct.destroy(rs); + + // Okay, we split the text. Now we need to see if we're + // parented to the block element we're splitting and if + // not, we have to split all the way up. Ugh. + var parentC = startNode.parentNode; + while(parentC !== block.blockNode){ + var tg = parentC.tagName; + var newTg = doc.createElement(tg); + // Clone over any 'style' data. + if(parentC.style){ + if(newTg.style){ + if(parentC.style.cssText){ + newTg.style.cssText = parentC.style.cssText; + } + } + } + // If font also need to clone over any font data. + if(parentC.tagName === "FONT"){ + if(parentC.color){ + newTg.color = parentC.color; + } + if(parentC.face){ + newTg.face = parentC.face; + } + if(parentC.size){ // this check was necessary on IE + newTg.size = parentC.size; + } + } + + nodeToMove = endNode; + while(nodeToMove){ + tNode = nodeToMove.nextSibling; + newTg.appendChild(nodeToMove); + nodeToMove = tNode; + } + domConstruct.place(newTg, parentC, "after"); + startNode = parentC; + endNode = newTg; + parentC = parentC.parentNode; + } + + // Lastly, move the split out tags to the new block. + // as they should now be split properly. + nodeToMove = endNode; + if(nodeToMove.nodeType == 1 || (nodeToMove.nodeType == 3 && nodeToMove.nodeValue)){ + // Non-blank text and non-text nodes need to clear out that blank space + // before moving the contents. + newblock.innerHTML = ""; + } + firstNodeMoved = nodeToMove; + while(nodeToMove){ + tNode = nodeToMove.nextSibling; + newblock.appendChild(nodeToMove); + nodeToMove = tNode; + } + } + + //lets move caret to the newly created block + newrange = rangeapi.create(this.editor.window); + var nodeForCursor; + var innerMostFirstNodeMoved = firstNodeMoved; + if(this.blockNodeForEnter !== 'BR'){ + while(innerMostFirstNodeMoved){ + nodeForCursor = innerMostFirstNodeMoved; + tNode = innerMostFirstNodeMoved.firstChild; + innerMostFirstNodeMoved = tNode; + } + if(nodeForCursor && nodeForCursor.parentNode){ + newblock = nodeForCursor.parentNode; + newrange.setStart(newblock, 0); + selection.removeAllRanges(); + selection.addRange(newrange); + if(this.editor.height){ + winUtils.scrollIntoView(newblock); + } + if(has("mozilla")){ + // press enter in middle of P may leave a trailing <br/>, let's remove it later + this._pressedEnterInBlock = block.blockNode; + } + }else{ + _letBrowserHandle = true; + } + }else{ + newrange.setStart(newblock, 0); + selection.removeAllRanges(); + selection.addRange(newrange); + if(this.editor.height){ + winUtils.scrollIntoView(newblock); + } + if(has("mozilla")){ + // press enter in middle of P may leave a trailing <br/>, let's remove it later + this._pressedEnterInBlock = block.blockNode; + } + } + } + return _letBrowserHandle; + }, + + _adjustNodeAndOffset: function(/*DomNode*/node, /*Int*/offset){ + // summary: + // In the case there are multiple text nodes in a row the offset may not be within the node. If the offset is larger than the node length, it will attempt to find + // the next text sibling until it locates the text node in which the offset refers to + // node: + // The node to check. + // offset: + // The position to find within the text node + // tags: + // private. + while(node.length < offset && node.nextSibling && node.nextSibling.nodeType==3){ + //Adjust the offset and node in the case of multiple text nodes in a row + offset = offset - node.length; + node = node.nextSibling; + } + return {"node": node, "offset": offset}; + }, + + removeTrailingBr: function(container){ + // summary: + // If last child of container is a <br>, then remove it. + // tags: + // private + var para = /P|DIV|LI/i.test(container.tagName) ? + container : selectionapi.getParentOfType(container,['P','DIV','LI']); + + if(!para){ return; } + if(para.lastChild){ + if((para.childNodes.length > 1 && para.lastChild.nodeType == 3 && /^[\s\xAD]*$/.test(para.lastChild.nodeValue)) || + para.lastChild.tagName=='BR'){ + + domConstruct.destroy(para.lastChild); + } + } + if(!para.childNodes.length){ + para.innerHTML=this.bogusHtmlContent; + } + } +}); + +}); diff --git a/js/dojo/dijit/_editor/plugins/FontChoice.js b/js/dojo/dijit/_editor/plugins/FontChoice.js new file mode 100644 index 0000000..22d01dc --- /dev/null +++ b/js/dojo/dijit/_editor/plugins/FontChoice.js @@ -0,0 +1,592 @@ +//>>built +define("dijit/_editor/plugins/FontChoice", [ + "dojo/_base/array", // array.indexOf array.map + "dojo/_base/declare", // declare + "dojo/dom-construct", // domConstruct.place + "dojo/i18n", // i18n.getLocalization + "dojo/_base/lang", // lang.delegate lang.hitch lang.isString + "dojo/store/Memory", // MemoryStore + "dojo/_base/window", // win.withGlobal + "../../registry", // registry.getUniqueId + "../../_Widget", + "../../_TemplatedMixin", + "../../_WidgetsInTemplateMixin", + "../../form/FilteringSelect", + "../_Plugin", + "../range", + "../selection", + "dojo/i18n!../nls/FontChoice" +], function(array, declare, domConstruct, i18n, lang, MemoryStore, win, + registry, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin, FilteringSelect, _Plugin, rangeapi, selectionapi){ + +/*===== + var _Plugin = dijit._editor._Plugin; + var _Widget = dijit._Widget; + var _TemplatedMixin = dijit._TemplatedMixin; + var _WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin; + var FilteringSelect = dijit.form.FilteringSelect; +=====*/ + + +// module: +// dijit/_editor/plugins/FontChoice +// summary: +// fontchoice, fontsize, and formatblock editor plugins + + +var _FontDropDown = declare("dijit._editor.plugins._FontDropDown", + [_Widget, _TemplatedMixin, _WidgetsInTemplateMixin], { + // summary: + // Base class for widgets that contains a label (like "Font:") + // and a FilteringSelect drop down to pick a value. + // Used as Toolbar entry. + + // label: [public] String + // The label to apply to this particular FontDropDown. + label: "", + + // plainText: [public] boolean + // Flag to indicate that the returned label should be plain text + // instead of an example. + plainText: false, + + // templateString: [public] String + // The template used to construct the labeled dropdown. + templateString: + "<span style='white-space: nowrap' class='dijit dijitReset dijitInline'>" + + "<label class='dijitLeft dijitInline' for='${selectId}'>${label}</label>" + + "<input data-dojo-type='dijit.form.FilteringSelect' required='false' " + + "data-dojo-props='labelType:\"html\", labelAttr:\"label\", searchAttr:\"name\"' " + + "tabIndex='-1' id='${selectId}' data-dojo-attach-point='select' value=''/>" + + "</span>", + + postMixInProperties: function(){ + // summary: + // Over-ride to set specific properties. + this.inherited(arguments); + + this.strings = i18n.getLocalization("dijit._editor", "FontChoice"); + + // Set some substitution variables used in the template + this.label = this.strings[this.command]; + this.id = registry.getUniqueId(this.declaredClass.replace(/\./g,"_")); // TODO: unneeded?? + this.selectId = this.id + "_select"; // used in template + + this.inherited(arguments); + }, + + postCreate: function(){ + // summary: + // Over-ride for the default postCreate action + // This establishes the filtering selects and the like. + + // Initialize the list of items in the drop down by creating data store with items like: + // {value: 1, name: "xx-small", label: "<font size=1>xx-small</font-size>" } + this.select.set("store", new MemoryStore({ + idProperty: "value", + data: array.map(this.values, function(value){ + var name = this.strings[value] || value; + return { + label: this.getLabel(value, name), + name: name, + value: value + }; + }, this) + })); + + this.select.set("value", "", false); + this.disabled = this.select.get("disabled"); + }, + + _setValueAttr: function(value, priorityChange){ + // summary: + // Over-ride for the default action of setting the + // widget value, maps the input to known values + // value: Object|String + // The value to set in the select. + // priorityChange: + // Optional parameter used to tell the select whether or not to fire + // onChange event. + + // if the value is not a permitted value, just set empty string to prevent showing the warning icon + priorityChange = priorityChange !== false; + this.select.set('value', array.indexOf(this.values,value) < 0 ? "" : value, priorityChange); + if(!priorityChange){ + // Clear the last state in case of updateState calls. Ref: #10466 + this.select._lastValueReported=null; + } + }, + + _getValueAttr: function(){ + // summary: + // Allow retrieving the value from the composite select on + // call to button.get("value"); + return this.select.get('value'); + }, + + focus: function(){ + // summary: + // Over-ride for focus control of this widget. Delegates focus down to the + // filtering select. + this.select.focus(); + }, + + _setDisabledAttr: function(value){ + // summary: + // Over-ride for the button's 'disabled' attribute so that it can be + // disabled programmatically. + + // Save off ths disabled state so the get retrieves it correctly + //without needing to have a function proxy it. + this.disabled = value; + this.select.set("disabled", value); + } +}); + + +var _FontNameDropDown = declare("dijit._editor.plugins._FontNameDropDown", _FontDropDown, { + // summary: + // Dropdown to select a font; goes in editor toolbar. + + // generic: Boolean + // Use generic (web standard) font names + generic: false, + + // command: [public] String + // The editor 'command' implemented by this plugin. + command: "fontName", + + postMixInProperties: function(){ + // summary: + // Over-ride for the default posr mixin control + if(!this.values){ + this.values = this.generic ? + ["serif", "sans-serif", "monospace", "cursive", "fantasy"] : // CSS font-family generics + ["Arial", "Times New Roman", "Comic Sans MS", "Courier New"]; + } + this.inherited(arguments); + }, + + getLabel: function(value, name){ + // summary: + // Function used to generate the labels of the format dropdown + // will return a formatted, or plain label based on the value + // of the plainText option. + // value: String + // The 'insert value' associated with a name + // name: String + // The text name of the value + if(this.plainText){ + return name; + }else{ + return "<div style='font-family: "+value+"'>" + name + "</div>"; + } + }, + + _setValueAttr: function(value, priorityChange){ + // summary: + // Over-ride for the default action of setting the + // widget value, maps the input to known values + + priorityChange = priorityChange !== false; + if(this.generic){ + var map = { + "Arial": "sans-serif", + "Helvetica": "sans-serif", + "Myriad": "sans-serif", + "Times": "serif", + "Times New Roman": "serif", + "Comic Sans MS": "cursive", + "Apple Chancery": "cursive", + "Courier": "monospace", + "Courier New": "monospace", + "Papyrus": "fantasy", + "Estrangelo Edessa": "cursive", // Windows 7 + "Gabriola": "fantasy" // Windows 7 + }; + value = map[value] || value; + } + this.inherited(arguments, [value, priorityChange]); + } +}); + +var _FontSizeDropDown = declare("dijit._editor.plugins._FontSizeDropDown", _FontDropDown, { + // summary: + // Dropdown to select a font size; goes in editor toolbar. + + // command: [public] String + // The editor 'command' implemented by this plugin. + command: "fontSize", + + // values: [public] Number[] + // The HTML font size values supported by this plugin + values: [1,2,3,4,5,6,7], // sizes according to the old HTML FONT SIZE + + getLabel: function(value, name){ + // summary: + // Function used to generate the labels of the format dropdown + // will return a formatted, or plain label based on the value + // of the plainText option. + // We're stuck using the deprecated FONT tag to correspond + // with the size measurements used by the editor + // value: String + // The 'insert value' associated with a name + // name: String + // The text name of the value + if(this.plainText){ + return name; + }else{ + return "<font size=" + value + "'>" + name + "</font>"; + } + }, + + _setValueAttr: function(value, priorityChange){ + // summary: + // Over-ride for the default action of setting the + // widget value, maps the input to known values + priorityChange = priorityChange !== false; + if(value.indexOf && value.indexOf("px") != -1){ + var pixels = parseInt(value, 10); + value = {10:1, 13:2, 16:3, 18:4, 24:5, 32:6, 48:7}[pixels] || value; + } + + this.inherited(arguments, [value, priorityChange]); + } +}); + + +var _FormatBlockDropDown = declare("dijit._editor.plugins._FormatBlockDropDown", _FontDropDown, { + // summary: + // Dropdown to select a format (like paragraph or heading); goes in editor toolbar. + + // command: [public] String + // The editor 'command' implemented by this plugin. + command: "formatBlock", + + // values: [public] Array + // The HTML format tags supported by this plugin + values: ["noFormat", "p", "h1", "h2", "h3", "pre"], + + postCreate: function(){ + // Init and set the default value to no formatting. Update state will adjust it + // as needed. + this.inherited(arguments); + this.set("value", "noFormat", false); + }, + + getLabel: function(value, name){ + // summary: + // Function used to generate the labels of the format dropdown + // will return a formatted, or plain label based on the value + // of the plainText option. + // value: String + // The 'insert value' associated with a name + // name: String + // The text name of the value + if(this.plainText || value == "noFormat"){ + return name; + }else{ + return "<" + value + ">" + name + "</" + value + ">"; + } + }, + + _execCommand: function(editor, command, choice){ + // summary: + // Over-ride for default exec-command label. + // Allows us to treat 'none' as special. + if(choice === "noFormat"){ + var start; + var end; + var sel = rangeapi.getSelection(editor.window); + if(sel && sel.rangeCount > 0){ + var range = sel.getRangeAt(0); + var node, tag; + if(range){ + start = range.startContainer; + end = range.endContainer; + + // find containing nodes of start/end. + while(start && start !== editor.editNode && + start !== editor.document.body && + start.nodeType !== 1){ + start = start.parentNode; + } + + while(end && end !== editor.editNode && + end !== editor.document.body && + end.nodeType !== 1){ + end = end.parentNode; + } + + var processChildren = lang.hitch(this, function(node, ary){ + if(node.childNodes && node.childNodes.length){ + var i; + for(i = 0; i < node.childNodes.length; i++){ + var c = node.childNodes[i]; + if(c.nodeType == 1){ + if(win.withGlobal(editor.window, "inSelection", selectionapi, [c])){ + var tag = c.tagName? c.tagName.toLowerCase(): ""; + if(array.indexOf(this.values, tag) !== -1){ + ary.push(c); + } + processChildren(c, ary); + } + } + } + } + }); + + var unformatNodes = lang.hitch(this, function(nodes){ + // summary: + // Internal function to clear format nodes. + // nodes: + // The array of nodes to strip formatting from. + if(nodes && nodes.length){ + editor.beginEditing(); + while(nodes.length){ + this._removeFormat(editor, nodes.pop()); + } + editor.endEditing(); + } + }); + + var clearNodes = []; + if(start == end){ + //Contained within the same block, may be collapsed, but who cares, see if we + // have a block element to remove. + var block; + node = start; + while(node && node !== editor.editNode && node !== editor.document.body){ + if(node.nodeType == 1){ + tag = node.tagName? node.tagName.toLowerCase(): ""; + if(array.indexOf(this.values, tag) !== -1){ + block = node; + break; + } + } + node = node.parentNode; + } + + //Also look for all child nodes in the selection that may need to be + //cleared of formatting + processChildren(start, clearNodes); + if(block){ clearNodes = [block].concat(clearNodes); } + unformatNodes(clearNodes); + }else{ + // Probably a multi select, so we have to process it. Whee. + node = start; + while(win.withGlobal(editor.window, "inSelection", selectionapi, [node])){ + if(node.nodeType == 1){ + tag = node.tagName? node.tagName.toLowerCase(): ""; + if(array.indexOf(this.values, tag) !== -1){ + clearNodes.push(node); + } + processChildren(node,clearNodes); + } + node = node.nextSibling; + } + unformatNodes(clearNodes); + } + editor.onDisplayChanged(); + } + } + }else{ + editor.execCommand(command, choice); + } + }, + + _removeFormat: function(editor, node){ + // summary: + // function to remove the block format node. + // node: + // The block format node to remove (and leave the contents behind) + if(editor.customUndo){ + // So of course IE doesn't work right with paste-overs. + // We have to do this manually, which is okay since IE already uses + // customUndo and we turned it on for WebKit. WebKit pasted funny, + // so couldn't use the execCommand approach + while(node.firstChild){ + domConstruct.place(node.firstChild, node, "before"); + } + node.parentNode.removeChild(node); + }else{ + // Everyone else works fine this way, a paste-over and is native + // undo friendly. + win.withGlobal(editor.window, + "selectElementChildren", selectionapi, [node]); + var html = win.withGlobal(editor.window, + "getSelectedHtml", selectionapi, [null]); + win.withGlobal(editor.window, + "selectElement", selectionapi, [node]); + editor.execCommand("inserthtml", html||""); + } + } +}); + +// TODO: for 2.0, split into FontChoice plugin into three separate classes, +// one for each command (and change registry below) +var FontChoice = declare("dijit._editor.plugins.FontChoice", _Plugin,{ + // summary: + // This plugin provides three drop downs for setting style in the editor + // (font, font size, and format block), as controlled by command. + // + // description: + // The commands provided by this plugin are: + // + // * fontName + // | Provides a drop down to select from a list of font names + // * fontSize + // | Provides a drop down to select from a list of font sizes + // * formatBlock + // | Provides a drop down to select from a list of block styles + // | + // + // which can easily be added to an editor by including one or more of the above commands + // in the `plugins` attribute as follows: + // + // | plugins="['fontName','fontSize',...]" + // + // It is possible to override the default dropdown list by providing an Array for the `custom` property when + // instantiating this plugin, e.g. + // + // | plugins="[{name:'dijit._editor.plugins.FontChoice', command:'fontName', custom:['Verdana','Myriad','Garamond']},...]" + // + // Alternatively, for `fontName` only, `generic:true` may be specified to provide a dropdown with + // [CSS generic font families](http://www.w3.org/TR/REC-CSS2/fonts.html#generic-font-families) + // + // Note that the editor is often unable to properly handle font styling information defined outside + // the context of the current editor instance, such as pre-populated HTML. + + // useDefaultCommand: [protected] Boolean + // Override _Plugin.useDefaultCommand... + // processing is handled by this plugin, not by dijit.Editor. + useDefaultCommand: false, + + _initButton: function(){ + // summary: + // Overrides _Plugin._initButton(), to initialize the FilteringSelect+label in toolbar, + // rather than a simple button. + // tags: + // protected + + // Create the widget to go into the toolbar (the so-called "button") + var clazz = { + fontName: _FontNameDropDown, + fontSize: _FontSizeDropDown, + formatBlock: _FormatBlockDropDown + }[this.command], + params = this.params; + + // For back-compat reasons support setting custom values via "custom" parameter + // rather than "values" parameter + if(this.params.custom){ + params.values = this.params.custom; + } + + var editor = this.editor; + this.button = new clazz(lang.delegate({dir: editor.dir, lang: editor.lang}, params)); + + // Reflect changes to the drop down in the editor + this.connect(this.button.select, "onChange", function(choice){ + // User invoked change, since all internal updates set priorityChange to false and will + // not trigger an onChange event. + this.editor.focus(); + + if(this.command == "fontName" && choice.indexOf(" ") != -1){ choice = "'" + choice + "'"; } + + // Invoke, the editor already normalizes commands called through its + // execCommand. + if(this.button._execCommand){ + this.button._execCommand(this.editor, this.command, choice); + }else{ + this.editor.execCommand(this.command, choice); + } + }); + }, + + updateState: function(){ + // summary: + // Overrides _Plugin.updateState(). This controls updating the menu + // options to the right values on state changes in the document (that trigger a + // test of the actions.) + // It set value of drop down in toolbar to reflect font/font size/format block + // of text at current caret position. + // tags: + // protected + var _e = this.editor; + var _c = this.command; + if(!_e || !_e.isLoaded || !_c.length){ return; } + + if(this.button){ + var disabled = this.get("disabled"); + this.button.set("disabled", disabled); + if(disabled){ return; } + var value; + try{ + value = _e.queryCommandValue(_c) || ""; + }catch(e){ + //Firefox may throw error above if the editor is just loaded, ignore it + value = ""; + } + + // strip off single quotes, if any + var quoted = lang.isString(value) && value.match(/'([^']*)'/); + if(quoted){ value = quoted[1]; } + + if(_c === "formatBlock"){ + if(!value || value == "p"){ + // Some browsers (WebKit) doesn't actually get the tag info right. + // and IE returns paragraph when in a DIV!, so incorrect a lot, + // so we have double-check it. + value = null; + var elem; + // Try to find the current element where the caret is. + var sel = rangeapi.getSelection(this.editor.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 !== _e.editNode && elem !== _e.document){ + var tg = elem.tagName?elem.tagName.toLowerCase():""; + if(tg && array.indexOf(this.button.values, tg) > -1){ + value = tg; + break; + } + elem = elem.parentNode; + } + if(!value){ + // Still no value, so lets select 'none'. + value = "noFormat"; + } + }else{ + // Check that the block format is one allowed, if not, + // null it so that it gets set to empty. + if(array.indexOf(this.button.values, value) < 0){ + value = "noFormat"; + } + } + } + if(value !== this.button.get("value")){ + // Set the value, but denote it is not a priority change, so no + // onchange fires. + this.button.set('value', value, false); + } + } + } +}); + +// Register these plugins +array.forEach(["fontName", "fontSize", "formatBlock"], function(name){ + _Plugin.registry[name] = function(args){ + return new FontChoice({ + command: name, + plainText: args.plainText + }); + }; +}); + +}); diff --git a/js/dojo/dijit/_editor/plugins/FullScreen.js b/js/dojo/dijit/_editor/plugins/FullScreen.js new file mode 100644 index 0000000..bb77cd6 --- /dev/null +++ b/js/dojo/dijit/_editor/plugins/FullScreen.js @@ -0,0 +1,458 @@ +//>>built +define("dijit/_editor/plugins/FullScreen", [ + "dojo/aspect", + "dojo/_base/declare", // declare + "dojo/dom-class", // domClass.add domClass.remove + "dojo/dom-geometry", + "dojo/dom-style", + "dojo/_base/event", // event.stop + "dojo/i18n", // i18n.getLocalization + "dojo/keys", // keys.F11 keys.TAB + "dojo/_base/lang", // lang.hitch + "dojo/on", // on() + "dojo/_base/sniff", // has("ie"), has("quirks") + "dojo/_base/window", // win.body + "dojo/window", // winUtils.getBox winUtils.scrollIntoView + "../../focus", // focus.focus(), focus.curNode + "../_Plugin", + "../../form/ToggleButton", + "../../registry", // registry.getEnclosingWidget() + "dojo/i18n!../nls/commands" +], function(aspect, declare, domClass, domGeometry, domStyle, event, i18n, keys, lang, on, has, win, winUtils, + focus, _Plugin, ToggleButton, registry){ + +/*===== + var _Plugin = dijit._editor._Plugin; +=====*/ + + +// module: +// dijit/_editor/plugins/FullScreen +// summary: +// This plugin provides FullScreen capability to the editor. When +// toggled on, it will render the editor into the full window and +// overlay everything. It also binds to the hotkey: CTRL-SHIFT-F11 +// for toggling fullscreen mode. + + +var FullScreen = declare("dijit._editor.plugins.FullScreen",_Plugin,{ + // summary: + // This plugin provides FullScreen capability to the editor. When + // toggled on, it will render the editor into the full window and + // overlay everything. It also binds to the hotkey: CTRL-SHIFT-F11 + // for toggling fullscreen mode. + + // zIndex: [public] Number + // zIndex value used for overlaying the full page. + // default is 500. + zIndex: 500, + + // _origState: [private] Object + // The original view state of the editor. + _origState: null, + + // _origiFrameState: [private] Object + // The original view state of the iframe of the editor. + _origiFrameState: null, + + // _resizeHandle: [private] Object + // Connection point used for handling resize when window resizes. + _resizeHandle: null, + + // isFullscreen: [const] boolean + // Read-Only variable used to denote of the editor is in fullscreen mode or not. + isFullscreen: false, + + toggle: function(){ + // summary: + // Function to allow programmatic toggling of the view. + this.button.set("checked", !this.button.get("checked")); + }, + + _initButton: function(){ + // summary: + // Over-ride for creation of the resize button. + var strings = i18n.getLocalization("dijit._editor", "commands"), + editor = this.editor; + this.button = new ToggleButton({ + label: strings["fullScreen"], + dir: editor.dir, + lang: editor.lang, + showLabel: false, + iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "FullScreen", + tabIndex: "-1", + onChange: lang.hitch(this, "_setFullScreen") + }); + }, + + 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.editor.addKeyHandler(keys.F11, true, true, lang.hitch(this, function(e){ + // Enable the CTRL-SHIFT-F11 hotkey for fullscreen mode. + this.toggle(); + event.stop(e); + setTimeout(lang.hitch(this, function(){this.editor.focus();}), 250); + return true; + })); + this.connect(this.editor.domNode, "onkeydown", "_containFocus"); + }, + + _containFocus: function(e){ + // summary: + // When in Full Screen mode, it's good to try and retain focus in the editor + // so this function is intended to try and constrain the TAB key. + // e: Event + // The key event. + // tags: + // private + if(this.isFullscreen){ + var ed = this.editor; + if(!ed.isTabIndent && + ed._fullscreen_oldOnKeyDown && + e.keyCode === keys.TAB){ + // If we're in fullscreen mode, we want to take over how tab moves focus a bit. + // to keep it within the editor since it's hiding the rest of the page. + // IE hates changing focus IN the event handler, so need to put calls + // in a timeout. Gotta love IE. + // Also need to check for alternate view nodes if present and active. + var f = focus.curNode; + var avn = this._getAltViewNode(); + if(f == ed.iframe || + (avn && f === avn)){ + setTimeout(lang.hitch(this, function(){ + ed.toolbar.focus(); + }), 10); + }else{ + if(avn && domStyle.get(ed.iframe, "display") === "none"){ + setTimeout(lang.hitch(this, function(){ + focus.focus(avn); + }), 10); + }else{ + setTimeout(lang.hitch(this, function(){ + ed.focus(); + }), 10); + } + } + event.stop(e); + }else if(ed._fullscreen_oldOnKeyDown){ + // Only call up when it's a different function. Traps corner case event issue + // on IE which caused stack overflow on handler cleanup. + ed._fullscreen_oldOnKeyDown(e); + } + } + }, + + _resizeEditor: function(){ + // summary: + // Function to handle resizing the editor as the viewport + // resizes (window scaled) + // tags: + // private + var vp = winUtils.getBox(); + domGeometry.setMarginBox(this.editor.domNode, { + w: vp.w, + h: vp.h + }); + + //Adjust the internal heights too, as they can be a bit off. + var hHeight = this.editor.getHeaderHeight(); + var fHeight = this.editor.getFooterHeight(); + var extents = domGeometry.getPadBorderExtents(this.editor.domNode); + var fcpExtents = domGeometry.getPadBorderExtents(this.editor.iframe.parentNode); + var fcmExtents = domGeometry.getMarginExtents(this.editor.iframe.parentNode); + + var cHeight = vp.h - (hHeight + extents.h + fHeight); + domGeometry.setMarginBox(this.editor.iframe.parentNode, { + h: cHeight, + w: vp.w + }); + domGeometry.setMarginBox(this.editor.iframe, { + h: cHeight - (fcpExtents.h + fcmExtents.h) + }); + }, + + _getAltViewNode: function(){ + // summary: + // This function is intended as a hook point for setting an + // alternate view node for when in full screen mode and the + // editable iframe is hidden. + // tags: + // protected. + }, + + _setFullScreen: function(full){ + // summary: + // Function to handle toggling between full screen and + // regular view. + // tags: + // private + var vp = winUtils.getBox(); + + //Alias this for shorter code. + var ed = this.editor; + var body = win.body(); + var editorParent = ed.domNode.parentNode; + + this.isFullscreen = full; + + if(full){ + //Parent classes can royally screw up this plugin, so we + //have to set everything to position static. + while(editorParent && editorParent !== win.body()){ + domClass.add(editorParent, "dijitForceStatic"); + editorParent = editorParent.parentNode; + } + + // Save off the resize function. We want to kill its behavior. + this._editorResizeHolder = this.editor.resize; + ed.resize = function(){} ; + + // Try to constrain focus control. + ed._fullscreen_oldOnKeyDown = ed.onKeyDown; + ed.onKeyDown = lang.hitch(this, this._containFocus); + + this._origState = {}; + this._origiFrameState = {}; + + // Store the basic editor state we have to restore later. + // Not using domStyle.get here, had problems, didn't + // give me stuff like 100%, gave me pixel calculated values. + // Need the exact original values. + var domNode = ed.domNode, + rawStyle = domNode && domNode.style || {}; + this._origState = { + width: rawStyle.width || "", + height: rawStyle.height || "", + top: domStyle.get(domNode, "top") || "", + left: domStyle.get(domNode, "left") || "", + position: domStyle.get(domNode, "position") || "static", + marginBox: domGeometry.getMarginBox(ed.domNode) + }; + + // Store the iframe state we have to restore later. + // Not using domStyle.get here, had problems, didn't + // give me stuff like 100%, gave me pixel calculated values. + // Need the exact original values. + var iframe = ed.iframe, + iframeStyle = iframe && iframe.style || {}; + + var bc = domStyle.get(ed.iframe, "backgroundColor"); + this._origiFrameState = { + backgroundColor: bc || "transparent", + width: iframeStyle.width || "auto", + height: iframeStyle.height || "auto", + zIndex: iframeStyle.zIndex || "" + }; + + // Okay, size everything. + domStyle.set(ed.domNode, { + position: "absolute", + top: "0px", + left: "0px", + zIndex: this.zIndex, + width: vp.w + "px", + height: vp.h + "px" + }); + + domStyle.set(ed.iframe, { + height: "100%", + width: "100%", + zIndex: this.zIndex, + backgroundColor: bc !== "transparent" && + bc !== "rgba(0, 0, 0, 0)"?bc:"white" + }); + + domStyle.set(ed.iframe.parentNode, { + height: "95%", + width: "100%" + }); + + // Store the overflow state we have to restore later. + // IE had issues, so have to check that it's defined. Ugh. + if(body.style && body.style.overflow){ + this._oldOverflow = domStyle.get(body, "overflow"); + }else{ + this._oldOverflow = ""; + } + + if(has("ie") && !has("quirks")){ + // IE will put scrollbars in anyway, html (parent of body) + // also controls them in standards mode, so we have to + // remove them, argh. + if(body.parentNode && + body.parentNode.style && + body.parentNode.style.overflow){ + this._oldBodyParentOverflow = body.parentNode.style.overflow; + }else{ + try{ + this._oldBodyParentOverflow = domStyle.get(body.parentNode, "overflow"); + }catch(e){ + this._oldBodyParentOverflow = "scroll"; + } + } + domStyle.set(body.parentNode, "overflow", "hidden"); + } + domStyle.set(body, "overflow", "hidden"); + + var resizer = function(){ + // function to handle resize events. + // Will check current VP and only resize if + // different. + var vp = winUtils.getBox(); + if("_prevW" in this && "_prevH" in this){ + // No actual size change, ignore. + if(vp.w === this._prevW && vp.h === this._prevH){ + return; + } + }else{ + this._prevW = vp.w; + this._prevH = vp.h; + } + if(this._resizer){ + clearTimeout(this._resizer); + delete this._resizer; + } + // Timeout it to help avoid spamming resize on IE. + // Works for all browsers. + this._resizer = setTimeout(lang.hitch(this, function(){ + delete this._resizer; + this._resizeEditor(); + }), 10); + }; + this._resizeHandle = on(window, "resize", lang.hitch(this, resizer)); + + // Also monitor for direct calls to resize and adapt editor. + this._resizeHandle2 = aspect.after(ed, "onResize", lang.hitch(this, function(){ + if(this._resizer){ + clearTimeout(this._resizer); + delete this._resizer; + } + this._resizer = setTimeout(lang.hitch(this, function(){ + delete this._resizer; + this._resizeEditor(); + }), 10); + })); + + // Call it once to work around IE glitchiness. Safe for other browsers too. + this._resizeEditor(); + var dn = this.editor.toolbar.domNode; + setTimeout(function(){winUtils.scrollIntoView(dn);}, 250); + }else{ + if(this._resizeHandle){ + // Cleanup resizing listeners + this._resizeHandle.remove(); + this._resizeHandle = null; + } + if(this._resizeHandle2){ + // Cleanup resizing listeners + this._resizeHandle2.remove(); + this._resizeHandle2 = null; + } + if(this._rst){ + clearTimeout(this._rst); + this._rst = null; + } + + //Remove all position static class assigns. + while(editorParent && editorParent !== win.body()){ + domClass.remove(editorParent, "dijitForceStatic"); + editorParent = editorParent.parentNode; + } + + // Restore resize function + if(this._editorResizeHolder){ + this.editor.resize = this._editorResizeHolder; + } + + if(!this._origState && !this._origiFrameState){ + // If we actually didn't toggle, then don't do anything. + return; + } + if(ed._fullscreen_oldOnKeyDown){ + ed.onKeyDown = ed._fullscreen_oldOnKeyDown; + delete ed._fullscreen_oldOnKeyDown; + } + + // Add a timeout to make sure we don't have a resize firing in the + // background at the time of minimize. + var self = this; + setTimeout(function(){ + // Restore all the editor state. + var mb = self._origState.marginBox; + var oh = self._origState.height; + if(has("ie") && !has("quirks")){ + body.parentNode.style.overflow = self._oldBodyParentOverflow; + delete self._oldBodyParentOverflow; + } + domStyle.set(body, "overflow", self._oldOverflow); + delete self._oldOverflow; + + domStyle.set(ed.domNode, self._origState); + domStyle.set(ed.iframe.parentNode, { + height: "", + width: "" + }); + domStyle.set(ed.iframe, self._origiFrameState); + delete self._origState; + delete self._origiFrameState; + // In case it is contained in a layout and the layout changed size, + // go ahead and call resize. + var pWidget = registry.getEnclosingWidget(ed.domNode.parentNode); + if(pWidget && pWidget.resize){ + pWidget.resize(); + }else{ + if(!oh || oh.indexOf("%") < 0){ + // Resize if the original size wasn't set + // or wasn't in percent. Timeout is to avoid + // an IE crash in unit testing. + setTimeout(lang.hitch(this, function(){ed.resize({h: mb.h});}), 0); + } + } + winUtils.scrollIntoView(self.editor.toolbar.domNode); + }, 100); + } + }, + + updateState: function(){ + // summary: + // Over-ride for button state control for disabled to work. + this.button.set("disabled", this.get("disabled")); + }, + + destroy: function(){ + // summary: + // Over-ride to ensure the resize handle gets cleaned up. + if(this._resizeHandle){ + // Cleanup resizing listeners + this._resizeHandle.remove(); + this._resizeHandle = null; + } + if(this._resizeHandle2){ + // Cleanup resizing listeners + this._resizeHandle2.remove(); + this._resizeHandle2 = null; + } + if(this._resizer){ + clearTimeout(this._resizer); + this._resizer = null; + } + this.inherited(arguments); + } +}); + +// Register this plugin. +// For back-compat accept "fullscreen" (all lowercase) too, remove in 2.0 +_Plugin.registry["fullScreen"] = _Plugin.registry["fullscreen"] = function(args){ + return new FullScreen({ + zIndex: ("zIndex" in args)?args.zIndex:500 + }); +}; + +return FullScreen; +}); diff --git a/js/dojo/dijit/_editor/plugins/LinkDialog.js b/js/dojo/dijit/_editor/plugins/LinkDialog.js new file mode 100644 index 0000000..3be832e --- /dev/null +++ b/js/dojo/dijit/_editor/plugins/LinkDialog.js @@ -0,0 +1,587 @@ +//>>built +define("dijit/_editor/plugins/LinkDialog", [ + "require", + "dojo/_base/declare", // declare + "dojo/dom-attr", // domAttr.get + "dojo/keys", // keys.ENTER + "dojo/_base/lang", // lang.delegate lang.hitch lang.trim + "dojo/_base/sniff", // has("ie") + "dojo/string", // string.substitute + "dojo/_base/window", // win.withGlobal + "../../_Widget", + "../_Plugin", + "../../form/DropDownButton", + "../range", + "../selection" +], function(require, declare, domAttr, keys, lang, has, string, win, + _Widget, _Plugin, DropDownButton, rangeapi, selectionapi){ + +/*===== + var _Plugin = dijit._editor._Plugin; +=====*/ + +// module: +// dijit/_editor/plugins/LinkDialog +// summary: +// Editor plugins: LinkDialog (for inserting links) and ImgLinkDialog (for inserting images) + + +var LinkDialog = declare("dijit._editor.plugins.LinkDialog", _Plugin, { + // summary: + // This plugin provides the basis for an 'anchor' (link) dialog and an extension of it + // provides the image link dialog. + // + // description: + // The command provided by this plugin is: + // * createLink + + // Override _Plugin.buttonClass. This plugin is controlled by a DropDownButton + // (which triggers a TooltipDialog). + buttonClass: DropDownButton, + + // Override _Plugin.useDefaultCommand... processing is handled by this plugin, not by dijit.Editor. + useDefaultCommand: false, + + // urlRegExp: [protected] String + // Used for validating input as correct URL. While file:// urls are not terribly + // useful, they are technically valid. + urlRegExp: "((https?|ftps?|file)\\://|\./|/|)(/[a-zA-Z]{1,1}:/|)(((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)*(?:[a-zA-Z](?:[-\\da-zA-Z]{0,80}[\\da-zA-Z])?)\\.?)|(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])|(0[xX]0*[\\da-fA-F]?[\\da-fA-F]\\.){3}0[xX]0*[\\da-fA-F]?[\\da-fA-F]|(0+[0-3][0-7][0-7]\\.){3}0+[0-3][0-7][0-7]|(0|[1-9]\\d{0,8}|[1-3]\\d{9}|4[01]\\d{8}|42[0-8]\\d{7}|429[0-3]\\d{6}|4294[0-8]\\d{5}|42949[0-5]\\d{4}|429496[0-6]\\d{3}|4294967[01]\\d{2}|42949672[0-8]\\d|429496729[0-5])|0[xX]0*[\\da-fA-F]{1,8}|([\\da-fA-F]{1,4}\\:){7}[\\da-fA-F]{1,4}|([\\da-fA-F]{1,4}\\:){6}((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])))(\\:\\d+)?(/(?:[^?#\\s/]+/)*(?:[^?#\\s/]{0,}(?:\\?[^?#\\s/]*)?(?:#.*)?)?)?", + + // emailRegExp: [protected] String + // Used for validating input as correct email address. Taken from dojox.validate + emailRegExp: "<?(mailto\\:)([!#-'*+\\-\\/-9=?A-Z^-~]+[.])*[!#-'*+\\-\\/-9=?A-Z^-~]+" /*username*/ + "@" + + "((?:(?:[\\da-zA-Z](?:[-\\da-zA-Z]{0,61}[\\da-zA-Z])?)\\.)+(?:[a-zA-Z](?:[-\\da-zA-Z]{0,6}[\\da-zA-Z])?)\\.?)|localhost|^[^-][a-zA-Z0-9_-]*>?", // host. + + // htmlTemplate: [protected] String + // String used for templating the HTML to insert at the desired point. + htmlTemplate: "<a href=\"${urlInput}\" _djrealurl=\"${urlInput}\"" + + " target=\"${targetSelect}\"" + + ">${textInput}</a>", + + // tag: [protected] String + // Tag used for the link type. + tag: "a", + + // _hostRxp [private] RegExp + // Regular expression used to validate url fragments (ip address, hostname, etc) + _hostRxp: /^((([^\[:]+):)?([^@]+)@)?(\[([^\]]+)\]|([^\[:]*))(:([0-9]+))?$/, + + // _userAtRxp [private] RegExp + // Regular expression used to validate e-mail address fragment. + _userAtRxp: /^([!#-'*+\-\/-9=?A-Z^-~]+[.])*[!#-'*+\-\/-9=?A-Z^-~]+@/i, + + // linkDialogTemplate: [protected] String + // Template for contents of TooltipDialog to pick URL + linkDialogTemplate: [ + "<table><tr><td>", + "<label for='${id}_urlInput'>${url}</label>", + "</td><td>", + "<input data-dojo-type='dijit.form.ValidationTextBox' required='true' " + + "id='${id}_urlInput' name='urlInput' data-dojo-props='intermediateChanges:true'/>", + "</td></tr><tr><td>", + "<label for='${id}_textInput'>${text}</label>", + "</td><td>", + "<input data-dojo-type='dijit.form.ValidationTextBox' required='true' id='${id}_textInput' " + + "name='textInput' data-dojo-props='intermediateChanges:true'/>", + "</td></tr><tr><td>", + "<label for='${id}_targetSelect'>${target}</label>", + "</td><td>", + "<select id='${id}_targetSelect' name='targetSelect' data-dojo-type='dijit.form.Select'>", + "<option selected='selected' value='_self'>${currentWindow}</option>", + "<option value='_blank'>${newWindow}</option>", + "<option value='_top'>${topWindow}</option>", + "<option value='_parent'>${parentWindow}</option>", + "</select>", + "</td></tr><tr><td colspan='2'>", + "<button data-dojo-type='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>", + "<button data-dojo-type='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>", + "</td></tr></table>" + ].join(""), + + _initButton: function(){ + this.inherited(arguments); + + // Setup to lazy create TooltipDialog first time the button is clicked + this.button.loadDropDown = lang.hitch(this, "_loadDropDown"); + + this._connectTagEvents(); + }, + _loadDropDown: function(callback){ + // Called the first time the button is pressed. Initialize TooltipDialog. + require([ + "dojo/i18n", // i18n.getLocalization + "../../TooltipDialog", + "../../registry", // registry.byId, registry.getUniqueId + "../../form/Button", // used by template + "../../form/Select", // used by template + "../../form/ValidationTextBox", // used by template + "dojo/i18n!../../nls/common", + "dojo/i18n!../nls/LinkDialog" + ], lang.hitch(this, function(i18n, TooltipDialog, registry){ + var _this = this; + this.tag = this.command == 'insertImage' ? 'img' : 'a'; + var messages = lang.delegate(i18n.getLocalization("dijit", "common", this.lang), + i18n.getLocalization("dijit._editor", "LinkDialog", this.lang)); + var dropDown = (this.dropDown = this.button.dropDown = new TooltipDialog({ + title: messages[this.command + "Title"], + execute: lang.hitch(this, "setValue"), + onOpen: function(){ + _this._onOpenDialog(); + TooltipDialog.prototype.onOpen.apply(this, arguments); + }, + onCancel: function(){ + setTimeout(lang.hitch(_this, "_onCloseDialog"),0); + } + })); + messages.urlRegExp = this.urlRegExp; + messages.id = registry.getUniqueId(this.editor.id); + this._uniqueId = messages.id; + this._setContent(dropDown.title + + "<div style='border-bottom: 1px black solid;padding-bottom:2pt;margin-bottom:4pt'></div>" + + string.substitute(this.linkDialogTemplate, messages)); + dropDown.startup(); + this._urlInput = registry.byId(this._uniqueId + "_urlInput"); + this._textInput = registry.byId(this._uniqueId + "_textInput"); + this._setButton = registry.byId(this._uniqueId + "_setButton"); + this.connect(registry.byId(this._uniqueId + "_cancelButton"), "onClick", function(){ + this.dropDown.onCancel(); + }); + if(this._urlInput){ + this.connect(this._urlInput, "onChange", "_checkAndFixInput"); + } + if(this._textInput){ + this.connect(this._textInput, "onChange", "_checkAndFixInput"); + } + + // Build up the dual check for http/https/file:, and mailto formats. + this._urlRegExp = new RegExp("^" + this.urlRegExp + "$", "i"); + this._emailRegExp = new RegExp("^" + this.emailRegExp + "$", "i"); + this._urlInput.isValid = lang.hitch(this, function(){ + // Function over-ride of isValid to test if the input matches a url or a mailto style link. + var value = this._urlInput.get("value"); + return this._urlRegExp.test(value) || this._emailRegExp.test(value); + }); + + // Listen for enter and execute if valid. + this.connect(dropDown.domNode, "onkeypress", function(e){ + if(e && e.charOrCode == keys.ENTER && + !e.shiftKey && !e.metaKey && !e.ctrlKey && !e.altKey){ + if(!this._setButton.get("disabled")){ + dropDown.onExecute(); + dropDown.execute(dropDown.get('value')); + } + } + }); + + callback(); + })); + }, + + _checkAndFixInput: function(){ + // summary: + // A function to listen for onChange events and test the input contents + // for valid information, such as valid urls with http/https/ftp and if + // not present, try and guess if the input url is relative or not, and if + // not, append http:// to it. Also validates other fields as determined by + // the internal _isValid function. + var self = this; + var url = this._urlInput.get("value"); + var fixupUrl = function(url){ + var appendHttp = false; + var appendMailto = false; + if(url && url.length > 1){ + url = lang.trim(url); + if(url.indexOf("mailto:") !== 0){ + if(url.indexOf("/") > 0){ + if(url.indexOf("://") === -1){ + // Check that it doesn't start with / or ./, which would + // imply 'target server relativeness' + if(url.charAt(0) !== '/' && url.indexOf("./") !== 0){ + if(self._hostRxp.test(url)){ + appendHttp = true; + } + } + } + }else if(self._userAtRxp.test(url)){ + // If it looks like a foo@, append a mailto. + appendMailto = true; + } + } + } + if(appendHttp){ + self._urlInput.set("value", "http://" + url); + } + if(appendMailto){ + self._urlInput.set("value", "mailto:" + url); + } + self._setButton.set("disabled", !self._isValid()); + }; + if(this._delayedCheck){ + clearTimeout(this._delayedCheck); + this._delayedCheck = null; + } + this._delayedCheck = setTimeout(function(){ + fixupUrl(url); + }, 250); + }, + + _connectTagEvents: function(){ + // summary: + // Over-ridable function that connects tag specific events. + this.editor.onLoadDeferred.addCallback(lang.hitch(this, function(){ + this.connect(this.editor.editNode, "ondblclick", this._onDblClick); + })); + }, + + _isValid: function(){ + // summary: + // Internal function to allow validating of the inputs + // for a link to determine if set should be disabled or not + // tags: + // protected + return this._urlInput.isValid() && this._textInput.isValid(); + }, + + _setContent: function(staticPanel){ + // summary: + // Helper for _initButton above. Not sure why it's a separate method. + this.dropDown.set({ + parserScope: "dojo", // make parser search for dojoType/data-dojo-type even if page is multi-version + content: staticPanel + }); + }, + + _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 && args.urlInput){ + args.urlInput = args.urlInput.replace(/"/g, """); + } + return args; + }, + + setValue: function(args){ + // summary: + // Callback from the dialog when user presses "set" button. + // tags: + // private + //TODO: prevent closing popup if the text is empty + this._onCloseDialog(); + if(has("ie") < 9){ //see #4151 + var sel = rangeapi.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() !== this.tag)){ + // Still nothing, one last thing to try on IE, as it might be 'img' + // and thus considered a control. + a = win.withGlobal(this.editor.window, + "getSelectedElement", selectionapi, [this.tag]); + } + if(a && (a.nodeName && a.nodeName.toLowerCase() === this.tag)){ + // Okay, we do have a match. IE, for some reason, sometimes pastes before + // instead of removing the targeted 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 children, then unlink. The following insert will + // then replace the selected text. + win.withGlobal(this.editor.window, + "selectElementChildren", selectionapi, [a]); + this.editor.execCommand("unlink"); + } + } + } + // make sure values are properly escaped, etc. + args = this._checkValues(args); + this.editor.execCommand('inserthtml', + 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 url, text, target; + if(a && a.tagName.toLowerCase() === this.tag){ + url = a.getAttribute('_djrealurl') || a.getAttribute('href'); + target = a.getAttribute('target') || "_self"; + text = a.textContent || a.innerText; + win.withGlobal(this.editor.window, "selectElement", selectionapi, [a, true]); + }else{ + text = win.withGlobal(this.editor.window, selectionapi.getSelectedText); + } + return {urlInput: url || '', textInput: text || '', targetSelect: target || ''}; //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(has("ie") < 9){ + // IE is difficult to select the element in, using the range unified + // API seems to work reasonably well. + var sel = rangeapi.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() !== this.tag)){ + // Still nothing, one last thing to try on IE, as it might be 'img' + // and thus considered a control. + a = win.withGlobal(this.editor.window, + "getSelectedElement", selectionapi, [this.tag]); + } + }else{ + a = win.withGlobal(this.editor.window, + "getAncestorElement", selectionapi, [this.tag]); + } + 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 === this.tag && domAttr.get(t,"href")){ + var editor = this.editor; + + win.withGlobal(editor.window, + "selectElement", + selectionapi, [t]); + + editor.onDisplayChanged(); + + // Call onNormalizedDisplayChange() now, rather than on timer. + // On IE, when focus goes to the first <input> in the TooltipDialog, the editor loses it's selection. + // Later if onNormalizedDisplayChange() gets called via the timer it will disable the LinkDialog button + // (actually, all the toolbar buttons), at which point clicking the <input> will close the dialog, + // since (for unknown reasons) focus.js ignores disabled controls. + if(editor._updateTimer){ + clearTimeout(editor._updateTimer); + delete editor._updateTimer; + } + editor.onNormalizedDisplayChanged(); + + var button = this.button; + setTimeout(function(){ + // Focus shift outside the event handler. + // IE doesn't like focus changes in event handles. + button.set("disabled", false); + button.loadAndOpenDropDown().then(function(){ + if(button.dropDown.focus){ + button.dropDown.focus(); + } + }); + }, 10); + } + } + } +}); + +var ImgLinkDialog = declare("dijit._editor.plugins.ImgLinkDialog", [LinkDialog], { + // summary: + // This plugin extends LinkDialog and adds in a plugin for handling image links. + // provides the image link dialog. + // + // description: + // The command provided by this plugin is: + // * insertImage + + // linkDialogTemplate: [protected] String + // Over-ride for template since img dialog doesn't need target that anchor tags may. + linkDialogTemplate: [ + "<table><tr><td>", + "<label for='${id}_urlInput'>${url}</label>", + "</td><td>", + "<input dojoType='dijit.form.ValidationTextBox' regExp='${urlRegExp}' " + + "required='true' id='${id}_urlInput' name='urlInput' data-dojo-props='intermediateChanges:true'/>", + "</td></tr><tr><td>", + "<label for='${id}_textInput'>${text}</label>", + "</td><td>", + "<input data-dojo-type='dijit.form.ValidationTextBox' required='false' id='${id}_textInput' " + + "name='textInput' data-dojo-props='intermediateChanges:true'/>", + "</td></tr><tr><td>", + "</td><td>", + "</td></tr><tr><td colspan='2'>", + "<button data-dojo-type='dijit.form.Button' type='submit' id='${id}_setButton'>${set}</button>", + "<button data-dojo-type='dijit.form.Button' type='button' id='${id}_cancelButton'>${buttonCancel}</button>", + "</td></tr></table>" + ].join(""), + + // htmlTemplate: [protected] String + // String used for templating the <img> HTML to insert at the desired point. + htmlTemplate: "<img src=\"${urlInput}\" _djrealurl=\"${urlInput}\" alt=\"${textInput}\" />", + + // tag: [protected] String + // Tag used for the link type (img). + tag: "img", + + _getCurrentValues: function(img){ + // 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 url, text; + if(img && img.tagName.toLowerCase() === this.tag){ + url = img.getAttribute('_djrealurl') || img.getAttribute('src'); + text = img.getAttribute('alt'); + win.withGlobal(this.editor.window, + "selectElement", selectionapi, [img, true]); + }else{ + text = win.withGlobal(this.editor.window, selectionapi.getSelectedText); + } + return {urlInput: url || '', textInput: text || ''}; //Object; + }, + + _isValid: function(){ + // summary: + // Over-ride for images. You can have alt text of blank, it is valid. + // tags: + // protected + return this._urlInput.isValid(); + }, + + _connectTagEvents: function(){ + // summary: + // Over-ridable function that connects tag specific events. + this.inherited(arguments); + this.editor.onLoadDeferred.addCallback(lang.hitch(this, function(){ + // Use onmousedown instead of onclick. Seems that IE eats the first onclick + // to wrap it in a selector box, then the second one acts as onclick. See #10420 + this.connect(this.editor.editNode, "onmousedown", this._selectTag); + })); + }, + + _selectTag: function(e){ + // summary: + // A simple event handler that lets me select an image if it is clicked on. + // makes it easier to select images in a standard way across browsers. Otherwise + // selecting an image for edit becomes difficult. + // e: Event + // The mousedown event. + // tags: + // private + if(e && e.target){ + var t = e.target; + var tg = t.tagName? t.tagName.toLowerCase() : ""; + if(tg === this.tag){ + win.withGlobal(this.editor.window, + "selectElement", + selectionapi, [t]); + } + } + }, + + _checkValues: function(args){ + // summary: + // Function to check the values in args and 'fix' them up as needed + // (special characters in the url or alt text) + // args: Object + // Content being set. + // tags: + // protected + if(args && args.urlInput){ + args.urlInput = args.urlInput.replace(/"/g, """); + } + if(args && args.textInput){ + args.textInput = args.textInput.replace(/"/g, """); + } + return args; + }, + + _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 === this.tag && domAttr.get(t,"src")){ + var editor = this.editor; + + win.withGlobal(editor.window, + "selectElement", + selectionapi, [t]); + editor.onDisplayChanged(); + + // Call onNormalizedDisplayChange() now, rather than on timer. + // On IE, when focus goes to the first <input> in the TooltipDialog, the editor loses it's selection. + // Later if onNormalizedDisplayChange() gets called via the timer it will disable the LinkDialog button + // (actually, all the toolbar buttons), at which point clicking the <input> will close the dialog, + // since (for unknown reasons) focus.js ignores disabled controls. + if(editor._updateTimer){ + clearTimeout(editor._updateTimer); + delete editor._updateTimer; + } + editor.onNormalizedDisplayChanged(); + + var button = this.button; + setTimeout(function(){ + // Focus shift outside the event handler. + // IE doesn't like focus changes in event handles. + button.set("disabled", false); + button.loadAndOpenDropDown().then(function(){ + if(button.dropDown.focus){ + button.dropDown.focus(); + } + }); + }, 10); + } + } + } +}); + +// Register these plugins +_Plugin.registry["createLink"] = function(){ + return new LinkDialog({command: "createLink"}); +}; +_Plugin.registry["insertImage"] = function(){ + return new ImgLinkDialog({command: "insertImage"}); +}; + + +// Export both LinkDialog and ImgLinkDialog +LinkDialog.ImgLinkDialog = ImgLinkDialog; +return LinkDialog; +}); diff --git a/js/dojo/dijit/_editor/plugins/NewPage.js b/js/dojo/dijit/_editor/plugins/NewPage.js new file mode 100644 index 0000000..be837ae --- /dev/null +++ b/js/dojo/dijit/_editor/plugins/NewPage.js @@ -0,0 +1,84 @@ +//>>built +define("dijit/_editor/plugins/NewPage", [ + "dojo/_base/declare", // declare + "dojo/i18n", // i18n.getLocalization + "dojo/_base/lang", // lang.hitch + "../_Plugin", + "../../form/Button", + "dojo/i18n!../nls/commands" +], function(declare, i18n, lang, _Plugin, Button){ + +/*===== + var _Plugin = dijit._editor._Plugin; +=====*/ + +// module: +// dijit/_editor/plugins/NewPage +// summary: +// This plugin provides a simple 'new page' capability. In other +// words, set content to some default user defined string. + + +var NewPage = declare("dijit._editor.plugins.NewPage",_Plugin,{ + // summary: + // This plugin provides a simple 'new page' capability. In other + // words, set content to some default user defined string. + + // content: [public] String + // The default content to insert into the editor as the new page. + // The default is the <br> tag, a single blank line. + content: "<br>", + + _initButton: function(){ + // summary: + // Over-ride for creation of the Print button. + var strings = i18n.getLocalization("dijit._editor", "commands"), + editor = this.editor; + this.button = new Button({ + label: strings["newPage"], + dir: editor.dir, + lang: editor.lang, + showLabel: false, + iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "NewPage", + tabIndex: "-1", + onClick: lang.hitch(this, "_newPage") + }); + }, + + setEditor: function(/*dijit.Editor*/ editor){ + // summary: + // Tell the plugin which Editor it is associated with. + // editor: Object + // The editor object to attach the newPage capability to. + this.editor = editor; + this._initButton(); + }, + + updateState: function(){ + // summary: + // Over-ride for button state control for disabled to work. + this.button.set("disabled", this.get("disabled")); + }, + + _newPage: function(){ + // summary: + // Function to set the content to blank. + // tags: + // private + this.editor.beginEditing(); + this.editor.set("value", this.content); + this.editor.endEditing(); + this.editor.focus(); + } +}); + +// Register this plugin. +// For back-compat accept "newpage" (all lowercase) too, remove in 2.0 +_Plugin.registry["newPage"] = _Plugin.registry["newpage"] = function(args){ + return new NewPage({ + content: ("content" in args)?args.content:"<br>" + }); +}; + +return NewPage; +}); diff --git a/js/dojo/dijit/_editor/plugins/Print.js b/js/dojo/dijit/_editor/plugins/Print.js new file mode 100644 index 0000000..16058ba --- /dev/null +++ b/js/dojo/dijit/_editor/plugins/Print.js @@ -0,0 +1,130 @@ +//>>built +define("dijit/_editor/plugins/Print", [ + "dojo/_base/declare", // declare + "dojo/i18n", // i18n.getLocalization + "dojo/_base/lang", // lang.hitch + "dojo/_base/sniff", // has("chrome") has("opera") + "../../focus", // focus.focus() + "../_Plugin", + "../../form/Button", + "dojo/i18n!../nls/commands" +], function(declare, i18n, lang, has, focus, _Plugin, Button){ + +/*===== + var _Plugin = dijit._editor._Plugin; +=====*/ + +// module: +// dijit/_editor/plugins/Print +// summary: +// This plugin provides Print capability to the editor. When +// clicked, the document in the editor frame will be printed. + + +var Print = declare("dijit._editor.plugins.Print",_Plugin,{ + // summary: + // This plugin provides Print capability to the editor. When + // clicked, the document in the editor frame will be printed. + + _initButton: function(){ + // summary: + // Over-ride for creation of the Print button. + var strings = i18n.getLocalization("dijit._editor", "commands"), + editor = this.editor; + this.button = new Button({ + label: strings["print"], + dir: editor.dir, + lang: editor.lang, + showLabel: false, + iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "Print", + tabIndex: "-1", + onClick: lang.hitch(this, "_print") + }); + }, + + setEditor: function(/*dijit.Editor*/ editor){ + // summary: + // Tell the plugin which Editor it is associated with. + // editor: Object + // The editor object to attach the print capability to. + this.editor = editor; + this._initButton(); + + // Set up a check that we have a print function + // and disable button if we do not. + this.editor.onLoadDeferred.addCallback( + lang.hitch(this, function(){ + if(!this.editor.iframe.contentWindow["print"]){ + this.button.set("disabled", true); + } + }) + ); + }, + + updateState: function(){ + // summary: + // Over-ride for button state control for disabled to work. + var disabled = this.get("disabled"); + if(!this.editor.iframe.contentWindow["print"]){ + disabled = true; + } + this.button.set("disabled", disabled); + }, + + _print: function(){ + // summary: + // Function to trigger printing of the editor document + // tags: + // private + var edFrame = this.editor.iframe; + if(edFrame.contentWindow["print"]){ + // IE requires the frame to be focused for + // print to work, but since this is okay for all + // no special casing. + if(!has("opera") && !has("chrome")){ + focus.focus(edFrame); + edFrame.contentWindow.print(); + }else{ + // Neither Opera nor Chrome 3 et you print single frames. + // So, open a new 'window', print it, and close it. + // Also, can't use size 0x0, have to use 1x1 + var edDoc = this.editor.document; + var content = this.editor.get("value"); + content = "<html><head><meta http-equiv='Content-Type' " + + "content='text/html; charset='UTF-8'></head><body>" + + content + "</body></html>"; + var win = window.open("javascript: ''", + "", + "status=0,menubar=0,location=0,toolbar=0," + + "width=1,height=1,resizable=0,scrollbars=0"); + win.document.open(); + win.document.write(content); + win.document.close(); + + var styleNodes = edDoc.getElementsByTagName("style"); + if(styleNodes){ + // Clone over any editor view styles, since we can't print the iframe + // directly. + var i; + for(i = 0; i < styleNodes.length; i++){ + var style = styleNodes[i].innerHTML; + var sNode = win.document.createElement("style"); + sNode.appendChild(win.document.createTextNode(style)); + win.document.getElementsByTagName("head")[0].appendChild(sNode); + } + } + win.print(); + win.close(); + } + } + } +}); + +// Register this plugin. +_Plugin.registry["print"] = function(){ + return new Print({command: "print"}); +}; + + +return Print; +}); diff --git a/js/dojo/dijit/_editor/plugins/TabIndent.js b/js/dojo/dijit/_editor/plugins/TabIndent.js new file mode 100644 index 0000000..01032fa --- /dev/null +++ b/js/dojo/dijit/_editor/plugins/TabIndent.js @@ -0,0 +1,70 @@ +//>>built +define("dijit/_editor/plugins/TabIndent", [ + "dojo/_base/declare", // declare + "dojo/_base/kernel", // kernel.experimental + "../_Plugin", + "../../form/ToggleButton" +], function(declare, kernel, _Plugin, ToggleButton){ + +/*===== + var _Plugin = dijit._editor._Plugin; +=====*/ + + // module: + // dijit/_editor/plugins/TabIndent + // summary: + // This plugin is used to allow the use of the tab and shift-tab keys + // to indent/outdent list items. This overrides the default behavior + // of moving focus from/to the toolbar + + + kernel.experimental("dijit._editor.plugins.TabIndent"); + + + var TabIndent = declare("dijit._editor.plugins.TabIndent", _Plugin, { + // summary: + // This plugin is used to allow the use of the tab and shift-tab keys + // to indent/outdent list items. This overrides the default behavior + // of moving focus from/to the toolbar + + // Override _Plugin.useDefaultCommand... processing is handled by this plugin, not by dijit.Editor. + useDefaultCommand: false, + + // Override _Plugin.buttonClass to use a ToggleButton for this plugin rather than a vanilla Button + buttonClass: ToggleButton, + + command: "tabIndent", + + _initButton: function(){ + // Override _Plugin._initButton() to setup listener on button click + this.inherited(arguments); + + var e = this.editor; + this.connect(this.button, "onChange", function(val){ + e.set("isTabIndent", val); + }); + + // Set initial checked state of button based on Editor.isTabIndent + this.updateState(); + }, + + updateState: function(){ + // Overrides _Plugin.updateState(). + // Ctrl-m in the editor will switch tabIndent mode on/off, so we need to react to that. + var disabled = this.get("disabled"); + this.button.set("disabled", disabled); + if(disabled){ + return; + } + this.button.set('checked', this.editor.isTabIndent, false); + } + }); + + // Register this plugin. + _Plugin.registry["tabIndent"] = function(){ + return new TabIndent({command: "tabIndent"}); + }; + + + return TabIndent; +}); diff --git a/js/dojo/dijit/_editor/plugins/TextColor.js b/js/dojo/dijit/_editor/plugins/TextColor.js new file mode 100644 index 0000000..b93a716 --- /dev/null +++ b/js/dojo/dijit/_editor/plugins/TextColor.js @@ -0,0 +1,120 @@ +//>>built +define("dijit/_editor/plugins/TextColor", [ + "require", + "dojo/colors", // colors.fromRgb + "dojo/_base/declare", // declare + "dojo/_base/lang", + "../_Plugin", + "../../form/DropDownButton" +], function(require, colors, declare, lang, _Plugin, DropDownButton){ + +/*===== + var _Plugin = dijit._editor._Plugin; +=====*/ + +// module: +// dijit/_editor/plugins/TextColor +// summary: +// This plugin provides dropdown color pickers for setting text color and background color + + +var TextColor = declare("dijit._editor.plugins.TextColor", _Plugin, { + // summary: + // This plugin provides dropdown color pickers for setting text color and background color + // + // description: + // The commands provided by this plugin are: + // * foreColor - sets the text color + // * hiliteColor - sets the background color + + // Override _Plugin.buttonClass to use DropDownButton (with ColorPalette) to control this plugin + buttonClass: DropDownButton, + + // useDefaultCommand: Boolean + // False as we do not use the default editor command/click behavior. + useDefaultCommand: false, + + _initButton: function(){ + this.inherited(arguments); + + // Setup to lazy load ColorPalette first time the button is clicked + var self = this; + this.button.loadDropDown = function(callback){ + require(["../../ColorPalette"], lang.hitch(this, function(ColorPalette){ + this.dropDown = new ColorPalette({ + value: self.value, + onChange: function(color){ + self.editor.execCommand(self.command, color); + } + }); + callback(); + })); + }; + }, + + updateState: function(){ + // summary: + // Overrides _Plugin.updateState(). This updates the ColorPalette + // to show the color of the currently selected text. + // tags: + // protected + + var _e = this.editor; + var _c = this.command; + if(!_e || !_e.isLoaded || !_c.length){ + return; + } + + if(this.button){ + var disabled = this.get("disabled"); + this.button.set("disabled", disabled); + if(disabled){ return; } + + var value; + try{ + value = _e.queryCommandValue(_c)|| ""; + }catch(e){ + //Firefox may throw error above if the editor is just loaded, ignore it + value = ""; + } + } + + if(value == ""){ + value = "#000000"; + } + if(value == "transparent"){ + value = "#ffffff"; + } + + if(typeof value == "string"){ + //if RGB value, convert to hex value + if(value.indexOf("rgb")> -1){ + value = colors.fromRgb(value).toHex(); + } + }else{ //it's an integer(IE returns an MS access #) + value =((value & 0x0000ff)<< 16)|(value & 0x00ff00)|((value & 0xff0000)>>> 16); + value = value.toString(16); + value = "#000000".slice(0, 7 - value.length)+ value; + + } + + this.value = value; + + var dropDown = this.button.dropDown; + if(dropDown && value !== dropDown.get('value')){ + dropDown.set('value', value, false); + } + } +}); + +// Register this plugin. +_Plugin.registry["foreColor"] = function(){ + return new TextColor({command: "foreColor"}); +}; +_Plugin.registry["hiliteColor"] = function(){ + return new TextColor({command: "hiliteColor"}); +}; + + +return TextColor; +}); diff --git a/js/dojo/dijit/_editor/plugins/ToggleDir.js b/js/dojo/dijit/_editor/plugins/ToggleDir.js new file mode 100644 index 0000000..df46f0a --- /dev/null +++ b/js/dojo/dijit/_editor/plugins/ToggleDir.js @@ -0,0 +1,78 @@ +//>>built +define("dijit/_editor/plugins/ToggleDir", [ + "dojo/_base/declare", // declare + "dojo/dom-style", // domStyle.getComputedStyle + "dojo/_base/kernel", // kernel.experimental + "dojo/_base/lang", // lang.hitch + "../_Plugin", + "../../form/ToggleButton" +], function(declare, domStyle, kernel, lang, _Plugin, ToggleButton){ + +/*===== + var _Plugin = dijit._editor._Plugin; +=====*/ + + // module: + // dijit/_editor/plugins/ToggleDir + // summary: + // This plugin is used to toggle direction of the edited document, + // independent of what direction the whole page is. + + + kernel.experimental("dijit._editor.plugins.ToggleDir"); + + var ToggleDir = declare("dijit._editor.plugins.ToggleDir", _Plugin, { + // summary: + // This plugin is used to toggle direction of the edited document, + // independent of what direction the whole page is. + + // Override _Plugin.useDefaultCommand: processing is done in this plugin + // rather than by sending commands to the Editor + useDefaultCommand: false, + + command: "toggleDir", + + // Override _Plugin.buttonClass to use a ToggleButton for this plugin rather than a vanilla Button + buttonClass: ToggleButton, + + _initButton: function(){ + // Override _Plugin._initButton() to setup handler for button click events. + this.inherited(arguments); + this.editor.onLoadDeferred.addCallback(lang.hitch(this, function(){ + var editDoc = this.editor.editorObject.contentWindow.document.documentElement; + //IE direction has to toggle on the body, not document itself. + //If you toggle just the document, things get very strange in the + //view. But, the nice thing is this works for all supported browsers. + editDoc = editDoc.getElementsByTagName("body")[0]; + var isLtr = domStyle.getComputedStyle(editDoc).direction == "ltr"; + this.button.set("checked", !isLtr); + this.connect(this.button, "onChange", "_setRtl"); + })); + }, + + updateState: function(){ + // summary: + // Over-ride for button state control for disabled to work. + this.button.set("disabled", this.get("disabled")); + }, + + _setRtl: function(rtl){ + // summary: + // Handler for button click events, to switch the text direction of the editor + var dir = "ltr"; + if(rtl){ + dir = "rtl"; + } + var editDoc = this.editor.editorObject.contentWindow.document.documentElement; + editDoc = editDoc.getElementsByTagName("body")[0]; + editDoc.dir/*html node*/ = dir; + } + }); + + // Register this plugin. + _Plugin.registry["toggleDir"] = function(){ + return new ToggleDir({command: "toggleDir"}); + }; + + return ToggleDir; +}); diff --git a/js/dojo/dijit/_editor/plugins/ViewSource.js b/js/dojo/dijit/_editor/plugins/ViewSource.js new file mode 100644 index 0000000..f1115c1 --- /dev/null +++ b/js/dojo/dijit/_editor/plugins/ViewSource.js @@ -0,0 +1,565 @@ +//>>built +define("dijit/_editor/plugins/ViewSource", [ + "dojo/_base/array", // array.forEach + "dojo/_base/declare", // declare + "dojo/dom-attr", // domAttr.set + "dojo/dom-construct", // domConstruct.create domConstruct.place + "dojo/dom-geometry", // domGeometry.setMarginBox domGeometry.position + "dojo/dom-style", // domStyle.set + "dojo/_base/event", // event.stop + "dojo/i18n", // i18n.getLocalization + "dojo/keys", // keys.F12 + "dojo/_base/lang", // lang.hitch + "dojo/on", // on() + "dojo/_base/sniff", // has("ie") has("webkit") + "dojo/_base/window", // win.body win.global + "dojo/window", // winUtils.getBox + "../../focus", // focus.focus() + "../_Plugin", + "../../form/ToggleButton", + "../..", // dijit._scopeName + "../../registry", // registry.getEnclosingWidget() + "dojo/i18n!../nls/commands" +], function(array, declare, domAttr, domConstruct, domGeometry, domStyle, event, i18n, keys, lang, on, has, win, + winUtils, focus, _Plugin, ToggleButton, dijit, registry){ + +/*===== + var _Plugin = dijit._editor._Plugin; +=====*/ + +// module: +// dijit/_editor/plugins/ViewSource +// summary: +// This plugin provides a simple view source capability. + + +var ViewSource = declare("dijit._editor.plugins.ViewSource",_Plugin, { + // summary: + // This plugin provides a simple view source capability. When view + // source mode is enabled, it disables all other buttons/plugins on the RTE. + // It also binds to the hotkey: CTRL-SHIFT-F11 for toggling ViewSource mode. + + // stripScripts: [public] Boolean + // Boolean flag used to indicate if script tags should be stripped from the document. + // Defaults to true. + stripScripts: true, + + // stripComments: [public] Boolean + // Boolean flag used to indicate if comment tags should be stripped from the document. + // Defaults to true. + stripComments: true, + + // stripComments: [public] Boolean + // Boolean flag used to indicate if iframe tags should be stripped from the document. + // Defaults to true. + stripIFrames: true, + + // readOnly: [const] Boolean + // Boolean flag used to indicate if the source view should be readonly or not. + // Cannot be changed after initialization of the plugin. + // Defaults to false. + readOnly: false, + + // _fsPlugin: [private] Object + // Reference to a registered fullscreen plugin so that viewSource knows + // how to scale. + _fsPlugin: null, + + toggle: function(){ + // summary: + // Function to allow programmatic toggling of the view. + + // For Webkit, we have to focus a very particular way. + // when swapping views, otherwise focus doesn't shift right + // but can't focus this way all the time, only for VS changes. + // If we did it all the time, buttons like bold, italic, etc + // break. + if(has("webkit")){this._vsFocused = true;} + this.button.set("checked", !this.button.get("checked")); + + }, + + _initButton: function(){ + // summary: + // Over-ride for creation of the resize button. + var strings = i18n.getLocalization("dijit._editor", "commands"), + editor = this.editor; + this.button = new ToggleButton({ + label: strings["viewSource"], + dir: editor.dir, + lang: editor.lang, + showLabel: false, + iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "ViewSource", + tabIndex: "-1", + onChange: lang.hitch(this, "_showSource") + }); + + // IE 7 has a horrible bug with zoom, so we have to create this node + // to cross-check later. Sigh. + if(has("ie") == 7){ + this._ieFixNode = domConstruct.create("div", { + style: { + opacity: "0", + zIndex: "-1000", + position: "absolute", + top: "-1000px" + } + }, win.body()); + } + // Make sure readonly mode doesn't make the wrong cursor appear over the button. + this.button.set("readOnly", false); + }, + + + setEditor: function(/*dijit.Editor*/ editor){ + // summary: + // Tell the plugin which Editor it is associated with. + // editor: Object + // The editor object to attach the print capability to. + this.editor = editor; + this._initButton(); + + this.editor.addKeyHandler(keys.F12, true, true, lang.hitch(this, function(e){ + // Move the focus before switching + // It'll focus back. Hiding a focused + // node causes issues. + this.button.focus(); + this.toggle(); + event.stop(e); + + // Call the focus shift outside of the handler. + setTimeout(lang.hitch(this, function(){ + // We over-ride focus, so we just need to call. + this.editor.focus(); + }), 100); + })); + }, + + _showSource: function(source){ + // summary: + // Function to toggle between the source and RTE views. + // source: boolean + // Boolean value indicating if it should be in source mode or not. + // tags: + // private + var ed = this.editor; + var edPlugins = ed._plugins; + var html; + this._sourceShown = source; + var self = this; + try{ + if(!this.sourceArea){ + this._createSourceView(); + } + if(source){ + // Update the QueryCommandEnabled function to disable everything but + // the source view mode. Have to over-ride a function, then kick all + // plugins to check their state. + ed._sourceQueryCommandEnabled = ed.queryCommandEnabled; + ed.queryCommandEnabled = function(cmd){ + return cmd.toLowerCase() === "viewsource"; + }; + this.editor.onDisplayChanged(); + html = ed.get("value"); + html = this._filter(html); + ed.set("value", html); + array.forEach(edPlugins, function(p){ + // Turn off any plugins not controlled by queryCommandenabled. + if(!(p instanceof ViewSource)){ + p.set("disabled", true) + } + }); + + // We actually do need to trap this plugin and adjust how we + // display the textarea. + if(this._fsPlugin){ + this._fsPlugin._getAltViewNode = function(){ + return self.sourceArea; + }; + } + + this.sourceArea.value = html; + + // Since neither iframe nor textarea have margin, border, or padding, + // just set sizes equal + this.sourceArea.style.height = ed.iframe.style.height; + this.sourceArea.style.width = ed.iframe.style.width; + domStyle.set(ed.iframe, "display", "none"); + domStyle.set(this.sourceArea, { + display: "block" + }); + + var resizer = function(){ + // function to handle resize events. + // Will check current VP and only resize if + // different. + var vp = winUtils.getBox(); + + if("_prevW" in this && "_prevH" in this){ + // No actual size change, ignore. + if(vp.w === this._prevW && vp.h === this._prevH){ + return; + }else{ + this._prevW = vp.w; + this._prevH = vp.h; + } + }else{ + this._prevW = vp.w; + this._prevH = vp.h; + } + if(this._resizer){ + clearTimeout(this._resizer); + delete this._resizer; + } + // Timeout it to help avoid spamming resize on IE. + // Works for all browsers. + this._resizer = setTimeout(lang.hitch(this, function(){ + delete this._resizer; + this._resize(); + }), 10); + }; + this._resizeHandle = on(window, "resize", lang.hitch(this, resizer)); + + //Call this on a delay once to deal with IE glitchiness on initial size. + setTimeout(lang.hitch(this, this._resize), 100); + + //Trigger a check for command enablement/disablement. + this.editor.onNormalizedDisplayChanged(); + + this.editor.__oldGetValue = this.editor.getValue; + this.editor.getValue = lang.hitch(this, function(){ + var txt = this.sourceArea.value; + txt = this._filter(txt); + return txt; + }); + }else{ + // First check that we were in source view before doing anything. + // corner case for being called with a value of false and we hadn't + // actually been in source display mode. + if(!ed._sourceQueryCommandEnabled){ + return; + } + this._resizeHandle.remove(); + delete this._resizeHandle; + + if(this.editor.__oldGetValue){ + this.editor.getValue = this.editor.__oldGetValue; + delete this.editor.__oldGetValue; + } + + // Restore all the plugin buttons state. + ed.queryCommandEnabled = ed._sourceQueryCommandEnabled; + if(!this._readOnly){ + html = this.sourceArea.value; + html = this._filter(html); + ed.beginEditing(); + ed.set("value", html); + ed.endEditing(); + } + + array.forEach(edPlugins, function(p){ + // Turn back on any plugins we turned off. + p.set("disabled", false); + }); + + domStyle.set(this.sourceArea, "display", "none"); + domStyle.set(ed.iframe, "display", "block"); + delete ed._sourceQueryCommandEnabled; + + //Trigger a check for command enablement/disablement. + this.editor.onDisplayChanged(); + } + // Call a delayed resize to wait for some things to display in header/footer. + setTimeout(lang.hitch(this, function(){ + // Make resize calls. + var parent = ed.domNode.parentNode; + if(parent){ + var container = registry.getEnclosingWidget(parent); + if(container && container.resize){ + container.resize(); + } + } + ed.resize(); + }), 300); + }catch(e){ + console.log(e); + } + }, + + updateState: function(){ + // summary: + // Over-ride for button state control for disabled to work. + this.button.set("disabled", this.get("disabled")); + }, + + _resize: function(){ + // summary: + // Internal function to resize the source view + // tags: + // private + var ed = this.editor; + var tbH = ed.getHeaderHeight(); + var fH = ed.getFooterHeight(); + var eb = domGeometry.position(ed.domNode); + + // Styles are now applied to the internal source container, so we have + // to subtract them off. + var containerPadding = domGeometry.getPadBorderExtents(ed.iframe.parentNode); + var containerMargin = domGeometry.getMarginExtents(ed.iframe.parentNode); + + var extents = domGeometry.getPadBorderExtents(ed.domNode); + var edb = { + w: eb.w - extents.w, + h: eb.h - (tbH + extents.h + + fH) + }; + + // Fullscreen gets odd, so we need to check for the FS plugin and + // adapt. + if(this._fsPlugin && this._fsPlugin.isFullscreen){ + //Okay, probably in FS, adjust. + var vp = winUtils.getBox(); + edb.w = (vp.w - extents.w); + edb.h = (vp.h - (tbH + extents.h + fH)); + } + + if(has("ie")){ + // IE is always off by 2px, so we have to adjust here + // Note that IE ZOOM is broken here. I can't get + //it to scale right. + edb.h -= 2; + } + + // IE has a horrible zoom bug. So, we have to try and account for + // it and fix up the scaling. + if(this._ieFixNode){ + var _ie7zoom = -this._ieFixNode.offsetTop / 1000; + edb.w = Math.floor((edb.w + 0.9) / _ie7zoom); + edb.h = Math.floor((edb.h + 0.9) / _ie7zoom); + } + + domGeometry.setMarginBox(this.sourceArea, { + w: edb.w - (containerPadding.w + containerMargin.w), + h: edb.h - (containerPadding.h + containerMargin.h) + }); + + // Scale the parent container too in this case. + domGeometry.setMarginBox(ed.iframe.parentNode, { + h: edb.h + }); + }, + + _createSourceView: function(){ + // summary: + // Internal function for creating the source view area. + // tags: + // private + var ed = this.editor; + var edPlugins = ed._plugins; + this.sourceArea = domConstruct.create("textarea"); + if(this.readOnly){ + domAttr.set(this.sourceArea, "readOnly", true); + this._readOnly = true; + } + domStyle.set(this.sourceArea, { + padding: "0px", + margin: "0px", + borderWidth: "0px", + borderStyle: "none" + }); + domConstruct.place(this.sourceArea, ed.iframe, "before"); + + if(has("ie") && ed.iframe.parentNode.lastChild !== ed.iframe){ + // There's some weirdo div in IE used for focus control + // But is messed up scaling the textarea if we don't config + // it some so it doesn't have a varying height. + domStyle.set(ed.iframe.parentNode.lastChild,{ + width: "0px", + height: "0px", + padding: "0px", + margin: "0px", + borderWidth: "0px", + borderStyle: "none" + }); + } + + // We also need to take over editor focus a bit here, so that focus calls to + // focus the editor will focus to the right node when VS is active. + ed._viewsource_oldFocus = ed.focus; + var self = this; + ed.focus = function(){ + if(self._sourceShown){ + self.setSourceAreaCaret(); + }else{ + try{ + if(this._vsFocused){ + delete this._vsFocused; + // Must focus edit node in this case (webkit only) or + // focus doesn't shift right, but in normal + // cases we focus with the regular function. + focus.focus(ed.editNode); + }else{ + ed._viewsource_oldFocus(); + } + }catch(e){ + console.log(e); + } + } + }; + + var i, p; + for(i = 0; i < edPlugins.length; i++){ + // We actually do need to trap this plugin and adjust how we + // display the textarea. + p = edPlugins[i]; + if(p && (p.declaredClass === "dijit._editor.plugins.FullScreen" || + p.declaredClass === (dijit._scopeName + + "._editor.plugins.FullScreen"))){ + this._fsPlugin = p; + break; + } + } + if(this._fsPlugin){ + // Found, we need to over-ride the alt-view node function + // on FullScreen with our own, chain up to parent call when appropriate. + this._fsPlugin._viewsource_getAltViewNode = this._fsPlugin._getAltViewNode; + this._fsPlugin._getAltViewNode = function(){ + return self._sourceShown?self.sourceArea:this._viewsource_getAltViewNode(); + }; + } + + // Listen to the source area for key events as well, as we need to be able to hotkey toggle + // it from there too. + this.connect(this.sourceArea, "onkeydown", lang.hitch(this, function(e){ + if(this._sourceShown && e.keyCode == keys.F12 && e.ctrlKey && e.shiftKey){ + this.button.focus(); + this.button.set("checked", false); + setTimeout(lang.hitch(this, function(){ed.focus();}), 100); + event.stop(e); + } + })); + }, + + _stripScripts: function(html){ + // summary: + // Strips out script tags from the HTML used in editor. + // html: String + // The HTML to filter + // tags: + // private + if(html){ + // Look for closed and unclosed (malformed) script attacks. + html = html.replace(/<\s*script[^>]*>((.|\s)*?)<\\?\/\s*script\s*>/ig, ""); + html = html.replace(/<\s*script\b([^<>]|\s)*>?/ig, ""); + html = html.replace(/<[^>]*=(\s|)*[("|')]javascript:[^$1][(\s|.)]*[$1][^>]*>/ig, ""); + } + return html; + }, + + _stripComments: function(html){ + // summary: + // Strips out comments from the HTML used in editor. + // html: String + // The HTML to filter + // tags: + // private + if(html){ + html = html.replace(/<!--(.|\s){1,}?-->/g, ""); + } + return html; + }, + + _stripIFrames: function(html){ + // summary: + // Strips out iframe tags from the content, to avoid iframe script + // style injection attacks. + // html: String + // The HTML to filter + // tags: + // private + if(html){ + html = html.replace(/<\s*iframe[^>]*>((.|\s)*?)<\\?\/\s*iframe\s*>/ig, ""); + } + return html; + }, + + _filter: function(html){ + // summary: + // Internal function to perform some filtering on the HTML. + // html: String + // The HTML to filter + // tags: + // private + if(html){ + if(this.stripScripts){ + html = this._stripScripts(html); + } + if(this.stripComments){ + html = this._stripComments(html); + } + if(this.stripIFrames){ + html = this._stripIFrames(html); + } + } + return html; + }, + + setSourceAreaCaret: function(){ + // summary: + // Internal function to set the caret in the sourceArea + // to 0x0 + var global = win.global; + var elem = this.sourceArea; + focus.focus(elem); + if(this._sourceShown && !this.readOnly){ + if(has("ie")){ + if(this.sourceArea.createTextRange){ + var range = elem.createTextRange(); + range.collapse(true); + range.moveStart("character", -99999); // move to 0 + range.moveStart("character", 0); // delta from 0 is the correct position + range.moveEnd("character", 0); + range.select(); + } + }else if(global.getSelection){ + if(elem.setSelectionRange){ + elem.setSelectionRange(0,0); + } + } + } + }, + + destroy: function(){ + // summary: + // Over-ride to remove the node used to correct for IE's + // zoom bug. + if(this._ieFixNode){ + win.body().removeChild(this._ieFixNode); + } + if(this._resizer){ + clearTimeout(this._resizer); + delete this._resizer; + } + if(this._resizeHandle){ + this._resizeHandle.remove(); + delete this._resizeHandle; + } + this.inherited(arguments); + } +}); + +// Register this plugin. +// For back-compat accept "viewsource" (all lowercase) too, remove in 2.0 +_Plugin.registry["viewSource"] = _Plugin.registry["viewsource"] = function(args){ + return new ViewSource({ + readOnly: ("readOnly" in args)?args.readOnly:false, + stripComments: ("stripComments" in args)?args.stripComments:true, + stripScripts: ("stripScripts" in args)?args.stripScripts:true, + stripIFrames: ("stripIFrames" in args)?args.stripIFrames:true + }); +}; + + + + +return ViewSource; +}); diff --git a/js/dojo/dijit/_editor/range.js b/js/dojo/dijit/_editor/range.js new file mode 100644 index 0000000..8ddbb41 --- /dev/null +++ b/js/dojo/dijit/_editor/range.js @@ -0,0 +1,554 @@ +//>>built +define("dijit/_editor/range", [ + "dojo/_base/array", // array.every + "dojo/_base/declare", // declare + "dojo/_base/lang", // lang.isArray + "dojo/_base/window", // win.global + ".." // for exporting symbols to dijit, TODO: remove in 2.0 +], function(array, declare, lang, win, dijit){ + +// module: +// dijit/_editor/range +// summary: +// W3C range API + + +dijit.range={}; + +dijit.range.getIndex = function(/*DomNode*/node, /*DomNode*/parent){ +// dojo.profile.start("dijit.range.getIndex"); + var ret = [], retR = []; + var onode = node; + + var pnode, n; + while(node != parent){ + var i = 0; + pnode = node.parentNode; + while((n = pnode.childNodes[i++])){ + if(n === node){ + --i; + break; + } + } + //if(i>=pnode.childNodes.length){ + //dojo.debug("Error finding index of a node in dijit.range.getIndex"); + //} + ret.unshift(i); + retR.unshift(i - pnode.childNodes.length); + node = pnode; + } + + //normalized() can not be called so often to prevent + //invalidating selection/range, so we have to detect + //here that any text nodes in a row + if(ret.length > 0 && onode.nodeType == 3){ + n = onode.previousSibling; + while(n && n.nodeType == 3){ + ret[ret.length - 1]--; + n = n.previousSibling; + } + n = onode.nextSibling; + while(n && n.nodeType == 3){ + retR[retR.length - 1]++; + n = n.nextSibling; + } + } +// dojo.profile.end("dijit.range.getIndex"); + return {o: ret, r:retR}; +}; + +dijit.range.getNode = function(/*Array*/index, /*DomNode*/parent){ + if(!lang.isArray(index) || index.length == 0){ + return parent; + } + var node = parent; +// if(!node)debugger + array.every(index, function(i){ + if(i >= 0 && i < node.childNodes.length){ + node = node.childNodes[i]; + }else{ + node = null; + //console.debug('Error: can not find node with index',index,'under parent node',parent ); + return false; //terminate array.every + } + return true; //carry on the every loop + }); + + return node; +}; + +dijit.range.getCommonAncestor = function(n1, n2, root){ + root = root || n1.ownerDocument.body; + var getAncestors = function(n){ + var as = []; + while(n){ + as.unshift(n); + if(n !== root){ + n = n.parentNode; + }else{ + break; + } + } + return as; + }; + var n1as = getAncestors(n1); + var n2as = getAncestors(n2); + + var m = Math.min(n1as.length, n2as.length); + var com = n1as[0]; //at least, one element should be in the array: the root (BODY by default) + for(var i = 1; i < m; i++){ + if(n1as[i] === n2as[i]){ + com = n1as[i] + }else{ + break; + } + } + return com; +}; + +dijit.range.getAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){ + root = root || node.ownerDocument.body; + while(node && node !== root){ + var name = node.nodeName.toUpperCase(); + if(regex.test(name)){ + return node; + } + + node = node.parentNode; + } + return null; +}; + +dijit.range.BlockTagNames = /^(?:P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|DT|DE)$/; +dijit.range.getBlockAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){ + root = root || node.ownerDocument.body; + regex = regex || dijit.range.BlockTagNames; + var block = null, blockContainer; + while(node && node !== root){ + var name = node.nodeName.toUpperCase(); + if(!block && regex.test(name)){ + block = node; + } + if(!blockContainer && (/^(?:BODY|TD|TH|CAPTION)$/).test(name)){ + blockContainer = node; + } + + node = node.parentNode; + } + return {blockNode:block, blockContainer:blockContainer || node.ownerDocument.body}; +}; + +dijit.range.atBeginningOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){ + var atBeginning = false; + var offsetAtBeginning = (offset == 0); + if(!offsetAtBeginning && node.nodeType == 3){ //if this is a text node, check whether the left part is all space + if(/^[\s\xA0]+$/.test(node.nodeValue.substr(0, offset))){ + offsetAtBeginning = true; + } + } + if(offsetAtBeginning){ + var cnode = node; + atBeginning = true; + while(cnode && cnode !== container){ + if(cnode.previousSibling){ + atBeginning = false; + break; + } + cnode = cnode.parentNode; + } + } + return atBeginning; +}; + +dijit.range.atEndOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){ + var atEnd = false; + var offsetAtEnd = (offset == (node.length || node.childNodes.length)); + if(!offsetAtEnd && node.nodeType == 3){ //if this is a text node, check whether the right part is all space + if(/^[\s\xA0]+$/.test(node.nodeValue.substr(offset))){ + offsetAtEnd = true; + } + } + if(offsetAtEnd){ + var cnode = node; + atEnd = true; + while(cnode && cnode !== container){ + if(cnode.nextSibling){ + atEnd = false; + break; + } + cnode = cnode.parentNode; + } + } + return atEnd; +}; + +dijit.range.adjacentNoneTextNode = function(startnode, next){ + var node = startnode; + var len = (0 - startnode.length) || 0; + var prop = next ? 'nextSibling' : 'previousSibling'; + while(node){ + if(node.nodeType != 3){ + break; + } + len += node.length; + node = node[prop]; + } + return [node,len]; +}; + +dijit.range._w3c = Boolean(window['getSelection']); +dijit.range.create = function(/*Window?*/window){ + if(dijit.range._w3c){ + return (window || win.global).document.createRange(); + }else{//IE + return new dijit.range.W3CRange; + } +}; + +dijit.range.getSelection = function(/*Window*/win, /*Boolean?*/ignoreUpdate){ + if(dijit.range._w3c){ + return win.getSelection(); + }else{//IE + var s = new dijit.range.ie.selection(win); + if(!ignoreUpdate){ + s._getCurrentSelection(); + } + return s; + } +}; + +if(!dijit.range._w3c){ + dijit.range.ie = { + cachedSelection: {}, + selection: function(win){ + this._ranges = []; + this.addRange = function(r, /*boolean*/internal){ + this._ranges.push(r); + if(!internal){ + r._select(); + } + this.rangeCount = this._ranges.length; + }; + this.removeAllRanges = function(){ + //don't detach, the range may be used later +// for(var i=0;i<this._ranges.length;i++){ +// this._ranges[i].detach(); +// } + this._ranges = []; + this.rangeCount = 0; + }; + var _initCurrentRange = function(){ + var r = win.document.selection.createRange(); + var type = win.document.selection.type.toUpperCase(); + if(type == "CONTROL"){ + //TODO: multiple range selection(?) + return new dijit.range.W3CRange(dijit.range.ie.decomposeControlRange(r)); + }else{ + return new dijit.range.W3CRange(dijit.range.ie.decomposeTextRange(r)); + } + }; + this.getRangeAt = function(i){ + return this._ranges[i]; + }; + this._getCurrentSelection = function(){ + this.removeAllRanges(); + var r = _initCurrentRange(); + if(r){ + this.addRange(r, true); + this.isCollapsed = r.collapsed; + }else{ + this.isCollapsed = true; + } + }; + }, + decomposeControlRange: function(range){ + var firstnode = range.item(0), lastnode = range.item(range.length - 1); + var startContainer = firstnode.parentNode, endContainer = lastnode.parentNode; + var startOffset = dijit.range.getIndex(firstnode, startContainer).o[0]; + var endOffset = dijit.range.getIndex(lastnode, endContainer).o[0] + 1; + return [startContainer, startOffset,endContainer, endOffset]; + }, + getEndPoint: function(range, end){ + var atmrange = range.duplicate(); + atmrange.collapse(!end); + var cmpstr = 'EndTo' + (end ? 'End' : 'Start'); + var parentNode = atmrange.parentElement(); + + var startnode, startOffset, lastNode; + if(parentNode.childNodes.length > 0){ + array.every(parentNode.childNodes, function(node, i){ + var calOffset; + if(node.nodeType != 3){ + atmrange.moveToElementText(node); + + if(atmrange.compareEndPoints(cmpstr, range) > 0){ + //startnode = node.previousSibling; + if(lastNode && lastNode.nodeType == 3){ + //where shall we put the start? in the text node or after? + startnode = lastNode; + calOffset = true; + }else{ + startnode = parentNode; + startOffset = i; + return false; + } + }else{ + if(i == parentNode.childNodes.length - 1){ + startnode = parentNode; + startOffset = parentNode.childNodes.length; + return false; + } + } + }else{ + if(i == parentNode.childNodes.length - 1){//at the end of this node + startnode = node; + calOffset = true; + } + } + // try{ + if(calOffset && startnode){ + var prevnode = dijit.range.adjacentNoneTextNode(startnode)[0]; + if(prevnode){ + startnode = prevnode.nextSibling; + }else{ + startnode = parentNode.firstChild; //firstChild must be a text node + } + var prevnodeobj = dijit.range.adjacentNoneTextNode(startnode); + prevnode = prevnodeobj[0]; + var lenoffset = prevnodeobj[1]; + if(prevnode){ + atmrange.moveToElementText(prevnode); + atmrange.collapse(false); + }else{ + atmrange.moveToElementText(parentNode); + } + atmrange.setEndPoint(cmpstr, range); + startOffset = atmrange.text.length - lenoffset; + + return false; + } + // }catch(e){ debugger } + lastNode = node; + return true; + }); + }else{ + startnode = parentNode; + startOffset = 0; + } + + //if at the end of startnode and we are dealing with start container, then + //move the startnode to nextSibling if it is a text node + //TODO: do this for end container? + if(!end && startnode.nodeType == 1 && startOffset == startnode.childNodes.length){ + var nextnode = startnode.nextSibling; + if(nextnode && nextnode.nodeType == 3){ + startnode = nextnode; + startOffset = 0; + } + } + return [startnode, startOffset]; + }, + setEndPoint: function(range, container, offset){ + //text node + var atmrange = range.duplicate(), node, len; + if(container.nodeType != 3){ //normal node + if(offset > 0){ + node = container.childNodes[offset - 1]; + if(node){ + if(node.nodeType == 3){ + container = node; + offset = node.length; + //pass through + }else{ + if(node.nextSibling && node.nextSibling.nodeType == 3){ + container = node.nextSibling; + offset = 0; + //pass through + }else{ + atmrange.moveToElementText(node.nextSibling ? node : container); + var parent = node.parentNode; + var tempNode = parent.insertBefore(node.ownerDocument.createTextNode(' '), node.nextSibling); + atmrange.collapse(false); + parent.removeChild(tempNode); + } + } + } + }else{ + atmrange.moveToElementText(container); + atmrange.collapse(true); + } + } + if(container.nodeType == 3){ + var prevnodeobj = dijit.range.adjacentNoneTextNode(container); + var prevnode = prevnodeobj[0]; + len = prevnodeobj[1]; + if(prevnode){ + atmrange.moveToElementText(prevnode); + atmrange.collapse(false); + //if contentEditable is not inherit, the above collapse won't make the end point + //in the correctly position: it always has a -1 offset, so compensate it + if(prevnode.contentEditable != 'inherit'){ + len++; + } + }else{ + atmrange.moveToElementText(container.parentNode); + atmrange.collapse(true); + } + + offset += len; + if(offset > 0){ + if(atmrange.move('character', offset) != offset){ + console.error('Error when moving!'); + } + } + } + + return atmrange; + }, + decomposeTextRange: function(range){ + var tmpary = dijit.range.ie.getEndPoint(range); + var startContainer = tmpary[0], startOffset = tmpary[1]; + var endContainer = tmpary[0], endOffset = tmpary[1]; + + if(range.htmlText.length){ + if(range.htmlText == range.text){ //in the same text node + endOffset = startOffset + range.text.length; + }else{ + tmpary = dijit.range.ie.getEndPoint(range, true); + endContainer = tmpary[0],endOffset = tmpary[1]; +// if(startContainer.tagName == "BODY"){ +// startContainer = startContainer.firstChild; +// } + } + } + return [startContainer, startOffset, endContainer, endOffset]; + }, + setRange: function(range, startContainer, startOffset, endContainer, endOffset, collapsed){ + var start = dijit.range.ie.setEndPoint(range, startContainer, startOffset); + + range.setEndPoint('StartToStart', start); + if(!collapsed){ + var end = dijit.range.ie.setEndPoint(range, endContainer, endOffset); + } + range.setEndPoint('EndToEnd', end || start); + + return range; + } + }; + +declare("dijit.range.W3CRange",null, { + constructor: function(){ + if(arguments.length>0){ + this.setStart(arguments[0][0],arguments[0][1]); + this.setEnd(arguments[0][2],arguments[0][3]); + }else{ + this.commonAncestorContainer = null; + this.startContainer = null; + this.startOffset = 0; + this.endContainer = null; + this.endOffset = 0; + this.collapsed = true; + } + }, + _updateInternal: function(){ + if(this.startContainer !== this.endContainer){ + this.commonAncestorContainer = dijit.range.getCommonAncestor(this.startContainer, this.endContainer); + }else{ + this.commonAncestorContainer = this.startContainer; + } + this.collapsed = (this.startContainer === this.endContainer) && (this.startOffset == this.endOffset); + }, + setStart: function(node, offset){ + offset=parseInt(offset); + if(this.startContainer === node && this.startOffset == offset){ + return; + } + delete this._cachedBookmark; + + this.startContainer = node; + this.startOffset = offset; + if(!this.endContainer){ + this.setEnd(node, offset); + }else{ + this._updateInternal(); + } + }, + setEnd: function(node, offset){ + offset=parseInt(offset); + if(this.endContainer === node && this.endOffset == offset){ + return; + } + delete this._cachedBookmark; + + this.endContainer = node; + this.endOffset = offset; + if(!this.startContainer){ + this.setStart(node, offset); + }else{ + this._updateInternal(); + } + }, + setStartAfter: function(node, offset){ + this._setPoint('setStart', node, offset, 1); + }, + setStartBefore: function(node, offset){ + this._setPoint('setStart', node, offset, 0); + }, + setEndAfter: function(node, offset){ + this._setPoint('setEnd', node, offset, 1); + }, + setEndBefore: function(node, offset){ + this._setPoint('setEnd', node, offset, 0); + }, + _setPoint: function(what, node, offset, ext){ + var index = dijit.range.getIndex(node, node.parentNode).o; + this[what](node.parentNode, index.pop()+ext); + }, + _getIERange: function(){ + var r = (this._body || this.endContainer.ownerDocument.body).createTextRange(); + dijit.range.ie.setRange(r, this.startContainer, this.startOffset, this.endContainer, this.endOffset, this.collapsed); + return r; + }, + getBookmark: function(){ + this._getIERange(); + return this._cachedBookmark; + }, + _select: function(){ + var r = this._getIERange(); + r.select(); + }, + deleteContents: function(){ + var s = this.startContainer, r = this._getIERange(); + if(s.nodeType === 3 && !this.startOffset){ + //if the range starts at the beginning of a + //text node, move it to before the textnode + //to make sure the range is still valid + //after deleteContents() finishes + this.setStartBefore(s); + } + r.pasteHTML(''); + this.endContainer = this.startContainer; + this.endOffset = this.startOffset; + this.collapsed = true; + }, + cloneRange: function(){ + var r = new dijit.range.W3CRange([this.startContainer,this.startOffset, + this.endContainer,this.endOffset]); + r._body = this._body; + return r; + }, + detach: function(){ + this._body = null; + this.commonAncestorContainer = null; + this.startContainer = null; + this.startOffset = 0; + this.endContainer = null; + this.endOffset = 0; + this.collapsed = true; +} +}); +} //if(!dijit.range._w3c) + + +return dijit.range; +}); diff --git a/js/dojo/dijit/_editor/selection.js b/js/dojo/dijit/_editor/selection.js new file mode 100644 index 0000000..05340e5 --- /dev/null +++ b/js/dojo/dijit/_editor/selection.js @@ -0,0 +1,373 @@ +//>>built +define("dijit/_editor/selection", [ + "dojo/dom", // dom.byId + "dojo/_base/lang", + "dojo/_base/sniff", // has("ie") has("opera") + "dojo/_base/window", // win.body win.doc win.doc.createElement win.doc.selection win.doc.selection.createRange win.doc.selection.type.toLowerCase win.global win.global.getSelection + ".." // for exporting symbols to dijit._editor.selection (TODO: remove in 2.0) +], function(dom, lang, has, win, dijit){ + +// module: +// dijit/_editor/selection +// summary: +// Text selection API + + +lang.getObject("_editor.selection", true, dijit); + +// FIXME: +// all of these methods branch internally for IE. This is probably +// sub-optimal in terms of runtime performance. We should investigate the +// size difference for differentiating at definition time. + +lang.mixin(dijit._editor.selection, { + getType: function(){ + // summary: + // Get the selection type (like win.doc.select.type in IE). + if(has("ie") < 9){ + return win.doc.selection.type.toLowerCase(); + }else{ + var stype = "text"; + + // Check if the actual selection is a CONTROL (IMG, TABLE, HR, etc...). + var oSel; + try{ + oSel = win.global.getSelection(); + }catch(e){ /*squelch*/ } + + if(oSel && oSel.rangeCount == 1){ + var oRange = oSel.getRangeAt(0); + if( (oRange.startContainer == oRange.endContainer) && + ((oRange.endOffset - oRange.startOffset) == 1) && + (oRange.startContainer.nodeType != 3 /* text node*/) + ){ + stype = "control"; + } + } + return stype; //String + } + }, + + getSelectedText: function(){ + // summary: + // Return the text (no html tags) included in the current selection or null if no text is selected + if(has("ie") < 9){ + if(dijit._editor.selection.getType() == 'control'){ + return null; + } + return win.doc.selection.createRange().text; + }else{ + var selection = win.global.getSelection(); + if(selection){ + return selection.toString(); //String + } + } + return ''; + }, + + getSelectedHtml: function(){ + // summary: + // Return the html text of the current selection or null if unavailable + if(has("ie") < 9){ + if(dijit._editor.selection.getType() == 'control'){ + return null; + } + return win.doc.selection.createRange().htmlText; + }else{ + var selection = win.global.getSelection(); + if(selection && selection.rangeCount){ + var i; + var html = ""; + for(i = 0; i < selection.rangeCount; i++){ + //Handle selections spanning ranges, such as Opera + var frag = selection.getRangeAt(i).cloneContents(); + var div = win.doc.createElement("div"); + div.appendChild(frag); + html += div.innerHTML; + } + return html; //String + } + return null; + } + }, + + getSelectedElement: function(){ + // summary: + // Retrieves the selected element (if any), just in the case that + // a single element (object like and image or a table) is + // selected. + if(dijit._editor.selection.getType() == "control"){ + if(has("ie") < 9){ + var range = win.doc.selection.createRange(); + if(range && range.item){ + return win.doc.selection.createRange().item(0); + } + }else{ + var selection = win.global.getSelection(); + return selection.anchorNode.childNodes[ selection.anchorOffset ]; + } + } + return null; + }, + + getParentElement: function(){ + // summary: + // Get the parent element of the current selection + if(dijit._editor.selection.getType() == "control"){ + var p = this.getSelectedElement(); + if(p){ return p.parentNode; } + }else{ + if(has("ie") < 9){ + var r = win.doc.selection.createRange(); + r.collapse(true); + return r.parentElement(); + }else{ + var selection = win.global.getSelection(); + if(selection){ + var node = selection.anchorNode; + while(node && (node.nodeType != 1)){ // not an element + node = node.parentNode; + } + return node; + } + } + } + return null; + }, + + hasAncestorElement: function(/*String*/tagName /* ... */){ + // summary: + // Check whether current selection has a parent element which is + // of type tagName (or one of the other specified tagName) + // tagName: String + // The tag name to determine if it has an ancestor of. + return this.getAncestorElement.apply(this, arguments) != null; //Boolean + }, + + getAncestorElement: function(/*String*/tagName /* ... */){ + // summary: + // Return the parent element of the current selection which is of + // type tagName (or one of the other specified tagName) + // tagName: String + // The tag name to determine if it has an ancestor of. + var node = this.getSelectedElement() || this.getParentElement(); + return this.getParentOfType(node, arguments); //DOMNode + }, + + isTag: function(/*DomNode*/ node, /*String[]*/ tags){ + // summary: + // Function to determine if a node is one of an array of tags. + // node: + // The node to inspect. + // tags: + // An array of tag name strings to check to see if the node matches. + if(node && node.tagName){ + var _nlc = node.tagName.toLowerCase(); + for(var i=0; i<tags.length; i++){ + var _tlc = String(tags[i]).toLowerCase(); + if(_nlc == _tlc){ + return _tlc; // String + } + } + } + return ""; + }, + + getParentOfType: function(/*DomNode*/ node, /*String[]*/ tags){ + // summary: + // Function to locate a parent node that matches one of a set of tags + // node: + // The node to inspect. + // tags: + // An array of tag name strings to check to see if the node matches. + while(node){ + if(this.isTag(node, tags).length){ + return node; // DOMNode + } + node = node.parentNode; + } + return null; + }, + + collapse: function(/*Boolean*/beginning){ + // summary: + // Function to collapse (clear), the current selection + // beginning: Boolean + // Boolean to indicate whether to collapse the cursor to the beginning of the selection or end. + if(window.getSelection){ + var selection = win.global.getSelection(); + if(selection.removeAllRanges){ // Mozilla + if(beginning){ + selection.collapseToStart(); + }else{ + selection.collapseToEnd(); + } + }else{ // Safari + // pulled from WebCore/ecma/kjs_window.cpp, line 2536 + selection.collapse(beginning); + } + }else if(has("ie")){ // IE + var range = win.doc.selection.createRange(); + range.collapse(beginning); + range.select(); + } + }, + + remove: function(){ + // summary: + // Function to delete the currently selected content from the document. + var sel = win.doc.selection; + if(has("ie") < 9){ + if(sel.type.toLowerCase() != "none"){ + sel.clear(); + } + return sel; //Selection + }else{ + sel = win.global.getSelection(); + sel.deleteFromDocument(); + return sel; //Selection + } + }, + + selectElementChildren: function(/*DomNode*/element,/*Boolean?*/nochangefocus){ + // summary: + // clear previous selection and select the content of the node + // (excluding the node itself) + // element: DOMNode + // The element you wish to select the children content of. + // nochangefocus: Boolean + // Boolean to indicate if the foxus should change or not. + var global = win.global; + var doc = win.doc; + var range; + element = dom.byId(element); + if(doc.selection && has("ie") < 9 && win.body().createTextRange){ // IE + range = element.ownerDocument.body.createTextRange(); + range.moveToElementText(element); + if(!nochangefocus){ + try{ + range.select(); // IE throws an exception here if the widget is hidden. See #5439 + }catch(e){ /* squelch */} + } + }else if(global.getSelection){ + var selection = win.global.getSelection(); + if(has("opera")){ + //Opera's selectAllChildren doesn't seem to work right + //against <body> nodes and possibly others ... so + //we use the W3C range API + if(selection.rangeCount){ + range = selection.getRangeAt(0); + }else{ + range = doc.createRange(); + } + range.setStart(element, 0); + range.setEnd(element,(element.nodeType == 3)?element.length:element.childNodes.length); + selection.addRange(range); + }else{ + selection.selectAllChildren(element); + } + } + }, + + selectElement: function(/*DomNode*/element,/*Boolean?*/nochangefocus){ + // summary: + // clear previous selection and select element (including all its children) + // element: DOMNode + // The element to select. + // nochangefocus: Boolean + // Boolean indicating if the focus should be changed. IE only. + var range; + var doc = win.doc; + var global = win.global; + element = dom.byId(element); + if(has("ie") < 9 && win.body().createTextRange){ + try{ + var tg = element.tagName ? element.tagName.toLowerCase() : ""; + if(tg === "img" || tg === "table"){ + range = win.body().createControlRange(); + }else{ + range = win.body().createRange(); + } + range.addElement(element); + if(!nochangefocus){ + range.select(); + } + }catch(e){ + this.selectElementChildren(element,nochangefocus); + } + }else if(global.getSelection){ + var selection = global.getSelection(); + range = doc.createRange(); + if(selection.removeAllRanges){ // Mozilla + // FIXME: does this work on Safari? + if(has("opera")){ + //Opera works if you use the current range on + //the selection if present. + if(selection.getRangeAt(0)){ + range = selection.getRangeAt(0); + } + } + range.selectNode(element); + selection.removeAllRanges(); + selection.addRange(range); + } + } + }, + + inSelection: function(node){ + // summary: + // This function determines if 'node' is + // in the current selection. + // tags: + // public + if(node){ + var newRange; + var doc = win.doc; + var range; + + if(win.global.getSelection){ + //WC3 + var sel = win.global.getSelection(); + if(sel && sel.rangeCount > 0){ + range = sel.getRangeAt(0); + } + if(range && range.compareBoundaryPoints && doc.createRange){ + try{ + newRange = doc.createRange(); + newRange.setStart(node, 0); + if(range.compareBoundaryPoints(range.START_TO_END, newRange) === 1){ + return true; + } + }catch(e){ /* squelch */} + } + }else if(doc.selection){ + // Probably IE, so we can't use the range object as the pseudo + // range doesn't implement the boundry checking, we have to + // use IE specific crud. + range = doc.selection.createRange(); + try{ + newRange = node.ownerDocument.body.createControlRange(); + if(newRange){ + newRange.addElement(node); + } + }catch(e1){ + try{ + newRange = node.ownerDocument.body.createTextRange(); + newRange.moveToElementText(node); + }catch(e2){/* squelch */} + } + if(range && newRange){ + // We can finally compare similar to W3C + if(range.compareEndPoints("EndToStart", newRange) === 1){ + return true; + } + } + } + } + return false; // boolean + } + +}); + +return dijit._editor.selection; +}); |
