1 /**
  2  * SlickGrid color editor and formatter.
  3  *
  4  * @module SlickGridColors
  5  */
  6 define([
  7     'jquery',
  8     'underscore',
  9     'view',
 10     'viewcontroller',
 11     'spectrum'
 12 ],
 13 function($, _, DecompositionView, ViewControllers, spectrum) {
 14 
 15   /**
 16    *
 17    * @class ColorEditor
 18    *
 19    * This class represents a color editor defined by the SlickGrid
 20    * project.
 21    *
 22    * Note, this object is heavily based on classes in slick.editors.js and in
 23    * the documentation that can be found [here](https://github.com/mleibman/
 24    * SlickGrid/wiki/Writing-custom-cell-editors).
 25    *
 26    * Also see ColorFormatter, a function in charge of formatting colors for the
 27    * SlickGrid object.
 28    *
 29    * @param {object} args Arguments passed by SlickGrid.
 30    *
 31    * @constructs ColorEditor
 32    * @alias module:SlickGridColors.ColorEditor
 33    *
 34    */
 35   function ColorEditor(args) {
 36     var $input = $("<div class='colorbox'></div>");
 37     var defaultValue;
 38     var scope = this;
 39 
 40     this.init = function() {
 41       // make the background look exactly the same when the color is being
 42       // edited
 43       $(args.container).css('background-color', '#eeeeee');
 44       $input.appendTo($(args.container));
 45       $input.css('background-color', args.item.value);
 46 
 47       // initialize spectrum
 48       $input.spectrum({
 49         color: args.item.color,
 50         showInput: true,
 51         allowEmpty: false,
 52         showInitial: true,
 53         clickoutFiresChange: true,
 54         className: 'full-spectrum',
 55         preferredFormat: 'hex6',
 56         // Show the whole set of color palette on the menu (only discrete)
 57         showPalette: args.grid.selectionPalette !== undefined,
 58         showSelectionPalette: args.grid.selectionPalette !== undefined,
 59         palette: args.grid.selectionPalette,
 60 
 61 
 62         /* On change callback */
 63         change: function(color) {
 64           $input.css('background-color', color.toHexString());
 65 
 66           // commit the changes as soon as a new shape is selected
 67           // https://stackoverflow.com/a/35768360/379593
 68           args.grid.getEditorLock().commitCurrentEdit();
 69           args.grid.resetActiveCell();
 70         }
 71       });
 72 
 73       // Don't propagate the keydown and keypress events so that inputing a
 74       // color doesn't interfere with the shortcuts of the Jupyter Notebook
 75       $input
 76         .spectrum('container')
 77         .find('.sp-input')
 78         .on('keydown keypress', function(e) {
 79           e.stopPropagation();
 80         });
 81     };
 82 
 83     this.destroy = function() {
 84       $input.spectrum('hide');
 85       $input.spectrum('destroy');
 86       $input.remove();
 87     };
 88 
 89     this.focus = function() {
 90       $input.focus();
 91       $input.spectrum('show');
 92     };
 93 
 94     this.isValueChanged = function() {
 95       return $input.spectrum('get').toHexString() !== defaultValue;
 96     };
 97 
 98     this.serializeValue = function() {
 99       return $input.spectrum('get').toHexString();
100     };
101 
102     this.loadValue = function(item) {
103       defaultValue = item[args.column.field];
104       $input.spectrum('set', defaultValue);
105     };
106 
107     this.applyValue = function(item, state) {
108       item[args.column.field] = state;
109     };
110 
111     this.validate = function() {
112       return {valid: true, msg: null};
113     };
114 
115     this.hide = function() {
116       $input.spectrum('hide');
117     };
118 
119     this.show = function() {
120       /*
121        *
122        * We setup a brief timeout that gives the browser enough time to finish
123        * preparing the specturm widget. If we don't wait for 100 milliseconds,
124        * opening the color picker will take two clicks. This is also a
125        * consequence of spectrum initializing asynchronously, by the time
126        * SlickGrid executes the show method the widget is not ready yet so the
127        * 'spectrum('show')' call results in a noop, and in order to show the
128        * color picker users would need to click again on the colorbox.
129        *
130        */
131       setTimeout(function() {
132         $input.spectrum('show');
133       }, 100);
134     };
135 
136     this.position = function(cellBox) {
137       $input.spectrum('reflow');
138     };
139 
140     this.init();
141   }
142 
143   /**
144    *
145    * Function to format colors for the SlickGrid object.
146    *
147    * This formatter is heavily based in the examples found in
148    * slick.formattters.js and is only intended to be used with ColorFormatter.
149    *
150    * @param {integer} row SlickGrid row.
151    * @param {integer} cell SlickGrid cell.
152    * @param {integer|string|bool} value The value in the row.
153    * @param {object} columnDef SlickGrid column definition.
154    * @param {object} dataContext Data model of the SlickGrid object.
155    *
156    * @return {string} String with a div where the background color is set as
157    * the value that's passed in.
158    *
159    * @alias module:SlickGridColors.ColorFormatter
160    *
161    */
162   function ColorFormatter(row, cell, value, columnDef, dataContext) {
163     return "<div class='colorbox' style='cursor:pointer;background-color:" +
164            value + ";'></div>";
165   }
166 
167   return {'ColorEditor': ColorEditor, 'ColorFormatter': ColorFormatter};
168 });
169