Subversion Repositories Applications.papyrus

Rev

Blame | Last modification | View Log | RSS feed

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, "ko,zh,ja,zh-tw,ru,it,hu,fr,pt,pl,es,ROOT,de,cs");

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(){
                        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{
                        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
                                var toolbarNode = dojo.doc.createElement("div");
                                dojo.place(toolbarNode, this.editingArea, "before");
                                this.toolbar = new dijit.Toolbar({}, toolbarNode);
                        }

                        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.destroy){
                                        p.destroy();
                                }
                        });
                        this._plugins=[];
                        this.toolbar.destroy(); delete this.toolbar;
                        this.inherited('destroy',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.Editor.getPlugin",[o]);
                                if(!o.plugin){
                                        var pc = dojo.getObject(args.name);
                                        if(pc){
                                                o.plugin=new pc(args);
                                        }
                                }
                                if(!o.plugin){
                                        console.debug('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);
                        }
                },
                _changeToStep: function(from,to){
                        this.setValue(to.text);
                        var b=to.bookmark;
                        if(!b){ return; }
                        if(dojo.isIE){
                                if(dojo.isArray(b)){//IE CONTROL
                                        var tmp=[];
                                        dojo.forEach(b,function(n){
                                                tmp.push(dijit.range.getNode(n,this.editNode));
                                        },this);
                                        b=tmp;
                                }
                        }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);
                                b=r;
                        }
                        dojo.withGlobal(this.window,'moveToBookmark',dijit,[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);
                        if(dojo.isIE){
                                if(dojo.isArray(b)){//CONTROL
                                        var tmp=[];
                                        dojo.forEach(b,function(n){
                                                tmp.push(dijit.range.getIndex(n,this.editNode).o);
                                        },this);
                                        b=tmp;
                                }
                        }else{//w3c range
                                var 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){
                                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:
                                                this.beginEditing();
                                                break;
                                        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.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":
                        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() });
                        break;
                case "createLink":
//                                      dojo['require']('dijit._editor.plugins.LinkDialog');
                        p = new dijit._editor.plugins.LinkDialog({ command: name });
                        break;
                case "foreColor": case "hiliteColor":
                        p = new dijit._editor.plugins.TextColor({ command: name });
                        break;
                case "fontName": case "fontSize": case "formatBlock":
                        p = new dijit._editor.plugins.FontChoice({ command: name });
        }
//      console.log('name',name,p);
        o.plugin=p;
});

}