summaryrefslogtreecommitdiff
path: root/includes/js/dijit/Editor.js
diff options
context:
space:
mode:
Diffstat (limited to 'includes/js/dijit/Editor.js')
-rw-r--r--includes/js/dijit/Editor.js373
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;
+});
+
+}