]> git.wh0rd.org - tt-rss.git/blame - lib/dijit/_editor/_Plugin.js
remove call-by-reference to comply with php 5.4
[tt-rss.git] / lib / dijit / _editor / _Plugin.js
CommitLineData
2f01fe57 1/*
81bea17a 2 Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
2f01fe57
AD
3 Available via Academic Free License >= 2.1 OR the modified BSD license.
4 see: http://dojotoolkit.org/license for details
5*/
6
7
81bea17a
AD
8if(!dojo._hasResource["dijit._editor._Plugin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
9dojo._hasResource["dijit._editor._Plugin"] = true;
2f01fe57
AD
10dojo.provide("dijit._editor._Plugin");
11dojo.require("dijit._Widget");
12dojo.require("dijit.form.Button");
81bea17a
AD
13
14
15dojo.declare("dijit._editor._Plugin", null, {
16 // summary
17 // Base class for a "plugin" to the editor, which is usually
18 // a single button on the Toolbar and some associated code
19
20 constructor: function(/*Object?*/args, /*DomNode?*/node){
21 this.params = args || {};
22 dojo.mixin(this, this.params);
23 this._connects=[];
24 this._attrPairNames = {};
25 },
26
27 // editor: [const] dijit.Editor
28 // Points to the parent editor
29 editor: null,
30
31 // iconClassPrefix: [const] String
32 // The CSS class name for the button node is formed from `iconClassPrefix` and `command`
33 iconClassPrefix: "dijitEditorIcon",
34
35 // button: dijit._Widget?
36 // Pointer to `dijit.form.Button` or other widget (ex: `dijit.form.FilteringSelect`)
37 // that is added to the toolbar to control this plugin.
38 // If not specified, will be created on initialization according to `buttonClass`
39 button: null,
40
41 // command: String
42 // String like "insertUnorderedList", "outdent", "justifyCenter", etc. that represents an editor command.
43 // Passed to editor.execCommand() if `useDefaultCommand` is true.
44 command: "",
45
46 // useDefaultCommand: Boolean
47 // If true, this plugin executes by calling Editor.execCommand() with the argument specified in `command`.
48 useDefaultCommand: true,
49
50 // buttonClass: Widget Class
51 // Class of widget (ex: dijit.form.Button or dijit.form.FilteringSelect)
52 // that is added to the toolbar to control this plugin.
53 // This is used to instantiate the button, unless `button` itself is specified directly.
54 buttonClass: dijit.form.Button,
55
56 // disabled: Boolean
57 // Flag to indicate if this plugin has been disabled and should do nothing
58 // helps control button state, among other things. Set via the setter api.
59 disabled: false,
60
61 getLabel: function(/*String*/key){
62 // summary:
63 // Returns the label to use for the button
64 // tags:
65 // private
66 return this.editor.commands[key]; // String
67 },
68
69 _initButton: function(){
70 // summary:
71 // Initialize the button or other widget that will control this plugin.
72 // This code only works for plugins controlling built-in commands in the editor.
73 // tags:
74 // protected extension
75 if(this.command.length){
76 var label = this.getLabel(this.command),
77 editor = this.editor,
78 className = this.iconClassPrefix+" "+this.iconClassPrefix + this.command.charAt(0).toUpperCase() + this.command.substr(1);
79 if(!this.button){
80 var props = dojo.mixin({
81 label: label,
82 dir: editor.dir,
83 lang: editor.lang,
84 showLabel: false,
85 iconClass: className,
86 dropDown: this.dropDown,
87 tabIndex: "-1"
88 }, this.params || {});
89 this.button = new this.buttonClass(props);
90 }
91 }
92 if(this.get("disabled") && this.button){
93 this.button.set("disabled", this.get("disabled"));
94 }
95 },
96
97 destroy: function(){
98 // summary:
99 // Destroy this plugin
100
101 dojo.forEach(this._connects, dojo.disconnect);
102 if(this.dropDown){
103 this.dropDown.destroyRecursive();
104 }
105 },
106
107 connect: function(o, f, tf){
108 // summary:
109 // Make a dojo.connect() that is automatically disconnected when this plugin is destroyed.
110 // Similar to `dijit._Widget.connect`.
111 // tags:
112 // protected
113 this._connects.push(dojo.connect(o, f, this, tf));
114 },
115
116 updateState: function(){
117 // summary:
118 // Change state of the plugin to respond to events in the editor.
119 // description:
120 // This is called on meaningful events in the editor, such as change of selection
121 // or caret position (but not simple typing of alphanumeric keys). It gives the
122 // plugin a chance to update the CSS of its button.
123 //
124 // For example, the "bold" plugin will highlight/unhighlight the bold button depending on whether the
125 // characters next to the caret are bold or not.
126 //
127 // Only makes sense when `useDefaultCommand` is true, as it calls Editor.queryCommandEnabled(`command`).
128 var e = this.editor,
129 c = this.command,
130 checked, enabled;
131 if(!e || !e.isLoaded || !c.length){ return; }
132 var disabled = this.get("disabled");
133 if(this.button){
134 try{
135 enabled = !disabled && e.queryCommandEnabled(c);
136 if(this.enabled !== enabled){
137 this.enabled = enabled;
138 this.button.set('disabled', !enabled);
139 }
140 if(typeof this.button.checked == 'boolean'){
141 checked = e.queryCommandState(c);
142 if(this.checked !== checked){
143 this.checked = checked;
144 this.button.set('checked', e.queryCommandState(c));
145 }
146 }
147 }catch(e){
148 console.log(e); // FIXME: we shouldn't have debug statements in our code. Log as an error?
149 }
150 }
151 },
152
153 setEditor: function(/*dijit.Editor*/ editor){
154 // summary:
155 // Tell the plugin which Editor it is associated with.
156
157 // TODO: refactor code to just pass editor to constructor.
158
159 // FIXME: detach from previous editor!!
160 this.editor = editor;
161
162 // FIXME: prevent creating this if we don't need to (i.e., editor can't handle our command)
163 this._initButton();
164
165 // Processing for buttons that execute by calling editor.execCommand()
166 if(this.button && this.useDefaultCommand){
167 if(this.editor.queryCommandAvailable(this.command)){
168 this.connect(this.button, "onClick",
169 dojo.hitch(this.editor, "execCommand", this.command, this.commandArg)
170 );
171 }else{
172 // hide button because editor doesn't support command (due to browser limitations)
173 this.button.domNode.style.display = "none";
174 }
175 }
176
177 this.connect(this.editor, "onNormalizedDisplayChanged", "updateState");
178 },
179
180 setToolbar: function(/*dijit.Toolbar*/ toolbar){
181 // summary:
182 // Tell the plugin to add it's controller widget (often a button)
183 // to the toolbar. Does nothing if there is no controller widget.
184
185 // TODO: refactor code to just pass toolbar to constructor.
186
187 if(this.button){
188 toolbar.addChild(this.button);
189 }
190 // console.debug("adding", this.button, "to:", toolbar);
191 },
192
193 set: function(/* attribute */ name, /* anything */ value){
194 // summary:
195 // Set a property on a plugin
196 // name:
197 // The property to set.
198 // value:
199 // The value to set in the property.
200 // description:
201 // Sets named properties on a plugin which may potentially be handled by a
202 // setter in the plugin.
203 // For example, if the plugin has a properties "foo"
204 // and "bar" and a method named "_setFooAttr", calling:
205 // | plugin.set("foo", "Howdy!");
206 // would be equivalent to writing:
207 // | plugin._setFooAttr("Howdy!");
208 // and:
209 // | plugin.set("bar", 3);
210 // would be equivalent to writing:
211 // | plugin.bar = 3;
212 //
213 // set() may also be called with a hash of name/value pairs, ex:
214 // | plugin.set({
215 // | foo: "Howdy",
216 // | bar: 3
217 // | })
218 // This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
219 if(typeof name === "object"){
220 for(var x in name){
221 this.set(x, name[x]);
222 }
223 return this;
224 }
225 var names = this._getAttrNames(name);
226 if(this[names.s]){
227 // use the explicit setter
228 var result = this[names.s].apply(this, Array.prototype.slice.call(arguments, 1));
229 }else{
230 this._set(name, value);
231 }
232 return result || this;
233 },
234
235 get: function(name){
236 // summary:
237 // Get a property from a plugin.
238 // name:
239 // The property to get.
240 // description:
241 // Get a named property from a plugin. The property may
242 // potentially be retrieved via a getter method. If no getter is defined, this
243 // just retrieves the object's property.
244 // For example, if the plugin has a properties "foo"
245 // and "bar" and a method named "_getFooAttr", calling:
246 // | plugin.get("foo");
247 // would be equivalent to writing:
248 // | plugin._getFooAttr();
249 // and:
250 // | plugin.get("bar");
251 // would be equivalent to writing:
252 // | plugin.bar;
253 var names = this._getAttrNames(name);
254 return this[names.g] ? this[names.g]() : this[name];
255 },
256
257 _setDisabledAttr: function(disabled){
258 // summary:
259 // Function to set the plugin state and call updateState to make sure the
260 // button is updated appropriately.
261 this.disabled = disabled;
262 this.updateState();
263 },
264
265 _getAttrNames: function(name){
266 // summary:
267 // Helper function for get() and set().
268 // Caches attribute name values so we don't do the string ops every time.
269 // tags:
270 // private
271
272 var apn = this._attrPairNames;
273 if(apn[name]){ return apn[name]; }
274 var uc = name.charAt(0).toUpperCase() + name.substr(1);
275 return (apn[name] = {
276 s: "_set"+uc+"Attr",
277 g: "_get"+uc+"Attr"
278 });
279 },
280
281 _set: function(/*String*/ name, /*anything*/ value){
282 // summary:
283 // Helper function to set new value for specified attribute
284 var oldValue = this[name];
285 this[name] = value;
286 }
287});
288
2f01fe57 289}