a16018ce69ffe6227d8dd03bf0827ffb5fa9177f
1 /***************************************************************
4 * (c) 2004-2012 Stanislas Rolland <typo3(arobas)sjbr.ca>
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.
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.
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.
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
28 * TYPO3 Color Plugin for TYPO3 htmlArea RTE
30 HTMLArea
.TYPO3Color
= Ext
.extend(HTMLArea
.Plugin
, {
32 * This function gets called by the class constructor
34 configurePlugin: function (editor
) {
35 this.buttonsConfiguration
= this.editorConfiguration
.buttons
;
36 this.colorsConfiguration
= this.editorConfiguration
.colors
;
37 this.disableColorPicker
= this.editorConfiguration
.disableColorPicker
;
38 // Coloring will use the style attribute
39 if (this.getPluginInstance('TextStyle')) {
40 this.getPluginInstance('TextStyle').addAllowedAttribute('style');
41 this.allowedAttributes
= this.getPluginInstance('TextStyle').allowedAttributes
;
43 if (this.getPluginInstance('InlineElements')) {
44 this.getPluginInstance('InlineElements').addAllowedAttribute('style');
45 if (!this.allowedAllowedAttributes
) {
46 this.allowedAttributes
= this.getPluginInstance('InlineElements').allowedAttributes
;
49 if (this.getPluginInstance('BlockElements')) {
50 this.getPluginInstance('BlockElements').addAllowedAttribute('style');
52 if (!this.allowedAttributes
) {
53 this.allowedAttributes
= new Array('id', 'title', 'lang', 'xml:lang', 'dir', 'class', 'style');
55 this.allowedAttributes
.push('className');
59 * Registering plugin "About" information
61 var pluginInformation
= {
63 developer
: 'Stanislas Rolland',
64 developerUrl
: 'http://www.sjbr.ca/',
65 copyrightOwner
: 'Stanislas Rolland',
67 sponsorUrl
: 'http://www.sjbr.ca/',
70 this.registerPluginInformation(pluginInformation
);
72 * Registering the buttons
74 var buttonList
= this.buttonList
, buttonId
;
75 for (var i
= 0; i
< buttonList
.length
; ++i
) {
76 var button
= buttonList
[i
];
78 var buttonConfiguration
= {
80 tooltip
: this.localize(buttonId
),
81 iconCls
: 'htmlarea-action-' + button
[2],
82 action
: 'onButtonPress',
83 hotKey
: (this.buttonsConfiguration
[button
[1]] ? this.buttonsConfiguration
[button
[1]].hotKey
: null),
86 this.registerButton(buttonConfiguration
);
91 * The list of buttons added by this plugin
94 ['ForeColor', 'textcolor', 'color-foreground'],
95 ['HiliteColor', 'bgcolor', 'color-background']
98 * Conversion object: button name to corresponding style property name
102 HiliteColor
: 'backgroundColor'
105 '000000', '222222', '444444', '666666', '999999', 'BBBBBB', 'DDDDDD', 'FFFFFF',
106 '660000', '663300', '996633', '003300', '003399', '000066', '330066', '660066',
107 '990000', '993300', 'CC9900', '006600', '0033FF', '000099', '660099', '990066',
108 'CC0000', 'CC3300', 'FFCC00', '009900', '0066FF', '0000CC', '663399', 'CC0099',
109 'FF0000', 'FF3300', 'FFFF00', '00CC00', '0099FF', '0000FF', '9900CC', 'FF0099',
110 'CC3333', 'FF6600', 'FFFF33', '00FF00', '00CCFF', '3366FF', '9933FF', 'FF00FF',
111 'FF6666', 'FF6633', 'FFFF66', '66FF66', '00FFFF', '3399FF', '9966FF', 'FF66FF',
112 'FF9999', 'FF9966', 'FFFF99', '99FF99', '99FFFF', '66CCFF', '9999FF', 'FF99FF',
113 'FFCCCC', 'FFCC99', 'FFFFCC', 'CCFFCC', 'CCFFFF', '99CCFF', 'CCCCFF', 'FFCCFF'
116 * This function gets called when the button was pressed.
118 * @param object editor: the editor instance
119 * @param string id: the button id or the key
120 * @param object target: the target element of the contextmenu event, when invoked from the context menu
122 * @return boolean false if action is completed
124 onButtonPress: function (editor
, id
, target
) {
125 // Could be a button or its hotkey
126 var buttonId
= this.translateHotKey(id
);
127 buttonId
= buttonId
? buttonId
: id
;
128 var element
= this.editor
.getSelection().getParentElement();
135 this.getWindowDimensions(
142 this.buildItemsConfig(element
, buttonId
),
147 * Build the window items config
149 buildItemsConfig: function (element
, buttonId
) {
150 var itemsConfig
= [];
151 var paletteItems
= [];
152 // Standard colors palette (boxed)
153 if (!this.disableColorPicker
) {
157 xtype
: 'colorpalette',
158 itemId
: 'color-palette',
160 cls
: 'color-palette',
161 value
: (element
&& element
.style
[this.styleProperty
[buttonId
]]) ? HTMLArea
.util
.Color
.colorToHex(element
.style
[this.styleProperty
[buttonId
]]).substr(1, 6) : '',
172 // Custom colors palette (boxed)
173 if (this.colorsConfiguration
) {
177 xtype
: 'colorpalette',
178 itemId
: 'custom-colors',
179 cls
: 'htmlarea-custom-colors',
180 colors
: this.colorsConfiguration
,
181 value
: (element
&& element
.style
[this.styleProperty
[buttonId
]]) ? HTMLArea
.util
.Color
.colorToHex(element
.style
[this.styleProperty
[buttonId
]]).substr(1, 6) : '',
182 tpl
: new Ext
.XTemplate(
183 '<tpl for="."><a href="#" class="color-{1}" hidefocus="on"><em><span style="background:#{1}" unselectable="on"> </span></em><span unselectable="on">{0}<span></a></tpl>'
201 xtype
: 'displayfield',
202 itemId
: 'show-color',
206 helpTitle
: this.localize(buttonId
)
213 value
: (element
&& element
.style
[this.styleProperty
[buttonId
]]) ? HTMLArea
.util
.Color
.colorToHex(element
.style
[this.styleProperty
[buttonId
]]).substr(1, 6) : '',
214 enableKeyEvents
: true,
215 fieldLabel
: this.localize(buttonId
),
216 helpTitle
: this.localize(buttonId
),
223 fn
: this.onAfterRender
,
230 title
: this.localize('color_title'),
231 defaultType
: 'textfield',
240 * On select handler: set the value of the color field, display the new color and update the other palette
242 onSelect: function (palette
, color
) {
243 this.dialog
.find('itemId', 'color')[0].setValue(color
);
244 this.showColor(color
);
245 if (palette
.getItemId() == 'color-palette') {
246 var customPalette
= this.dialog
.find('itemId', 'custom-colors')[0];
248 customPalette
.deSelect();
251 var standardPalette
= this.dialog
.find('itemId', 'color-palette')[0];
252 if (standardPalette
) {
253 standardPalette
.deSelect();
258 * Display the selected color
260 showColor: function (color
) {
262 var newColor
= color
;
263 if (newColor
.indexOf('#') == 0) {
264 newColor
= newColor
.substr(1);
266 this.dialog
.find('itemId', 'show-color')[0].el
.setStyle('backgroundColor', HTMLArea
.util
.Color
.colorToHex(parseInt(newColor
, 16)));
270 * On change handler: display the new color and select it in the palettes, if it exists
272 onChange: function (field
, value
) {
274 var color
= value
.toUpperCase();
275 this.showColor(color
);
276 var standardPalette
= this.dialog
.find('itemId', 'color-palette')[0];
277 if (standardPalette
) {
278 standardPalette
.select(color
);
280 var customPalette
= this.dialog
.find('itemId', 'custom-colors')[0];
282 customPalette
.select(color
);
287 * On after render handler: display the color
289 onAfterRender: function (field
) {
290 if (!Ext
.isEmpty(field
.getValue())) {
291 this.showColor(field
.getValue());
295 * Open the dialogue window
297 * @param string title: the window title
298 * @param object arguments: some arguments for the handler
299 * @param integer dimensions: the opening width of the window
300 * @param object tabItems: the configuration of the tabbed panel
301 * @param function handler: handler when the OK button if clicked
305 openDialogue: function (title
, arguments
, dimensions
, items
, handler
) {
309 this.dialog
= new Ext
.Window({
310 title
: this.localize(title
),
311 arguments
: arguments
,
312 cls
: 'htmlarea-window',
314 width
: dimensions
.width
,
315 height
: dimensions
.height
,
317 iconCls
: this.getButton(arguments
.buttonId
).iconCls
,
336 this.buildButtonConfig('OK', handler
),
337 this.buildButtonConfig('Cancel', this.onCancel
)
343 * Set the color and close the dialogue
345 setColor: function(button
, event
) {
346 this.restoreSelection();
347 var buttonId
= this.dialog
.arguments
.buttonId
;
348 var color
= this.dialog
.find('itemId', 'color')[0].getValue();
350 if (color
.indexOf('#') == 0) {
351 color
= color
.substr(1);
353 color
= HTMLArea
.util
.Color
.colorToHex(parseInt(color
, 16));
356 fullNodeSelected
= false;
357 var range
= this.editor
.getSelection().createRange();
358 var parent
= this.editor
.getSelection().getParentElement();
359 var selectionEmpty
= this.editor
.getSelection().isEmpty();
360 var statusBarSelection
= this.editor
.statusBar
? this.editor
.statusBar
.getSelection() : null;
361 if (!selectionEmpty
) {
362 var fullySelectedNode
= this.editor
.getSelection().getFullySelectedNode();
363 if (fullySelectedNode
) {
364 fullNodeSelected
= true;
365 parent
= fullySelectedNode
;
368 if (selectionEmpty
|| fullNodeSelected
) {
370 // Set the color in the style attribute
371 element
.style
[this.styleProperty
[buttonId
]] = color
;
372 // Remove the span tag if it has no more attribute
373 if (/^span$/i.test(element
.nodeName
) && !HTMLArea
.DOM
.hasAllowedAttributes(element
, this.allowedAttributes
)) {
374 this.editor
.getDomNode().removeMarkup(element
);
376 } else if (statusBarSelection
) {
377 var element
= statusBarSelection
;
378 // Set the color in the style attribute
379 element
.style
[this.styleProperty
[buttonId
]] = color
;
380 // Remove the span tag if it has no more attribute
381 if (/^span$/i.test(element
.nodeName
) && !HTMLArea
.DOM
.hasAllowedAttributes(element
, this.allowedAttributes
)) {
382 this.editor
.getDomNode().removeMarkup(element
);
384 } else if (color
&& this.editor
.getSelection().endPointsInSameBlock()) {
385 var element
= this.editor
.document
.createElement('span');
386 // Set the color in the style attribute
387 element
.style
[this.styleProperty
[buttonId
]] = color
;
388 this.editor
.getDomNode().wrapWithInlineElement(element
, range
);
394 * This function gets called when the toolbar is updated
396 onUpdateToolbar: function (button
, mode
, selectionEmpty
, ancestors
, endPointsInSameBlock
) {
397 if (mode
=== 'wysiwyg' && this.editor
.isEditable()) {
398 var statusBarSelection
= this.editor
.statusBar
? this.editor
.statusBar
.getSelection() : null,
399 parentElement
= statusBarSelection
? statusBarSelection
: this.editor
.getSelection().getParentElement(),
400 disabled
= !endPointsInSameBlock
|| (selectionEmpty
&& /^body$/i.test(parentElement
.nodeName
));
401 button
.setInactive(!parentElement
.style
[this.styleProperty
[button
.itemId
]]);
402 button
.setDisabled(disabled
);