a9696a753fc88754826c2575087e30789ca527a5
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / Resources / Public / JavaScript / Plugins / SelectFont.js
1 /*
2 * This file is part of the TYPO3 CMS project.
3 *
4 * It is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU General Public License, either version 2
6 * of the License, or any later version.
7 *
8 * For the full copyright and license information, please read the
9 * LICENSE.txt file that was distributed with this source code.
10 *
11 * The TYPO3 project - inspiring people to share!
12 */
13
14 /**
15 * SelectFont Plugin for TYPO3 htmlArea RTE
16 */
17 define('TYPO3/CMS/Rtehtmlarea/Plugins/SelectFont',
18 ['TYPO3/CMS/Rtehtmlarea/HTMLArea/Plugin/Plugin',
19 'TYPO3/CMS/Rtehtmlarea/HTMLArea/UserAgent/UserAgent',
20 'TYPO3/CMS/Rtehtmlarea/HTMLArea/DOM/DOM',
21 'TYPO3/CMS/Rtehtmlarea/HTMLArea/Util/Util'],
22 function (Plugin, UserAgent, Dom, Util) {
23
24 var SelectFont = function (editor, pluginName) {
25 this.constructor.super.call(this, editor, pluginName);
26 };
27 Util.inherit(SelectFont, Plugin);
28 Util.apply(SelectFont.prototype, {
29
30 /**
31 * This function gets called by the class constructor
32 */
33 configurePlugin: function (editor) {
34 this.buttonsConfiguration = this.editorConfiguration.buttons;
35 this.disablePCexamples = this.editorConfiguration.disablePCexamples;
36 // Font formating will use the style attribute
37 if (this.getPluginInstance('TextStyle')) {
38 this.getPluginInstance('TextStyle').addAllowedAttribute('style');
39 this.allowedAttributes = this.getPluginInstance('TextStyle').allowedAttributes;
40 }
41 if (this.getPluginInstance('InlineElements')) {
42 this.getPluginInstance('InlineElements').addAllowedAttribute('style');
43 if (!this.allowedAllowedAttributes) {
44 this.allowedAttributes = this.getPluginInstance('InlineElements').allowedAttributes;
45 }
46 }
47 if (this.getPluginInstance('BlockElements')) {
48 this.getPluginInstance('BlockElements').addAllowedAttribute('style');
49 }
50 if (!this.allowedAttributes) {
51 this.allowedAttributes = new Array('id', 'title', 'lang', 'xml:lang', 'dir', 'class', 'style');
52 if (UserAgent.isIEBeforeIE9) {
53 this.allowedAttributes.push('className');
54 }
55 }
56 /*
57 * Registering plugin "About" information
58 */
59 var pluginInformation = {
60 version : '2.2',
61 developer : 'Stanislas Rolland',
62 developerUrl : 'http://www.sjbr.ca/',
63 copyrightOwner : 'Stanislas Rolland',
64 sponsor : 'SJBR',
65 sponsorUrl : 'http://www.sjbr.ca/',
66 license : 'GPL'
67 };
68 this.registerPluginInformation(pluginInformation);
69 /*
70 * Registering the dropdowns
71 */
72 var dropDown, buttonId;
73 for (var i = this.dropDownList.length; --i >= 0;) {
74 dropDown = this.dropDownList[i];
75 buttonId = dropDown[0];
76 if (this.isButtonInToolbar(buttonId)) {
77 var dropDownConfiguration = {
78 id: buttonId,
79 tooltip: this.localize(buttonId.toLowerCase()),
80 storeUrl: this.buttonsConfiguration[dropDown[2]].dataUrl,
81 action: 'onChange',
82 tpl: this.disablePCexamples ? '' : '<tpl for="."><div ext:qtip="{value}" style="' + dropDown[3] + '" class="x-combo-list-item">{text}</div></tpl>'
83 };
84 if (this.buttonsConfiguration[dropDown[2]]) {
85 if (this.editorConfiguration.buttons[dropDown[2]].width) {
86 dropDownConfiguration.width = parseInt(this.editorConfiguration.buttons[dropDown[2]].width, 10);
87 }
88 if (this.editorConfiguration.buttons[dropDown[2]].listWidth) {
89 dropDownConfiguration.listWidth = parseInt(this.editorConfiguration.buttons[dropDown[2]].listWidth, 10);
90 }
91 if (this.editorConfiguration.buttons[dropDown[2]].maxHeight) {
92 dropDownConfiguration.maxHeight = parseInt(this.editorConfiguration.buttons[dropDown[2]].maxHeight, 10);
93 }
94 }
95 this.registerDropDown(dropDownConfiguration);
96 }
97 }
98 return true;
99 },
100 /*
101 * The list of buttons added by this plugin
102 */
103 dropDownList: [
104 ['FontName', null, 'fontstyle', 'font-family:{value};text-align:left;font-size:11px;'],
105 ['FontSize', null, 'fontsize', 'text-align:left;font-size:{value};']
106 ],
107 /*
108 * Conversion object: button name to corresponding style property name
109 */
110 styleProperty: {
111 FontName: 'fontFamily',
112 FontSize: 'fontSize'
113 },
114 /*
115 * Conversion object: button name to corresponding css property name
116 */
117 cssProperty: {
118 FontName: 'font-family',
119 FontSize: 'font-size'
120 },
121 /**
122 * This funcion is invoked by the editor when it is being generated
123 */
124 onGenerate: function () {
125 // Monitor the dropdowns stores being loaded
126 var dropDown;
127 for (var i = this.dropDownList.length; --i >= 0;) {
128 dropDown = this.dropDownList[i];
129 var select = this.getButton(dropDown[0]);
130 if (select) {
131 select.mon(select.getStore(), 'load', function () {
132 var selection = this.editor.getSelection(),
133 selectionEmpty = selection.isEmpty(),
134 ancestors = selection.getAllAncestors(),
135 endPointsInSameBlock = selection.endPointsInSameBlock();
136 this.onUpdateToolbar(select, this.getEditorMode(), selectionEmpty, ancestors, endPointsInSameBlock);
137 }, this);
138 }
139 }
140 },
141 /*
142 * This function gets called when some font style or font size was selected from the dropdown lists
143 */
144 onChange: function (editor, combo, record, index) {
145 var param = combo.getValue();
146 var element,
147 fullNodeSelected = false;
148 var range = editor.getSelection().createRange();
149 var parent = editor.getSelection().getParentElement();
150 var selectionEmpty = editor.getSelection().isEmpty();
151 var statusBarSelection = editor.statusBar ? editor.statusBar.getSelection() : null;
152 if (!selectionEmpty) {
153 var fullySelectedNode = editor.getSelection().getFullySelectedNode();
154 if (fullySelectedNode) {
155 fullNodeSelected = true;
156 parent = fullySelectedNode;
157 }
158 }
159 if (selectionEmpty || fullNodeSelected) {
160 element = parent;
161 // Set the style attribute
162 this.setStyle(element, combo.itemId, param);
163 // Remove the span tag if it has no more attribute
164 if (/^span$/i.test(element.nodeName) && !Dom.hasAllowedAttributes(element, this.allowedAttributes)) {
165 editor.getDomNode().removeMarkup(element);
166 }
167 } else if (statusBarSelection) {
168 element = statusBarSelection;
169 // Set the style attribute
170 this.setStyle(element, combo.itemId, param);
171 // Remove the span tag if it has no more attribute
172 if (/^span$/i.test(element.nodeName) && !Dom.hasAllowedAttributes(element, this.allowedAttributes)) {
173 editor.getDomNode().removeMarkup(element);
174 }
175 } else if (editor.getSelection().endPointsInSameBlock()) {
176 element = editor.document.createElement('span');
177 // Set the style attribute
178 this.setStyle(element, combo.itemId, param);
179 // Wrap the selection with span tag with the style attribute
180 editor.getDomNode().wrapWithInlineElement(element, range);
181 if (!UserAgent.isIEBeforeIE9) {
182 range.detach();
183 }
184 }
185 return false;
186 },
187 /*
188 * This function sets the style attribute on the element
189 *
190 * @param object element: the element on which the style attribute is to be set
191 * @param string buttonId: the button being processed
192 * @param string value: the value to be assigned
193 *
194 * @return void
195 */
196 setStyle: function (element, buttonId, value) {
197 element.style[this.styleProperty[buttonId]] = (value && value !== 'none') ? value : '';
198 // In IE, we need to remove the empty attribute in order to unset it
199 if (UserAgent.isIE && (!value || value == 'none')) {
200 element.style.removeAttribute(this.styleProperty[buttonId], false);
201 }
202 if (UserAgent.isOpera) {
203 // Opera 9.60 replaces single quotes with double quotes
204 element.style.cssText = element.style.cssText.replace(/\"/g, "\'");
205 // Opera 9.60 removes from the list of fonts any fonts that are not installed on the client system
206 // If the fontFamily property becomes empty, it is broken and cannot be reset/unset
207 // We remove it using cssText
208 if (!/\S/.test(element.style[this.styleProperty[buttonId]])) {
209 element.style.cssText = element.style.cssText.replace(/font-family: /gi, '');
210 }
211 }
212 },
213 /*
214 * This function gets called when the toolbar is updated
215 */
216 onUpdateToolbar: function (select, mode, selectionEmpty, ancestors, endPointsInSameBlock) {
217 var editor = this.editor;
218 if (mode === 'wysiwyg' && editor.isEditable()) {
219 var statusBarSelection = this.editor.statusBar ? this.editor.statusBar.getSelection() : null;
220 var parentElement = statusBarSelection ? statusBarSelection : editor.getSelection().getParentElement();
221 var value = parentElement.style[this.styleProperty[select.itemId]];
222 if (!value) {
223 if (!UserAgent.isIEBeforeIE9) {
224 if (editor.document.defaultView && editor.document.defaultView.getComputedStyle(parentElement, null)) {
225 value = editor.document.defaultView.getComputedStyle(parentElement, null).getPropertyValue(this.cssProperty[select.itemId]);
226 }
227 } else {
228 value = parentElement.currentStyle[this.styleProperty[select.itemId]];
229 }
230 }
231 var store = select.getStore();
232 var index = -1;
233 if (value) {
234 index = store.findBy(
235 function (record, id) {
236 return record.get('value').replace(/[\"\']/g, '') == value.replace(/, /g, ',').replace(/[\"\']/g, '');
237 }
238 );
239 }
240 if (index != -1) {
241 select.setValue(store.getAt(index).get('value'));
242 } else if (store.getCount()) {
243 select.setValue('none');
244 }
245 select.setDisabled(!endPointsInSameBlock || (selectionEmpty && /^body$/i.test(parentElement.nodeName)));
246 }
247 }
248 });
249
250 return SelectFont;
251
252 });