diff options
Diffstat (limited to 'includes/js/dijit/Editor.js')
-rw-r--r-- | includes/js/dijit/Editor.js | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/includes/js/dijit/Editor.js b/includes/js/dijit/Editor.js new file mode 100644 index 0000000..36f8096 --- /dev/null +++ b/includes/js/dijit/Editor.js @@ -0,0 +1,373 @@ +if(!dojo._hasResource["dijit.Editor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit.Editor"] = true; +dojo.provide("dijit.Editor"); +dojo.require("dijit._editor.RichText"); +dojo.require("dijit.Toolbar"); +dojo.require("dijit._editor._Plugin"); +dojo.require("dijit._Container"); +dojo.require("dojo.i18n"); +dojo.requireLocalization("dijit._editor", "commands", null, "zh,pt,da,tr,ru,de,sv,ja,he,fi,nb,el,ar,pt-pt,cs,fr,es,ko,nl,zh-tw,pl,it,hu,ROOT"); + +dojo.declare( + "dijit.Editor", + dijit._editor.RichText, + { + // summary: A rich-text Editing widget + + // plugins: Array + // a list of plugin names (as strings) or instances (as objects) + // for this widget. + plugins: null, + + // extraPlugins: Array + // a list of extra plugin names which will be appended to plugins array + extraPlugins: null, + + constructor: function(){ + if(!dojo.isArray(this.plugins)){ + this.plugins=["undo","redo","|","cut","copy","paste","|","bold","italic","underline","strikethrough","|", + "insertOrderedList","insertUnorderedList","indent","outdent","|","justifyLeft","justifyRight","justifyCenter","justifyFull"/*"createLink"*/]; + } + + this._plugins=[]; + this._editInterval = this.editActionInterval * 1000; + }, + + postCreate: function(){ + //for custom undo/redo + if(this.customUndo){ + dojo['require']("dijit._editor.range"); + this._steps=this._steps.slice(0); + this._undoedSteps=this._undoedSteps.slice(0); +// this.addKeyHandler('z',this.KEY_CTRL,this.undo); +// this.addKeyHandler('y',this.KEY_CTRL,this.redo); + } + if(dojo.isArray(this.extraPlugins)){ + this.plugins=this.plugins.concat(this.extraPlugins); + } + +// try{ + this.inherited(arguments); +// dijit.Editor.superclass.postCreate.apply(this, arguments); + + this.commands = dojo.i18n.getLocalization("dijit._editor", "commands", this.lang); + + if(!this.toolbar){ + // if we haven't been assigned a toolbar, create one + this.toolbar = new dijit.Toolbar({}); + dojo.place(this.toolbar.domNode, this.editingArea, "before"); + } + + dojo.forEach(this.plugins, this.addPlugin, this); + this.onNormalizedDisplayChanged(); //update toolbar button status +// }catch(e){ console.debug(e); } + }, + destroy: function(){ + dojo.forEach(this._plugins, function(p){ + if(p && p.destroy){ + p.destroy(); + } + }); + this._plugins=[]; + this.toolbar.destroy(); delete this.toolbar; + this.inherited(arguments); + }, + addPlugin: function(/*String||Object*/plugin, /*Integer?*/index){ + // summary: + // takes a plugin name as a string or a plugin instance and + // adds it to the toolbar and associates it with this editor + // instance. The resulting plugin is added to the Editor's + // plugins array. If index is passed, it's placed in the plugins + // array at that index. No big magic, but a nice helper for + // passing in plugin names via markup. + // plugin: String, args object or plugin instance. Required. + // args: This object will be passed to the plugin constructor. + // index: + // Integer, optional. Used when creating an instance from + // something already in this.plugins. Ensures that the new + // instance is assigned to this.plugins at that index. + var args=dojo.isString(plugin)?{name:plugin}:plugin; + if(!args.setEditor){ + var o={"args":args,"plugin":null,"editor":this}; + dojo.publish(dijit._scopeName + ".Editor.getPlugin",[o]); + if(!o.plugin){ + var pc = dojo.getObject(args.name); + if(pc){ + o.plugin=new pc(args); + } + } + if(!o.plugin){ + console.warn('Cannot find plugin',plugin); + return; + } + plugin=o.plugin; + } + if(arguments.length > 1){ + this._plugins[index] = plugin; + }else{ + this._plugins.push(plugin); + } + plugin.setEditor(this); + if(dojo.isFunction(plugin.setToolbar)){ + plugin.setToolbar(this.toolbar); + } + }, + /* beginning of custom undo/redo support */ + + // customUndo: Boolean + // Whether we shall use custom undo/redo support instead of the native + // browser support. By default, we only enable customUndo for IE, as it + // has broken native undo/redo support. Note: the implementation does + // support other browsers which have W3C DOM2 Range API. + customUndo: dojo.isIE, + + // editActionInterval: Integer + // When using customUndo, not every keystroke will be saved as a step. + // Instead typing (including delete) will be grouped together: after + // a user stop typing for editActionInterval seconds, a step will be + // saved; if a user resume typing within editActionInterval seconds, + // the timeout will be restarted. By default, editActionInterval is 3 + // seconds. + editActionInterval: 3, + beginEditing: function(cmd){ + if(!this._inEditing){ + this._inEditing=true; + this._beginEditing(cmd); + } + if(this.editActionInterval>0){ + if(this._editTimer){ + clearTimeout(this._editTimer); + } + this._editTimer = setTimeout(dojo.hitch(this, this.endEditing), this._editInterval); + } + }, + _steps:[], + _undoedSteps:[], + execCommand: function(cmd){ + if(this.customUndo && (cmd=='undo' || cmd=='redo')){ + return this[cmd](); + }else{ + try{ + if(this.customUndo){ + this.endEditing(); + this._beginEditing(); + } + var r = this.inherited('execCommand',arguments); + if(this.customUndo){ + this._endEditing(); + } + return r; + }catch(e){ + if(dojo.isMoz && /copy|cut|paste/.test(cmd)){ + // Warn user of platform limitation. Cannot programmatically access keyboard. See ticket #4136 + var sub = dojo.string.substitute, + accel = {cut:'X', copy:'C', paste:'V'}, + isMac = navigator.userAgent.indexOf("Macintosh") != -1; + alert(sub(this.commands.systemShortcutFF, + [this.commands[cmd], sub(this.commands[isMac ? 'appleKey' : 'ctrlKey'], [accel[cmd]])])); + } + return false; + } + } + }, + queryCommandEnabled: function(cmd){ + if(this.customUndo && (cmd=='undo' || cmd=='redo')){ + return cmd=='undo'?(this._steps.length>1):(this._undoedSteps.length>0); + }else{ + return this.inherited('queryCommandEnabled',arguments); + } + }, + _moveToBookmark: function(b){ + var bookmark=b; + if(dojo.isIE){ + if(dojo.isArray(b)){//IE CONTROL + bookmark=[]; + dojo.forEach(b,function(n){ + bookmark.push(dijit.range.getNode(n,this.editNode)); + },this); + } + }else{//w3c range + var r=dijit.range.create(); + r.setStart(dijit.range.getNode(b.startContainer,this.editNode),b.startOffset); + r.setEnd(dijit.range.getNode(b.endContainer,this.editNode),b.endOffset); + bookmark=r; + } + dojo.withGlobal(this.window,'moveToBookmark',dijit,[bookmark]); + }, + _changeToStep: function(from,to){ + this.setValue(to.text); + var b=to.bookmark; + if(!b){ return; } + this._moveToBookmark(b); + }, + undo: function(){ +// console.log('undo'); + this.endEditing(true); + var s=this._steps.pop(); + if(this._steps.length>0){ + this.focus(); + this._changeToStep(s,this._steps[this._steps.length-1]); + this._undoedSteps.push(s); + this.onDisplayChanged(); + return true; + } + return false; + }, + redo: function(){ +// console.log('redo'); + this.endEditing(true); + var s=this._undoedSteps.pop(); + if(s && this._steps.length>0){ + this.focus(); + this._changeToStep(this._steps[this._steps.length-1],s); + this._steps.push(s); + this.onDisplayChanged(); + return true; + } + return false; + }, + endEditing: function(ignore_caret){ + if(this._editTimer){ + clearTimeout(this._editTimer); + } + if(this._inEditing){ + this._endEditing(ignore_caret); + this._inEditing=false; + } + }, + _getBookmark: function(){ + var b=dojo.withGlobal(this.window,dijit.getBookmark); + var tmp=[]; + if(dojo.isIE){ + if(dojo.isArray(b)){//CONTROL + dojo.forEach(b,function(n){ + tmp.push(dijit.range.getIndex(n,this.editNode).o); + },this); + b=tmp; + } + }else{//w3c range + tmp=dijit.range.getIndex(b.startContainer,this.editNode).o; + b={startContainer:tmp, + startOffset:b.startOffset, + endContainer:b.endContainer===b.startContainer?tmp:dijit.range.getIndex(b.endContainer,this.editNode).o, + endOffset:b.endOffset}; + } + return b; + }, + _beginEditing: function(cmd){ + if(this._steps.length===0){ + this._steps.push({'text':this.savedContent,'bookmark':this._getBookmark()}); + } + }, + _endEditing: function(ignore_caret){ + var v=this.getValue(true); + + this._undoedSteps=[];//clear undoed steps + this._steps.push({text: v, bookmark: this._getBookmark()}); + }, + onKeyDown: function(e){ + if(!this.customUndo){ + this.inherited('onKeyDown',arguments); + return; + } + var k = e.keyCode, ks = dojo.keys; + if(e.ctrlKey && !e.altKey){//undo and redo only if the special right Alt + z/y are not pressed #5892 + if(k == 90 || k == 122){ //z + dojo.stopEvent(e); + this.undo(); + return; + }else if(k == 89 || k == 121){ //y + dojo.stopEvent(e); + this.redo(); + return; + } + } + this.inherited('onKeyDown',arguments); + + switch(k){ + case ks.ENTER: + case ks.BACKSPACE: + case ks.DELETE: + this.beginEditing(); + break; + case 88: //x + case 86: //v + if(e.ctrlKey && !e.altKey && !e.metaKey){ + this.endEditing();//end current typing step if any + if(e.keyCode == 88){ + this.beginEditing('cut'); + //use timeout to trigger after the cut is complete + setTimeout(dojo.hitch(this, this.endEditing), 1); + }else{ + this.beginEditing('paste'); + //use timeout to trigger after the paste is complete + setTimeout(dojo.hitch(this, this.endEditing), 1); + } + break; + } + //pass through + default: + if(!e.ctrlKey && !e.altKey && !e.metaKey && (e.keyCode<dojo.keys.F1 || e.keyCode>dojo.keys.F15)){ + this.beginEditing(); + break; + } + //pass through + case ks.ALT: + this.endEditing(); + break; + case ks.UP_ARROW: + case ks.DOWN_ARROW: + case ks.LEFT_ARROW: + case ks.RIGHT_ARROW: + case ks.HOME: + case ks.END: + case ks.PAGE_UP: + case ks.PAGE_DOWN: + this.endEditing(true); + break; + //maybe ctrl+backspace/delete, so don't endEditing when ctrl is pressed + case ks.CTRL: + case ks.SHIFT: + case ks.TAB: + break; + } + }, + _onBlur: function(){ + this.inherited('_onBlur',arguments); + this.endEditing(true); + }, + onClick: function(){ + this.endEditing(true); + this.inherited('onClick',arguments); + } + /* end of custom undo/redo support */ + } +); + +/* the following code is to registered a handler to get default plugins */ +dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){ + if(o.plugin){ return; } + var args = o.args, p; + var _p = dijit._editor._Plugin; + var name = args.name; + switch(name){ + case "undo": case "redo": case "cut": case "copy": case "paste": case "insertOrderedList": + case "insertUnorderedList": case "indent": case "outdent": case "justifyCenter": + case "justifyFull": case "justifyLeft": case "justifyRight": case "delete": + case "selectAll": case "removeFormat": + case "insertHorizontalRule": + p = new _p({ command: name }); + break; + + case "bold": case "italic": case "underline": case "strikethrough": + case "subscript": case "superscript": + p = new _p({ buttonClass: dijit.form.ToggleButton, command: name }); + break; + case "|": + p = new _p({ button: new dijit.ToolbarSeparator() }); + } +// console.log('name',name,p); + o.plugin=p; +}); + +} |