]>
git.wh0rd.org - tt-rss.git/blob - lib/dijit/_editor/plugins/FontChoice.js.uncompressed.js
1 define("dijit/_editor/plugins/FontChoice", [
2 "dojo/_base/array", // array.indexOf array.map
3 "dojo/_base/declare", // declare
4 "dojo/dom-construct", // domConstruct.place
5 "dojo/i18n", // i18n.getLocalization
6 "dojo/_base/lang", // lang.delegate lang.hitch lang.isString
7 "dojo/store/Memory", // MemoryStore
8 "dojo/_base/window", // win.withGlobal
9 "../../registry", // registry.getUniqueId
11 "../../_TemplatedMixin",
12 "../../_WidgetsInTemplateMixin",
13 "../../form/FilteringSelect",
17 "dojo/i18n!../nls/FontChoice"
18 ], function(array
, declare
, domConstruct
, i18n
, lang
, MemoryStore
, win
,
19 registry
, _Widget
, _TemplatedMixin
, _WidgetsInTemplateMixin
, FilteringSelect
, _Plugin
, rangeapi
, selectionapi
){
22 var _Plugin = dijit._editor._Plugin;
23 var _Widget = dijit._Widget;
24 var _TemplatedMixin = dijit._TemplatedMixin;
25 var _WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
26 var FilteringSelect = dijit.form.FilteringSelect;
31 // dijit/_editor/plugins/FontChoice
33 // fontchoice, fontsize, and formatblock editor plugins
36 var _FontDropDown
= declare("dijit._editor.plugins._FontDropDown",
37 [_Widget
, _TemplatedMixin
, _WidgetsInTemplateMixin
], {
39 // Base class for widgets that contains a label (like "Font:")
40 // and a FilteringSelect drop down to pick a value.
41 // Used as Toolbar entry.
43 // label: [public] String
44 // The label to apply to this particular FontDropDown.
47 // plainText: [public] boolean
48 // Flag to indicate that the returned label should be plain text
49 // instead of an example.
52 // templateString: [public] String
53 // The template used to construct the labeled dropdown.
55 "<span style='white-space: nowrap' class='dijit dijitReset dijitInline'>" +
56 "<label class='dijitLeft dijitInline' for='${selectId}'>${label}</label>" +
57 "<input data-dojo-type='dijit.form.FilteringSelect' required='false' " +
58 "data-dojo-props='labelType:\"html\", labelAttr:\"label\", searchAttr:\"name\"' " +
59 "tabIndex='-1' id='${selectId}' data-dojo-attach-point='select' value=''/>" +
62 postMixInProperties: function(){
64 // Over-ride to set specific properties.
65 this.inherited(arguments
);
67 this.strings
= i18n
.getLocalization("dijit._editor", "FontChoice");
69 // Set some substitution variables used in the template
70 this.label
= this.strings
[this.command
];
71 this.id
= registry
.getUniqueId(this.declaredClass
.replace(/\./g,"_")); // TODO: unneeded??
72 this.selectId
= this.id
+ "_select"; // used in template
74 this.inherited(arguments
);
77 postCreate: function(){
79 // Over-ride for the default postCreate action
80 // This establishes the filtering selects and the like.
82 // Initialize the list of items in the drop down by creating data store with items like:
83 // {value: 1, name: "xx-small", label: "<font size=1>xx-small</font-size>" }
84 this.select
.set("store", new MemoryStore({
86 data
: array
.map(this.values
, function(value
){
87 var name
= this.strings
[value
] || value
;
89 label
: this.getLabel(value
, name
),
96 this.select
.set("value", "", false);
97 this.disabled
= this.select
.get("disabled");
100 _setValueAttr: function(value
, priorityChange
){
102 // Over-ride for the default action of setting the
103 // widget value, maps the input to known values
104 // value: Object|String
105 // The value to set in the select.
107 // Optional parameter used to tell the select whether or not to fire
110 // if the value is not a permitted value, just set empty string to prevent showing the warning icon
111 priorityChange
= priorityChange
!== false;
112 this.select
.set('value', array
.indexOf(this.values
,value
) < 0 ? "" : value
, priorityChange
);
114 // Clear the last state in case of updateState calls. Ref: #10466
115 this.select
._lastValueReported
=null;
119 _getValueAttr: function(){
121 // Allow retrieving the value from the composite select on
122 // call to button.get("value");
123 return this.select
.get('value');
128 // Over-ride for focus control of this widget. Delegates focus down to the
133 _setDisabledAttr: function(value
){
135 // Over-ride for the button's 'disabled' attribute so that it can be
136 // disabled programmatically.
138 // Save off ths disabled state so the get retrieves it correctly
139 //without needing to have a function proxy it.
140 this.disabled
= value
;
141 this.select
.set("disabled", value
);
146 var _FontNameDropDown
= declare("dijit._editor.plugins._FontNameDropDown", _FontDropDown
, {
148 // Dropdown to select a font; goes in editor toolbar.
151 // Use generic (web standard) font names
154 // command: [public] String
155 // The editor 'command' implemented by this plugin.
158 postMixInProperties: function(){
160 // Over-ride for the default posr mixin control
162 this.values
= this.generic
?
163 ["serif", "sans-serif", "monospace", "cursive", "fantasy"] : // CSS font-family generics
164 ["Arial", "Times New Roman", "Comic Sans MS", "Courier New"];
166 this.inherited(arguments
);
169 getLabel: function(value
, name
){
171 // Function used to generate the labels of the format dropdown
172 // will return a formatted, or plain label based on the value
173 // of the plainText option.
175 // The 'insert value' associated with a name
177 // The text name of the value
181 return "<div style='font-family: "+value
+"'>" + name
+ "</div>";
185 _setValueAttr: function(value
, priorityChange
){
187 // Over-ride for the default action of setting the
188 // widget value, maps the input to known values
190 priorityChange
= priorityChange
!== false;
193 "Arial": "sans-serif",
194 "Helvetica": "sans-serif",
195 "Myriad": "sans-serif",
197 "Times New Roman": "serif",
198 "Comic Sans MS": "cursive",
199 "Apple Chancery": "cursive",
200 "Courier": "monospace",
201 "Courier New": "monospace",
202 "Papyrus": "fantasy",
203 "Estrangelo Edessa": "cursive", // Windows 7
204 "Gabriola": "fantasy" // Windows 7
206 value
= map
[value
] || value
;
208 this.inherited(arguments
, [value
, priorityChange
]);
212 var _FontSizeDropDown
= declare("dijit._editor.plugins._FontSizeDropDown", _FontDropDown
, {
214 // Dropdown to select a font size; goes in editor toolbar.
216 // command: [public] String
217 // The editor 'command' implemented by this plugin.
220 // values: [public] Number[]
221 // The HTML font size values supported by this plugin
222 values
: [1,2,3,4,5,6,7], // sizes according to the old HTML FONT SIZE
224 getLabel: function(value
, name
){
226 // Function used to generate the labels of the format dropdown
227 // will return a formatted, or plain label based on the value
228 // of the plainText option.
229 // We're stuck using the deprecated FONT tag to correspond
230 // with the size measurements used by the editor
232 // The 'insert value' associated with a name
234 // The text name of the value
238 return "<font size=" + value
+ "'>" + name
+ "</font>";
242 _setValueAttr: function(value
, priorityChange
){
244 // Over-ride for the default action of setting the
245 // widget value, maps the input to known values
246 priorityChange
= priorityChange
!== false;
247 if(value
.indexOf
&& value
.indexOf("px") != -1){
248 var pixels
= parseInt(value
, 10);
249 value
= {10:1, 13:2, 16:3, 18:4, 24:5, 32:6, 48:7}[pixels
] || value
;
252 this.inherited(arguments
, [value
, priorityChange
]);
257 var _FormatBlockDropDown
= declare("dijit._editor.plugins._FormatBlockDropDown", _FontDropDown
, {
259 // Dropdown to select a format (like paragraph or heading); goes in editor toolbar.
261 // command: [public] String
262 // The editor 'command' implemented by this plugin.
263 command
: "formatBlock",
265 // values: [public] Array
266 // The HTML format tags supported by this plugin
267 values
: ["noFormat", "p", "h1", "h2", "h3", "pre"],
269 postCreate: function(){
270 // Init and set the default value to no formatting. Update state will adjust it
272 this.inherited(arguments
);
273 this.set("value", "noFormat", false);
276 getLabel: function(value
, name
){
278 // Function used to generate the labels of the format dropdown
279 // will return a formatted, or plain label based on the value
280 // of the plainText option.
282 // The 'insert value' associated with a name
284 // The text name of the value
285 if(this.plainText
|| value
== "noFormat"){
288 return "<" + value
+ ">" + name
+ "</" + value
+ ">";
292 _execCommand: function(editor
, command
, choice
){
294 // Over-ride for default exec-command label.
295 // Allows us to treat 'none' as special.
296 if(choice
=== "noFormat"){
299 var sel
= rangeapi
.getSelection(editor
.window
);
300 if(sel
&& sel
.rangeCount
> 0){
301 var range
= sel
.getRangeAt(0);
304 start
= range
.startContainer
;
305 end
= range
.endContainer
;
307 // find containing nodes of start/end.
308 while(start
&& start
!== editor
.editNode
&&
309 start
!== editor
.document
.body
&&
310 start
.nodeType
!== 1){
311 start
= start
.parentNode
;
314 while(end
&& end
!== editor
.editNode
&&
315 end
!== editor
.document
.body
&&
317 end
= end
.parentNode
;
320 var processChildren
= lang
.hitch(this, function(node
, ary
){
321 if(node
.childNodes
&& node
.childNodes
.length
){
323 for(i
= 0; i
< node
.childNodes
.length
; i
++){
324 var c
= node
.childNodes
[i
];
326 if(win
.withGlobal(editor
.window
, "inSelection", selectionapi
, [c
])){
327 var tag
= c
.tagName
? c
.tagName
.toLowerCase(): "";
328 if(array
.indexOf(this.values
, tag
) !== -1){
331 processChildren(c
, ary
);
338 var unformatNodes
= lang
.hitch(this, function(nodes
){
340 // Internal function to clear format nodes.
342 // The array of nodes to strip formatting from.
343 if(nodes
&& nodes
.length
){
344 editor
.beginEditing();
346 this._removeFormat(editor
, nodes
.pop());
354 //Contained within the same block, may be collapsed, but who cares, see if we
355 // have a block element to remove.
358 while(node
&& node
!== editor
.editNode
&& node
!== editor
.document
.body
){
359 if(node
.nodeType
== 1){
360 tag
= node
.tagName
? node
.tagName
.toLowerCase(): "";
361 if(array
.indexOf(this.values
, tag
) !== -1){
366 node
= node
.parentNode
;
369 //Also look for all child nodes in the selection that may need to be
370 //cleared of formatting
371 processChildren(start
, clearNodes
);
372 if(block
){ clearNodes
= [block
].concat(clearNodes
); }
373 unformatNodes(clearNodes
);
375 // Probably a multi select, so we have to process it. Whee.
377 while(win
.withGlobal(editor
.window
, "inSelection", selectionapi
, [node
])){
378 if(node
.nodeType
== 1){
379 tag
= node
.tagName
? node
.tagName
.toLowerCase(): "";
380 if(array
.indexOf(this.values
, tag
) !== -1){
381 clearNodes
.push(node
);
383 processChildren(node
,clearNodes
);
385 node
= node
.nextSibling
;
387 unformatNodes(clearNodes
);
389 editor
.onDisplayChanged();
393 editor
.execCommand(command
, choice
);
397 _removeFormat: function(editor
, node
){
399 // function to remove the block format node.
401 // The block format node to remove (and leave the contents behind)
402 if(editor
.customUndo
){
403 // So of course IE doesn't work right with paste-overs.
404 // We have to do this manually, which is okay since IE already uses
405 // customUndo and we turned it on for WebKit. WebKit pasted funny,
406 // so couldn't use the execCommand approach
407 while(node
.firstChild
){
408 domConstruct
.place(node
.firstChild
, node
, "before");
410 node
.parentNode
.removeChild(node
);
412 // Everyone else works fine this way, a paste-over and is native
414 win
.withGlobal(editor
.window
,
415 "selectElementChildren", selectionapi
, [node
]);
416 var html
= win
.withGlobal(editor
.window
,
417 "getSelectedHtml", selectionapi
, [null]);
418 win
.withGlobal(editor
.window
,
419 "selectElement", selectionapi
, [node
]);
420 editor
.execCommand("inserthtml", html
||"");
425 // TODO: for 2.0, split into FontChoice plugin into three separate classes,
426 // one for each command (and change registry below)
427 var FontChoice
= declare("dijit._editor.plugins.FontChoice", _Plugin
,{
429 // This plugin provides three drop downs for setting style in the editor
430 // (font, font size, and format block), as controlled by command.
433 // The commands provided by this plugin are:
436 // | Provides a drop down to select from a list of font names
438 // | Provides a drop down to select from a list of font sizes
440 // | Provides a drop down to select from a list of block styles
443 // which can easily be added to an editor by including one or more of the above commands
444 // in the `plugins` attribute as follows:
446 // | plugins="['fontName','fontSize',...]"
448 // It is possible to override the default dropdown list by providing an Array for the `custom` property when
449 // instantiating this plugin, e.g.
451 // | plugins="[{name:'dijit._editor.plugins.FontChoice', command:'fontName', custom:['Verdana','Myriad','Garamond']},...]"
453 // Alternatively, for `fontName` only, `generic:true` may be specified to provide a dropdown with
454 // [CSS generic font families](http://www.w3.org/TR/REC-CSS2/fonts.html#generic-font-families)
456 // Note that the editor is often unable to properly handle font styling information defined outside
457 // the context of the current editor instance, such as pre-populated HTML.
459 // useDefaultCommand: [protected] Boolean
460 // Override _Plugin.useDefaultCommand...
461 // processing is handled by this plugin, not by dijit.Editor.
462 useDefaultCommand
: false,
464 _initButton: function(){
466 // Overrides _Plugin._initButton(), to initialize the FilteringSelect+label in toolbar,
467 // rather than a simple button.
471 // Create the widget to go into the toolbar (the so-called "button")
473 fontName
: _FontNameDropDown
,
474 fontSize
: _FontSizeDropDown
,
475 formatBlock
: _FormatBlockDropDown
477 params
= this.params
;
479 // For back-compat reasons support setting custom values via "custom" parameter
480 // rather than "values" parameter
481 if(this.params
.custom
){
482 params
.values
= this.params
.custom
;
485 var editor
= this.editor
;
486 this.button
= new clazz(lang
.delegate({dir
: editor
.dir
, lang
: editor
.lang
}, params
));
488 // Reflect changes to the drop down in the editor
489 this.connect(this.button
.select
, "onChange", function(choice
){
490 // User invoked change, since all internal updates set priorityChange to false and will
491 // not trigger an onChange event.
494 if(this.command
== "fontName" && choice
.indexOf(" ") != -1){ choice
= "'" + choice
+ "'"; }
496 // Invoke, the editor already normalizes commands called through its
498 if(this.button
._execCommand
){
499 this.button
._execCommand(this.editor
, this.command
, choice
);
501 this.editor
.execCommand(this.command
, choice
);
506 updateState: function(){
508 // Overrides _Plugin.updateState(). This controls updating the menu
509 // options to the right values on state changes in the document (that trigger a
510 // test of the actions.)
511 // It set value of drop down in toolbar to reflect font/font size/format block
512 // of text at current caret position.
515 var _e
= this.editor
;
516 var _c
= this.command
;
517 if(!_e
|| !_e
.isLoaded
|| !_c
.length
){ return; }
520 var disabled
= this.get("disabled");
521 this.button
.set("disabled", disabled
);
522 if(disabled
){ return; }
525 value
= _e
.queryCommandValue(_c
) || "";
527 //Firefox may throw error above if the editor is just loaded, ignore it
531 // strip off single quotes, if any
532 var quoted
= lang
.isString(value
) && value
.match(/'([^']*)'/);
533 if(quoted
){ value
= quoted
[1]; }
535 if(_c
=== "formatBlock"){
536 if(!value
|| value
== "p"){
537 // Some browsers (WebKit) doesn't actually get the tag info right.
538 // and IE returns paragraph when in a DIV!, so incorrect a lot,
539 // so we have double-check it.
542 // Try to find the current element where the caret is.
543 var sel
= rangeapi
.getSelection(this.editor
.window
);
544 if(sel
&& sel
.rangeCount
> 0){
545 var range
= sel
.getRangeAt(0);
547 elem
= range
.endContainer
;
551 // Okay, now see if we can find one of the formatting types we're in.
552 while(elem
&& elem
!== _e
.editNode
&& elem
!== _e
.document
){
553 var tg
= elem
.tagName
?elem
.tagName
.toLowerCase():"";
554 if(tg
&& array
.indexOf(this.button
.values
, tg
) > -1){
558 elem
= elem
.parentNode
;
561 // Still no value, so lets select 'none'.
565 // Check that the block format is one allowed, if not,
566 // null it so that it gets set to empty.
567 if(array
.indexOf(this.button
.values
, value
) < 0){
572 if(value
!== this.button
.get("value")){
573 // Set the value, but denote it is not a priority change, so no
575 this.button
.set('value', value
, false);
581 // Register these plugins
582 array
.forEach(["fontName", "fontSize", "formatBlock"], function(name
){
583 _Plugin
.registry
[name
] = function(args
){
584 return new FontChoice({
586 plainText
: args
.plainText