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.keyCodedojo.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; }); }