summaryrefslogtreecommitdiff
path: root/lib/dijit/_editor/_Plugin.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dijit/_editor/_Plugin.js')
-rw-r--r--lib/dijit/_editor/_Plugin.js342
1 files changed, 279 insertions, 63 deletions
diff --git a/lib/dijit/_editor/_Plugin.js b/lib/dijit/_editor/_Plugin.js
index f3c95aae0..2f769960d 100644
--- a/lib/dijit/_editor/_Plugin.js
+++ b/lib/dijit/_editor/_Plugin.js
@@ -1,73 +1,289 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._editor._Plugin"]){
-dojo._hasResource["dijit._editor._Plugin"]=true;
+if(!dojo._hasResource["dijit._editor._Plugin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._editor._Plugin"] = true;
dojo.provide("dijit._editor._Plugin");
dojo.require("dijit._Widget");
dojo.require("dijit.form.Button");
-dojo.declare("dijit._editor._Plugin",null,{constructor:function(_1,_2){
-this.params=_1||{};
-dojo.mixin(this,this.params);
-this._connects=[];
-},editor:null,iconClassPrefix:"dijitEditorIcon",button:null,command:"",useDefaultCommand:true,buttonClass:dijit.form.Button,getLabel:function(_3){
-return this.editor.commands[_3];
-},_initButton:function(){
-if(this.command.length){
-var _4=this.getLabel(this.command),_5=this.editor,_6=this.iconClassPrefix+" "+this.iconClassPrefix+this.command.charAt(0).toUpperCase()+this.command.substr(1);
-if(!this.button){
-var _7=dojo.mixin({label:_4,dir:_5.dir,lang:_5.lang,showLabel:false,iconClass:_6,dropDown:this.dropDown,tabIndex:"-1"},this.params||{});
-this.button=new this.buttonClass(_7);
-}
-}
-},destroy:function(){
-dojo.forEach(this._connects,dojo.disconnect);
-if(this.dropDown){
-this.dropDown.destroyRecursive();
-}
-},connect:function(o,f,tf){
-this._connects.push(dojo.connect(o,f,this,tf));
-},updateState:function(){
-var e=this.editor,c=this.command,_8,_9;
-if(!e||!e.isLoaded||!c.length){
-return;
-}
-if(this.button){
-try{
-_9=e.queryCommandEnabled(c);
-if(this.enabled!==_9){
-this.enabled=_9;
-this.button.set("disabled",!_9);
-}
-if(typeof this.button.checked=="boolean"){
-_8=e.queryCommandState(c);
-if(this.checked!==_8){
-this.checked=_8;
-this.button.set("checked",e.queryCommandState(c));
-}
-}
-}
-catch(e){
-}
-}
-},setEditor:function(_a){
-this.editor=_a;
-this._initButton();
-if(this.button&&this.useDefaultCommand){
-if(this.editor.queryCommandAvailable(this.command)){
-this.connect(this.button,"onClick",dojo.hitch(this.editor,"execCommand",this.command,this.commandArg));
-}else{
-this.button.domNode.style.display="none";
-}
-}
-this.connect(this.editor,"onNormalizedDisplayChanged","updateState");
-},setToolbar:function(_b){
-if(this.button){
-_b.addChild(this.button);
-}
-}});
+
+
+dojo.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, /*DomNode?*/node){
+ this.params = args || {};
+ dojo.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: dijit.form.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 = dojo.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
+
+ dojo.forEach(this._connects, dojo.disconnect);
+ if(this.dropDown){
+ this.dropDown.destroyRecursive();
+ }
+ },
+
+ connect: function(o, f, tf){
+ // summary:
+ // Make a dojo.connect() that is automatically disconnected when this plugin is destroyed.
+ // Similar to `dijit._Widget.connect`.
+ // tags:
+ // protected
+ this._connects.push(dojo.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",
+ dojo.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
+ var oldValue = this[name];
+ this[name] = value;
+ }
+});
+
}