1 /**
  2  * color picker
  3  * @author yiminghe@gmail.com
  4  */
  5 KISSY.add("editor/plugin/color/colorPicker/dialog", function (S, Editor, Overlay4E) {
  6     var map = S.map,
  7         DOM = S.DOM;
  8 
  9     DOM.addStyleSheet("" +
 10         ".ks-editor-color-advanced-picker-left {" +
 11         "float:left;" +
 12         "display:inline;" +
 13         "margin-left:10px;" +
 14         "}" +
 15 
 16         ".ks-editor-color-advanced-picker-right {" +
 17         "float:right;" +
 18         "width:50px;" +
 19         "display:inline;" +
 20         "margin:13px 10px 0 0;" +
 21         "cursor:crosshair;" +
 22         "}" +
 23         "" +
 24         ".ks-editor-color-advanced-picker-right a {" +
 25         "height:2px;" +
 26         "line-height:0;" +
 27         "fontSize:0;" +
 28         "display:block;" +
 29         "}" +
 30         "" +
 31 
 32         ".ks-editor-color-advanced-picker-left ul{" +
 33         "float:left;" +
 34         "}" +
 35         ".ks-editor-color-advanced-picker-left li,.ks-editor-color-advanced-picker-left a{" +
 36         "overflow:hidden;" +
 37         "width:15px;" +
 38         "height:16px;" +
 39         "line-height:0;" +
 40         "fontSize:0;" +
 41         "display:block;" +
 42         "}" +
 43         ".ks-editor-color-advanced-picker-left a:hover{" +
 44         "width:13px;height:13px;border:1px solid white;" +
 45         "}" +
 46         "" +
 47         ".ks-editor-color-advanced-indicator {" +
 48         "margin-left:10px;" +
 49         "*zoom:1;" +
 50         "display:inline-block;" +
 51         "*display:inline;" +
 52         "width:68px;" +
 53         "height:24px;" +
 54         "vertical-align:middle;" +
 55         "line-height:0;" +
 56         "overflow:hidden;" +
 57         "}", "ks-editor-color-advanced");
 58 
 59     //获取颜色数组
 60     function getData(color) {
 61         if (S.isArray(color)) return color;
 62         var re = RegExp;
 63         if (/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.test(color)) {
 64             //#rrggbb
 65             return map([ re['$1'], re['$2'], re['$3'] ], function (x) {
 66                 return parseInt(x, 16);
 67             });
 68         } else if (/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(color)) {
 69             //#rgb
 70             return map([ re['$1'], re['$2'], re['$3'] ], function (x) {
 71                 return parseInt(x + x, 16);
 72             });
 73         } else if (/^rgb\((.*),(.*),(.*)\)$/i.test(color)) {
 74             //rgb(n,n,n) or rgb(n%,n%,n%)
 75             return map([ re['$1'], re['$2'], re['$3'] ], function (x) {
 76                 return x.indexOf("%") > 0 ? parseFloat(x, 10) * 2.55 : x | 0;
 77             });
 78         }
 79         return undefined;
 80     }
 81 
 82     //refer:http://www.cnblogs.com/cloudgamer/archive/2009/03/11/color.html
 83     //http://yiminghe.javaeye.com/blog/511589
 84     //获取颜色梯度方法
 85     var ColorGrads = (function () {
 86         //获取颜色梯度数据
 87         function getStep(start, end, step) {
 88             var colors = [];
 89             start = getColor(start);
 90             end = getColor(end);
 91             var stepR = (end[0] - start[0]) / step,
 92                 stepG = (end[1] - start[1]) / step,
 93                 stepB = (end[2] - start[2]) / step;
 94             //生成颜色集合
 95             for (var i = 0, r = start[0], g = start[1], b = start[2]; i < step; i++) {
 96                 colors[i] = [r, g, b];
 97                 r += stepR;
 98                 g += stepG;
 99                 b += stepB;
100             }
101             colors[i] = end;
102             //修正颜色值
103             return map(colors, function (x) {
104                 return map(x, function (x) {
105                     return Math.min(Math.max(0, Math.floor(x)), 255);
106                 });
107             });
108         }
109 
110         //获取颜色数据
111         var frag;
112 
113         function getColor(color) {
114             var ret = getData(color);
115             if (ret === undefined) {
116                 if (!frag) {
117                     frag = document.createElement("textarea");
118                     frag.style.display = "none";
119                     DOM.prepend(frag, document.body);
120                 }
121                 try {
122                     frag.style.color = color;
123                 } catch (e) {
124                     return [0, 0, 0];
125                 }
126 
127                 if (document.defaultView) {
128                     ret = getData(document.defaultView.getComputedStyle(frag, null).color);
129                 } else {
130                     color = frag.createTextRange()['queryCommandValue']("ForeColor");
131                     ret = [ color & 0x0000ff, (color & 0x00ff00) >>> 8, (color & 0xff0000) >>> 16 ];
132                 }
133             }
134             return ret;
135         }
136 
137 
138         return function (colors, step) {
139             var ret = [], len = colors.length;
140             if (step === undefined) {
141                 step = 20;
142             }
143             if (len == 1) {
144                 ret = getStep(colors[0], colors[0], step);
145             } else if (len > 1) {
146                 for (var i = 0, n = len - 1; i < n; i++) {
147                     var t = step[i] || step;
148                     var steps = getStep(colors[i], colors[i + 1], t);
149                     i < n - 1 && steps.pop();
150                     ret = ret.concat(steps);
151                 }
152             }
153             return ret;
154         }
155     })();
156 
157     function padding2(x) {
158         x = "0" + x;
159         var l = x.length;
160         return x.slice(l - 2, l);
161     }
162 
163     function hex(c) {
164         c = getData(c);
165         return "#" + padding2(c[0].toString(16))
166             + padding2(c[1].toString(16))
167             + padding2(c[2].toString(16));
168     }
169 
170     var pickerHtml = "<ul>" +
171         map(ColorGrads([ "red", "orange", "yellow", "green", "cyan", "blue", "purple" ], 5),
172             function (x) {
173                 return map(ColorGrads([ "white", "rgb(" + x.join(",") + ")" , "black" ], 5),
174                     function (x) {
175                         return "<li><a style='background-color" + ":" + hex(x) + "' href='#'></a></li>";
176                     }).join("");
177             }).join("</ul><ul>") + "</ul>",
178         panelHtml = "<div class='ks-editor-color-advanced-picker'>" +
179             "<div class='ks-clear'>" +
180             "<div class='ks-editor-color-advanced-picker-left'>" +
181             pickerHtml +
182             "</div>" +
183             "<div class='ks-editor-color-advanced-picker-right'>" +
184             "</div>" +
185             "</div>" +
186             "<div style='padding:10px;'>" +
187             "<label>" +
188             "颜色值: " +
189             "<input style='width:100px' class='ks-editor-color-advanced-value'/>" +
190             "</label>" +
191             "<span class='ks-editor-color-advanced-indicator'></span>" +
192             "</div>" +
193             "</div>",
194         footHtml = "<div style='padding:5px 20px 20px;'>" +
195             "<a class='ks-editor-button ks-editor-color-advanced-ok ks-inline-block'>确定</a>" +
196             "   " +
197             "<a class='ks-editor-button  ks-editor-color-advanced-cancel ks-inline-block'>取消</a>" +
198             "</div>";
199 
200     function ColorPicker(editor) {
201         this.editor = editor;
202         this._init();
203     }
204 
205     var addRes = Editor.Utils.addRes, destroyRes = Editor.Utils.destroyRes;
206 
207     S.augment(ColorPicker, {
208         _init:function () {
209             var self = this;
210 
211             self.dialog = new Overlay4E.Dialog({
212                 mask:true,
213                 headerContent:"颜色拾取器",
214                 bodyContent:panelHtml,
215                 footerContent:footHtml,
216                 autoRender:true,
217                 width:"550px"
218             });
219             var win = self.dialog,
220                 body = win.get("body"),
221                 foot = win.get("footer"),
222                 indicator = body.one(".ks-editor-color-advanced-indicator"),
223                 indicatorValue = body.one(".ks-editor-color-advanced-value"),
224                 left = body.one(".ks-editor-color-advanced-picker-left"),
225                 right = body.one(".ks-editor-color-advanced-picker-right"),
226                 ok = foot.one(".ks-editor-color-advanced-ok"),
227                 cancel = foot.one(".ks-editor-color-advanced-cancel");
228 
229             ok.on("click", function (ev) {
230                 var v = S.trim(indicatorValue.val()),
231                     cmd = self.cmd;
232                 if (!/^#([a-f0-9]{1,2}){3,3}$/i.test(v)) {
233                     alert("请输入正确的颜色代码");
234                     return;
235                 }
236                 //先隐藏窗口,使得编辑器恢复焦点,恢复原先range
237                 self.hide();
238                 setTimeout(function () {
239                     self.editor.execCommand(cmd, indicatorValue.val());
240                 }, 0);
241                 ev.halt();
242             });
243 
244 
245             indicatorValue.on("change", function () {
246                 var v = S.trim(indicatorValue.val());
247                 if (!/^#([a-f0-9]{1,2}){3,3}$/i.test(v)) {
248                     alert("请输入正确的颜色代码");
249                     return;
250                 }
251                 indicator.css("background-color", v);
252             });
253 
254 
255             cancel.on("click", function (ev) {
256                 self.hide();
257                 ev && ev.halt();
258             });
259             body.on("click", function (ev) {
260                 ev.halt();
261                 var t = new S.Node(ev.target);
262                 if (t.nodeName() == "a") {
263                     var c = hex(t.css("background-color"));
264                     if (left.contains(t))self._detailColor(c);
265                     indicatorValue.val(c);
266                     indicator.css("background-color", c);
267                 }
268             });
269             addRes.call(self, ok, indicatorValue, cancel, body, self.dialog);
270 
271             var defaultColor = "#FF9900";
272             self._detailColor(defaultColor);
273             indicatorValue.val(defaultColor);
274             indicator.css("background-color", defaultColor);
275         },
276 
277         _detailColor:function (color) {
278             var self = this,
279                 win = self.dialog,
280                 body = win.get("body"),
281                 detailPanel = body.one(".ks-editor-color-advanced-picker-right");
282 
283             detailPanel.html(map(ColorGrads(["#ffffff", color, "#000000"], 40),
284                 function (x) {
285                     return "<a style='background-color:" + hex(x) + "'></a>";
286                 }).join(""));
287         },
288         show:function (cmd) {
289             this.cmd = cmd;
290             this.dialog.show();
291         },
292         hide:function () {
293             this.dialog.hide();
294         },
295         destroy:function () {
296             destroyRes.call(this);
297         }
298     });
299 
300     return ColorPicker;
301 }, {
302     requires:['editor', '../../overlay/']
303 });