4 * Copyright 2009, Moxiecode Systems AB
5 * Released under LGPL License.
7 * License: http://tinymce.moxiecode.com/license
8 * Contributing: http://tinymce.moxiecode.com/contributing
12 var DOM = tinymce.DOM, Event = tinymce.dom.Event, is = tinymce.is, each = tinymce.each;
15 * This class is used to create UI color split button. A color split button will present show a small color picker
16 * when you press the open menu.
18 * @class tinymce.ui.ColorSplitButton
19 * @extends tinymce.ui.SplitButton
21 tinymce.create('tinymce.ui.ColorSplitButton:tinymce.ui.SplitButton', {
23 * Constructs a new color split button control instance.
26 * @method ColorSplitButton
27 * @param {String} id Control id for the color split button.
28 * @param {Object} s Optional name/value settings object.
29 * @param {Editor} ed The editor instance this button is for.
31 ColorSplitButton : function(id, s, ed) {
42 t.settings = s = tinymce.extend({
43 colors : '000000,993300,333300,003300,003366,000080,333399,333333,800000,FF6600,808000,008000,008080,0000FF,666699,808080,FF0000,FF9900,99CC00,339966,33CCCC,3366FF,800080,999999,FF00FF,FFCC00,FFFF00,00FF00,00FFFF,00CCFF,993366,C0C0C0,FF99CC,FFCC99,FFFF99,CCFFCC,CCFFFF,99CCFF,CC99FF,FFFFFF',
45 default_color : '#888888'
49 * Fires when the menu is shown.
53 t.onShowMenu = new tinymce.util.Dispatcher(t);
56 * Fires when the menu is hidden.
60 t.onHideMenu = new tinymce.util.Dispatcher(t);
63 * Current color value.
68 t.value = s.default_color;
72 * Shows the color menu. The color menu is a layer places under the button
73 * and displays a table of colors for the user to pick from.
77 showMenu : function() {
78 var t = this, r, p, e, p2;
83 if (!t.isMenuRendered) {
85 t.isMenuRendered = true;
92 DOM.show(t.id + '_menu');
93 DOM.addClass(e, 'mceSplitButtonSelected');
95 DOM.setStyles(t.id + '_menu', {
97 top : p2.y + e.clientHeight,
102 Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
103 t.onShowMenu.dispatch(t);
106 t._keyHandler = Event.add(t.id + '_menu', 'keydown', function(e) {
111 DOM.select('a', t.id + '_menu')[0].focus(); // Select first link
118 * Hides the color menu. The optional event parameter is used to check where the event occured so it
119 * doesn't close them menu if it was a event inside the menu.
122 * @param {Event} e Optional event object.
124 hideMenu : function(e) {
127 if (t.isMenuVisible) {
128 // Prevent double toogles by canceling the mouse click event to the button
129 if (e && e.type == "mousedown" && DOM.getParent(e.target, function(e) {return e.id === t.id + '_open';}))
132 if (!e || !DOM.getParent(e.target, '.mceSplitButtonMenu')) {
133 DOM.removeClass(t.id, 'mceSplitButtonSelected');
134 Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
135 Event.remove(t.id + '_menu', 'keydown', t._keyHandler);
136 DOM.hide(t.id + '_menu');
144 * Renders the menu to the DOM.
148 renderMenu : function() {
149 var t = this, m, i = 0, s = t.settings, n, tb, tr, w, context;
151 w = DOM.add(s.menu_container, 'div', {role: 'listbox', id : t.id + '_menu', 'class' : s['menu_class'] + ' ' + s['class'], style : 'position:absolute;left:0;top:-1000px;'});
152 m = DOM.add(w, 'div', {'class' : s['class'] + ' mceSplitButtonMenu'});
153 DOM.add(m, 'span', {'class' : 'mceMenuLine'});
155 n = DOM.add(m, 'table', {role: 'presentation', 'class' : 'mceColorSplitMenu'});
156 tb = DOM.add(n, 'tbody');
158 // Generate color grid
160 each(is(s.colors, 'array') ? s.colors : s.colors.split(','), function(c) {
161 c = c.replace(/^#/, '');
164 tr = DOM.add(tb, 'tr');
165 i = s.grid_width - 1;
168 n = DOM.add(tr, 'td');
169 n = DOM.add(n, 'a', {
171 href : 'javascript:;',
173 backgroundColor : '#' + c
175 'title': t.editor.getLang('colors.' + c, c),
176 'data-mce-color' : '#' + c
179 if (t.editor.forcedHighContrastMode) {
180 n = DOM.add(n, 'canvas', { width: 16, height: 16, 'aria-hidden': 'true' });
181 if (n.getContext && (context = n.getContext("2d"))) {
182 context.fillStyle = '#' + c;
183 context.fillRect(0, 0, 16, 16);
185 // No point leaving a canvas element around if it's not supported for drawing on anyway.
191 if (s.more_colors_func) {
192 n = DOM.add(tb, 'tr');
193 n = DOM.add(n, 'td', {colspan : s.grid_width, 'class' : 'mceMoreColors'});
194 n = DOM.add(n, 'a', {role: 'option', id : t.id + '_more', href : 'javascript:;', onclick : 'return false;', 'class' : 'mceMoreColors'}, s.more_colors_title);
196 Event.add(n, 'click', function(e) {
197 s.more_colors_func.call(s.more_colors_scope || this);
198 return Event.cancel(e); // Cancel to fix onbeforeunload problem
202 DOM.addClass(m, 'mceColorSplitMenu');
204 new tinymce.ui.KeyboardNavigation({
205 root: t.id + '_menu',
206 items: DOM.select('a', t.id + '_menu'),
207 onCancel: function() {
213 // Prevent IE from scrolling and hindering click to occur #4019
214 Event.add(t.id + '_menu', 'mousedown', function(e) {return Event.cancel(e);});
216 Event.add(t.id + '_menu', 'click', function(e) {
219 e = DOM.getParent(e.target, 'a', tb);
221 if (e && e.nodeName.toLowerCase() == 'a' && (c = e.getAttribute('data-mce-color')))
224 return Event.cancel(e); // Prevent IE auto save warning
231 * Sets the current color for the control and hides the menu if it should be visible.
234 * @param {String} c Color code value in hex for example: #FF00FF
236 setColor : function(c) {
237 this.displayColor(c);
239 this.settings.onselect(c);
243 * Change the currently selected color for the control.
245 * @method displayColor
246 * @param {String} c Color code value in hex for example: #FF00FF
248 displayColor : function(c) {
251 DOM.setStyle(t.id + '_preview', 'backgroundColor', c);
257 * Post render event. This will be executed after the control has been rendered and can be used to
258 * set states, add events to the control etc. It's recommended for subclasses of the control to call this method by using this.parent().
262 postRender : function() {
263 var t = this, id = t.id;
266 DOM.add(id + '_action', 'div', {id : id + '_preview', 'class' : 'mceColorPreview'});
267 DOM.setStyle(t.id + '_preview', 'backgroundColor', t.value);
271 * Destroys the control. This means it will be removed from the DOM and any
272 * events tied to it will also be removed.
276 destroy : function() {
279 Event.clear(this.id + '_menu');
280 Event.clear(this.id + '_more');
281 DOM.remove(this.id + '_menu');