666cb37b4d6c4628a9f089653f0184b568e54518
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / htmlarea / plugins / SelectFont / select-font.js
1 /***************************************************************
2 * Copyright notice
3 *
4 * (c) 2008-2012 Stanislas Rolland <typo3(arobas)sjbr.ca>
5 * All rights reserved
6 *
7 * This script is part of the TYPO3 project. The TYPO3 project is
8 * free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * The GNU General Public License can be found at
14 * http://www.gnu.org/copyleft/gpl.html.
15 * A copy is found in the textfile GPL.txt and important notices to the license
16 * from the author is found in LICENSE.txt distributed with these scripts.
17 *
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /*
28 * SelectFont Plugin for TYPO3 htmlArea RTE
29 */
30 HTMLArea.SelectFont = Ext.extend(HTMLArea.Plugin, {
31 /*
32 * This function gets called by the class constructor
33 */
34 configurePlugin: function (editor) {
35 this.buttonsConfiguration = this.editorConfiguration.buttons;
36 this.disablePCexamples = this.editorConfiguration.disablePCexamples;
37 // Font formating will use the style attribute
38 if (this.getPluginInstance('TextStyle')) {
39 this.getPluginInstance('TextStyle').addAllowedAttribute('style');
40 this.allowedAttributes = this.getPluginInstance('TextStyle').allowedAttributes;
41 }
42 if (this.getPluginInstance('InlineElements')) {
43 this.getPluginInstance('InlineElements').addAllowedAttribute('style');
44 if (!this.allowedAllowedAttributes) {
45 this.allowedAttributes = this.getPluginInstance('InlineElements').allowedAttributes;
46 }
47 }
48 if (this.getPluginInstance('BlockElements')) {
49 this.getPluginInstance('BlockElements').addAllowedAttribute('style');
50 }
51 if (!this.allowedAttributes) {
52 this.allowedAttributes = new Array('id', 'title', 'lang', 'xml:lang', 'dir', 'class', 'style');
53 if (Ext.isIE) {
54 this.allowedAttributes.push('className');
55 }
56 }
57 /*
58 * Registering plugin "About" information
59 */
60 var pluginInformation = {
61 version : '2.2',
62 developer : 'Stanislas Rolland',
63 developerUrl : 'http://www.sjbr.ca/',
64 copyrightOwner : 'Stanislas Rolland',
65 sponsor : 'SJBR',
66 sponsorUrl : 'http://www.sjbr.ca/',
67 license : 'GPL'
68 };
69 this.registerPluginInformation(pluginInformation);
70 /*
71 * Registering the dropdowns
72 */
73 Ext.each(this.dropDownList, function (dropDown) {
74 var buttonId = dropDown[0];
75 if (this.isButtonInToolbar(buttonId)) {
76 var dropDownConfiguration = {
77 id: buttonId,
78 tooltip: this.localize(buttonId.toLowerCase()),
79 storeUrl: this.buttonsConfiguration[dropDown[2]].dataUrl,
80 action: 'onChange',
81 tpl: this.disablePCexamples ? '' : '<tpl for="."><div ext:qtip="{value}" style="' + dropDown[3] + '" class="x-combo-list-item">{text}</div></tpl>'
82 };
83 if (this.buttonsConfiguration[dropDown[2]]) {
84 if (this.editorConfiguration.buttons[dropDown[2]].width) {
85 dropDownConfiguration.width = parseInt(this.editorConfiguration.buttons[dropDown[2]].width, 10);
86 }
87 if (this.editorConfiguration.buttons[dropDown[2]].listWidth) {
88 dropDownConfiguration.listWidth = parseInt(this.editorConfiguration.buttons[dropDown[2]].listWidth, 10);
89 }
90 if (this.editorConfiguration.buttons[dropDown[2]].maxHeight) {
91 dropDownConfiguration.maxHeight = parseInt(this.editorConfiguration.buttons[dropDown[2]].maxHeight, 10);
92 }
93 }
94 this.registerDropDown(dropDownConfiguration);
95 }
96 return true;
97 }, this);
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 Ext.each(this.dropDownList, function (dropDown) {
127 var select = this.getButton(dropDown[0]);
128 if (select) {
129 select.mon(select.getStore(), 'load', function () {
130 var selection = this.editor.getSelection(),
131 selectionEmpty = selection.isEmpty(),
132 ancestors = selection.getAllAncestors(),
133 endPointsInSameBlock = selection.endPointsInSameBlock();
134 this.onUpdateToolbar(select, this.getEditorMode(), selectionEmpty, ancestors, endPointsInSameBlock);
135 }, this);
136 }
137 }, this);
138 },
139 /*
140 * This function gets called when some font style or font size was selected from the dropdown lists
141 */
142 onChange: function (editor, combo, record, index) {
143 var param = combo.getValue();
144 var element,
145 fullNodeSelected = false;
146 var range = editor.getSelection().createRange();
147 var parent = editor.getSelection().getParentElement();
148 var selectionEmpty = editor.getSelection().isEmpty();
149 var statusBarSelection = editor.statusBar ? editor.statusBar.getSelection() : null;
150 if (!selectionEmpty) {
151 var fullySelectedNode = editor.getSelection().getFullySelectedNode();
152 if (fullySelectedNode) {
153 fullNodeSelected = true;
154 parent = fullySelectedNode;
155 }
156 }
157 if (selectionEmpty || fullNodeSelected) {
158 element = parent;
159 // Set the style attribute
160 this.setStyle(element, combo.itemId, param);
161 // Remove the span tag if it has no more attribute
162 if (/^span$/i.test(element.nodeName) && !HTMLArea.DOM.hasAllowedAttributes(element, this.allowedAttributes)) {
163 editor.getDomNode().removeMarkup(element);
164 }
165 } else if (statusBarSelection) {
166 element = statusBarSelection;
167 // Set the style attribute
168 this.setStyle(element, combo.itemId, param);
169 // Remove the span tag if it has no more attribute
170 if (/^span$/i.test(element.nodeName) && !HTMLArea.DOM.hasAllowedAttributes(element, this.allowedAttributes)) {
171 editor.getDomNode().removeMarkup(element);
172 }
173 } else if (editor.getSelection().endPointsInSameBlock()) {
174 element = editor.document.createElement('span');
175 // Set the style attribute
176 this.setStyle(element, combo.itemId, param);
177 // Wrap the selection with span tag with the style attribute
178 editor.getDomNode().wrapWithInlineElement(element, range);
179 if (!Ext.isIE) {
180 range.detach();
181 }
182 }
183 return false;
184 },
185 /*
186 * This function sets the style attribute on the element
187 *
188 * @param object element: the element on which the style attribute is to be set
189 * @param string buttonId: the button being processed
190 * @param string value: the value to be assigned
191 *
192 * @return void
193 */
194 setStyle: function (element, buttonId, value) {
195 element.style[this.styleProperty[buttonId]] = (value && value !== 'none') ? value : '';
196 // In IE, we need to remove the empty attribute in order to unset it
197 if (Ext.isIE && (!value || value == 'none')) {
198 element.style.removeAttribute(this.styleProperty[buttonId], false);
199 }
200 if (Ext.isOpera) {
201 // Opera 9.60 replaces single quotes with double quotes
202 element.style.cssText = element.style.cssText.replace(/\"/g, "\'");
203 // Opera 9.60 removes from the list of fonts any fonts that are not installed on the client system
204 // If the fontFamily property becomes empty, it is broken and cannot be reset/unset
205 // We remove it using cssText
206 if (!/\S/.test(element.style[this.styleProperty[buttonId]])) {
207 element.style.cssText = element.style.cssText.replace(/font-family: /gi, '');
208 }
209 }
210 },
211 /*
212 * This function gets called when the toolbar is updated
213 */
214 onUpdateToolbar: function (select, mode, selectionEmpty, ancestors, endPointsInSameBlock) {
215 var editor = this.editor;
216 if (mode === 'wysiwyg' && editor.isEditable()) {
217 var statusBarSelection = this.editor.statusBar ? this.editor.statusBar.getSelection() : null;
218 var parentElement = statusBarSelection ? statusBarSelection : editor.getSelection().getParentElement();
219 var value = parentElement.style[this.styleProperty[select.itemId]];
220 if (!value) {
221 if (!Ext.isIE) {
222 if (editor.document.defaultView && editor.document.defaultView.getComputedStyle(parentElement, null)) {
223 value = editor.document.defaultView.getComputedStyle(parentElement, null).getPropertyValue(this.cssProperty[select.itemId]);
224 }
225 } else {
226 value = parentElement.currentStyle[this.styleProperty[select.itemId]];
227 }
228 }
229 var store = select.getStore();
230 var index = -1;
231 if (value) {
232 index = store.findBy(
233 function (record, id) {
234 return record.get('value').replace(/[\"\']/g, '') == value.replace(/, /g, ',').replace(/[\"\']/g, '');
235 }
236 );
237 }
238 if (index != -1) {
239 select.setValue(store.getAt(index).get('value'));
240 } else if (store.getCount()) {
241 select.setValue('none');
242 }
243 select.setDisabled(!endPointsInSameBlock || (selectionEmpty && /^body$/i.test(parentElement.nodeName)));
244 }
245 }
246 });