bootstrap-colorpicker.js 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  1. /*!
  2. * Bootstrap Colorpicker
  3. * http://mjolnic.github.io/bootstrap-colorpicker/
  4. *
  5. * Originally written by (c) 2012 Stefan Petre
  6. * Licensed under the Apache License v2.0
  7. * http://www.apache.org/licenses/LICENSE-2.0.txt
  8. *
  9. * @todo Update DOCS
  10. */
  11. (function($) {
  12. 'use strict';
  13. // Color object
  14. var Color = function(val) {
  15. this.value = {
  16. h: 0,
  17. s: 0,
  18. b: 0,
  19. a: 1
  20. };
  21. this.origFormat = null; // original string format
  22. if (val) {
  23. if (val.toLowerCase !== undefined) {
  24. this.setColor(val);
  25. } else if (val.h !== undefined) {
  26. this.value = val;
  27. }
  28. }
  29. };
  30. Color.prototype = {
  31. constructor: Color,
  32. _sanitizeNumber: function(val) {
  33. if (typeof val === 'number') {
  34. return val;
  35. }
  36. if (isNaN(val) || (val === null) || (val === '') || (val === undefined)) {
  37. return 1;
  38. }
  39. if (val.toLowerCase !== undefined) {
  40. return parseFloat(val);
  41. }
  42. return 1;
  43. },
  44. //parse a string to HSB
  45. setColor: function(strVal) {
  46. strVal = strVal.toLowerCase();
  47. this.value = this.stringToHSB(strVal) ||  {
  48. h: 0,
  49. s: 0,
  50. b: 0,
  51. a: 1
  52. };
  53. },
  54. stringToHSB: function(strVal) {
  55. strVal = strVal.toLowerCase();
  56. var that = this,
  57. result = false;
  58. $.each(this.stringParsers, function(i, parser) {
  59. var match = parser.re.exec(strVal),
  60. values = match && parser.parse.apply(that, [match]),
  61. format = parser.format || 'rgba';
  62. if (values) {
  63. if (format.match(/hsla?/)) {
  64. result = that.RGBtoHSB.apply(that, that.HSLtoRGB.apply(that, values));
  65. } else {
  66. result = that.RGBtoHSB.apply(that, values);
  67. }
  68. that.origFormat = format;
  69. return false;
  70. }
  71. return true;
  72. });
  73. return result;
  74. },
  75. setHue: function(h) {
  76. this.value.h = 1 - h;
  77. },
  78. setSaturation: function(s) {
  79. this.value.s = s;
  80. },
  81. setBrightness: function(b) {
  82. this.value.b = 1 - b;
  83. },
  84. setAlpha: function(a) {
  85. this.value.a = parseInt((1 - a) * 100, 10) / 100;
  86. },
  87. toRGB: function(h, s, v, a) {
  88. h = h || this.value.h;
  89. s = s || this.value.s;
  90. v = v || this.value.b;
  91. a = a || this.value.a;
  92. var r, g, b, i, f, p, q, t;
  93. if (h && s === undefined && v === undefined) {
  94. s = h.s, v = h.v, h = h.h;
  95. }
  96. i = Math.floor(h * 6);
  97. f = h * 6 - i;
  98. p = v * (1 - s);
  99. q = v * (1 - f * s);
  100. t = v * (1 - (1 - f) * s);
  101. switch (i % 6) {
  102. case 0:
  103. r = v, g = t, b = p;
  104. break;
  105. case 1:
  106. r = q, g = v, b = p;
  107. break;
  108. case 2:
  109. r = p, g = v, b = t;
  110. break;
  111. case 3:
  112. r = p, g = q, b = v;
  113. break;
  114. case 4:
  115. r = t, g = p, b = v;
  116. break;
  117. case 5:
  118. r = v, g = p, b = q;
  119. break;
  120. }
  121. return {
  122. r: Math.floor(r * 255),
  123. g: Math.floor(g * 255),
  124. b: Math.floor(b * 255),
  125. a: a
  126. };
  127. },
  128. toHex: function(h, s, b, a) {
  129. var rgb = this.toRGB(h, s, b, a);
  130. return '#' + ((1 << 24) | (parseInt(rgb.r) << 16) | (parseInt(rgb.g) << 8) | parseInt(rgb.b)).toString(16).substr(1);
  131. },
  132. toHSL: function(h, s, b, a) {
  133. h = h || this.value.h;
  134. s = s || this.value.s;
  135. b = b || this.value.b;
  136. a = a || this.value.a;
  137. var H = h,
  138. L = (2 - s) * b,
  139. S = s * b;
  140. if (L > 0 && L <= 1) {
  141. S /= L;
  142. } else {
  143. S /= 2 - L;
  144. }
  145. L /= 2;
  146. if (S > 1) {
  147. S = 1;
  148. }
  149. return {
  150. h: H,
  151. s: S,
  152. l: L,
  153. a: a
  154. };
  155. },
  156. RGBtoHSB: function(r, g, b, a) {
  157. r /= 255;
  158. g /= 255;
  159. b /= 255;
  160. var H, S, V, C;
  161. V = Math.max(r, g, b);
  162. C = V - Math.min(r, g, b);
  163. H = (C === 0 ? null :
  164. V === r ? (g - b) / C :
  165. V === g ? (b - r) / C + 2 :
  166. (r - g) / C + 4
  167. );
  168. H = ((H + 360) % 6) * 60 / 360;
  169. S = C === 0 ? 0 : C / V;
  170. return {
  171. h: this._sanitizeNumber(H),
  172. s: S,
  173. b: V,
  174. a: this._sanitizeNumber(a)
  175. };
  176. },
  177. HueToRGB: function(p, q, h) {
  178. if (h < 0) {
  179. h += 1;
  180. } else if (h > 1) {
  181. h -= 1;
  182. }
  183. if ((h * 6) < 1) {
  184. return p + (q - p) * h * 6;
  185. } else if ((h * 2) < 1) {
  186. return q;
  187. } else if ((h * 3) < 2) {
  188. return p + (q - p) * ((2 / 3) - h) * 6;
  189. } else {
  190. return p;
  191. }
  192. },
  193. HSLtoRGB: function(h, s, l, a) {
  194. if (s < 0) {
  195. s = 0;
  196. }
  197. var q;
  198. if (l <= 0.5) {
  199. q = l * (1 + s);
  200. } else {
  201. q = l + s - (l * s);
  202. }
  203. var p = 2 * l - q;
  204. var tr = h + (1 / 3);
  205. var tg = h;
  206. var tb = h - (1 / 3);
  207. var r = Math.round(this.HueToRGB(p, q, tr) * 255);
  208. var g = Math.round(this.HueToRGB(p, q, tg) * 255);
  209. var b = Math.round(this.HueToRGB(p, q, tb) * 255);
  210. return [r, g, b, this._sanitizeNumber(a)];
  211. },
  212. toString: function(format) {
  213. format = format ||  'rgba';
  214. switch (format) {
  215. case 'rgb':
  216. {
  217. var rgb = this.toRGB();
  218. return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
  219. }
  220. break;
  221. case 'rgba':
  222. {
  223. var rgb = this.toRGB();
  224. return 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
  225. }
  226. break;
  227. case 'hsl':
  228. {
  229. var hsl = this.toHSL();
  230. return 'hsl(' + Math.round(hsl.h * 360) + ',' + Math.round(hsl.s * 100) + '%,' + Math.round(hsl.l * 100) + '%)';
  231. }
  232. break;
  233. case 'hsla':
  234. {
  235. var hsl = this.toHSL();
  236. return 'hsla(' + Math.round(hsl.h * 360) + ',' + Math.round(hsl.s * 100) + '%,' + Math.round(hsl.l * 100) + '%,' + hsl.a + ')';
  237. }
  238. break;
  239. case 'hex':
  240. {
  241. return this.toHex();
  242. }
  243. break;
  244. default:
  245. {
  246. return false;
  247. }
  248. break;
  249. }
  250. },
  251. // a set of RE's that can match strings and generate color tuples.
  252. // from John Resig color plugin
  253. // https://github.com/jquery/jquery-color/
  254. stringParsers: [{
  255. re: /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/,
  256. format: 'hex',
  257. parse: function(execResult) {
  258. return [
  259. parseInt(execResult[1], 16),
  260. parseInt(execResult[2], 16),
  261. parseInt(execResult[3], 16),
  262. 1
  263. ];
  264. }
  265. }, {
  266. re: /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/,
  267. format: 'hex',
  268. parse: function(execResult) {
  269. return [
  270. parseInt(execResult[1] + execResult[1], 16),
  271. parseInt(execResult[2] + execResult[2], 16),
  272. parseInt(execResult[3] + execResult[3], 16),
  273. 1
  274. ];
  275. }
  276. }, {
  277. re: /rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*?\)/,
  278. format: 'rgb',
  279. parse: function(execResult) {
  280. return [
  281. execResult[1],
  282. execResult[2],
  283. execResult[3],
  284. 1
  285. ];
  286. }
  287. }, {
  288. re: /rgb\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*?\)/,
  289. format: 'rgb',
  290. parse: function(execResult) {
  291. return [
  292. 2.55 * execResult[1],
  293. 2.55 * execResult[2],
  294. 2.55 * execResult[3],
  295. 1
  296. ];
  297. }
  298. }, {
  299. re: /rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
  300. format: 'rgba',
  301. parse: function(execResult) {
  302. return [
  303. execResult[1],
  304. execResult[2],
  305. execResult[3],
  306. execResult[4]
  307. ];
  308. }
  309. }, {
  310. re: /rgba\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
  311. format: 'rgba',
  312. parse: function(execResult) {
  313. return [
  314. 2.55 * execResult[1],
  315. 2.55 * execResult[2],
  316. 2.55 * execResult[3],
  317. execResult[4]
  318. ];
  319. }
  320. }, {
  321. re: /hsl\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*?\)/,
  322. format: 'hsl',
  323. parse: function(execResult) {
  324. return [
  325. execResult[1] / 360,
  326. execResult[2] / 100,
  327. execResult[3] / 100,
  328. execResult[4]
  329. ];
  330. }
  331. }, {
  332. re: /hsla\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
  333. format: 'hsla',
  334. parse: function(execResult) {
  335. return [
  336. execResult[1] / 360,
  337. execResult[2] / 100,
  338. execResult[3] / 100,
  339. execResult[4]
  340. ];
  341. }
  342. }, {
  343. //predefined color name
  344. re: /^([a-z]{3,})$/,
  345. format: 'alias',
  346. parse: function(execResult) {
  347. var hexval = this.colorNameToHex(execResult[0]) ||  '#000000';
  348. var match = this.stringParsers[0].re.exec(hexval),
  349. values = match && this.stringParsers[0].parse.apply(this, [match]);
  350. return values;
  351. }
  352. }],
  353. colorNameToHex: function(name) {
  354. // 140 predefined colors from the HTML Colors spec
  355. var colors = {
  356. "aliceblue": "#f0f8ff",
  357. "antiquewhite": "#faebd7",
  358. "aqua": "#00ffff",
  359. "aquamarine": "#7fffd4",
  360. "azure": "#f0ffff",
  361. "beige": "#f5f5dc",
  362. "bisque": "#ffe4c4",
  363. "black": "#000000",
  364. "blanchedalmond": "#ffebcd",
  365. "blue": "#0000ff",
  366. "blueviolet": "#8a2be2",
  367. "brown": "#a52a2a",
  368. "burlywood": "#deb887",
  369. "cadetblue": "#5f9ea0",
  370. "chartreuse": "#7fff00",
  371. "chocolate": "#d2691e",
  372. "coral": "#ff7f50",
  373. "cornflowerblue": "#6495ed",
  374. "cornsilk": "#fff8dc",
  375. "crimson": "#dc143c",
  376. "cyan": "#00ffff",
  377. "darkblue": "#00008b",
  378. "darkcyan": "#008b8b",
  379. "darkgoldenrod": "#b8860b",
  380. "darkgray": "#a9a9a9",
  381. "darkgreen": "#006400",
  382. "darkkhaki": "#bdb76b",
  383. "darkmagenta": "#8b008b",
  384. "darkolivegreen": "#556b2f",
  385. "darkorange": "#ff8c00",
  386. "darkorchid": "#9932cc",
  387. "darkred": "#8b0000",
  388. "darksalmon": "#e9967a",
  389. "darkseagreen": "#8fbc8f",
  390. "darkslateblue": "#483d8b",
  391. "darkslategray": "#2f4f4f",
  392. "darkturquoise": "#00ced1",
  393. "darkviolet": "#9400d3",
  394. "deeppink": "#ff1493",
  395. "deepskyblue": "#00bfff",
  396. "dimgray": "#696969",
  397. "dodgerblue": "#1e90ff",
  398. "firebrick": "#b22222",
  399. "floralwhite": "#fffaf0",
  400. "forestgreen": "#228b22",
  401. "fuchsia": "#ff00ff",
  402. "gainsboro": "#dcdcdc",
  403. "ghostwhite": "#f8f8ff",
  404. "gold": "#ffd700",
  405. "goldenrod": "#daa520",
  406. "gray": "#808080",
  407. "green": "#008000",
  408. "greenyellow": "#adff2f",
  409. "honeydew": "#f0fff0",
  410. "hotpink": "#ff69b4",
  411. "indianred ": "#cd5c5c",
  412. "indigo ": "#4b0082",
  413. "ivory": "#fffff0",
  414. "khaki": "#f0e68c",
  415. "lavender": "#e6e6fa",
  416. "lavenderblush": "#fff0f5",
  417. "lawngreen": "#7cfc00",
  418. "lemonchiffon": "#fffacd",
  419. "lightblue": "#add8e6",
  420. "lightcoral": "#f08080",
  421. "lightcyan": "#e0ffff",
  422. "lightgoldenrodyellow": "#fafad2",
  423. "lightgrey": "#d3d3d3",
  424. "lightgreen": "#90ee90",
  425. "lightpink": "#ffb6c1",
  426. "lightsalmon": "#ffa07a",
  427. "lightseagreen": "#20b2aa",
  428. "lightskyblue": "#87cefa",
  429. "lightslategray": "#778899",
  430. "lightsteelblue": "#b0c4de",
  431. "lightyellow": "#ffffe0",
  432. "lime": "#00ff00",
  433. "limegreen": "#32cd32",
  434. "linen": "#faf0e6",
  435. "magenta": "#ff00ff",
  436. "maroon": "#800000",
  437. "mediumaquamarine": "#66cdaa",
  438. "mediumblue": "#0000cd",
  439. "mediumorchid": "#ba55d3",
  440. "mediumpurple": "#9370d8",
  441. "mediumseagreen": "#3cb371",
  442. "mediumslateblue": "#7b68ee",
  443. "mediumspringgreen": "#00fa9a",
  444. "mediumturquoise": "#48d1cc",
  445. "mediumvioletred": "#c71585",
  446. "midnightblue": "#191970",
  447. "mintcream": "#f5fffa",
  448. "mistyrose": "#ffe4e1",
  449. "moccasin": "#ffe4b5",
  450. "navajowhite": "#ffdead",
  451. "navy": "#000080",
  452. "oldlace": "#fdf5e6",
  453. "olive": "#808000",
  454. "olivedrab": "#6b8e23",
  455. "orange": "#ffa500",
  456. "orangered": "#ff4500",
  457. "orchid": "#da70d6",
  458. "palegoldenrod": "#eee8aa",
  459. "palegreen": "#98fb98",
  460. "paleturquoise": "#afeeee",
  461. "palevioletred": "#d87093",
  462. "papayawhip": "#ffefd5",
  463. "peachpuff": "#ffdab9",
  464. "peru": "#cd853f",
  465. "pink": "#ffc0cb",
  466. "plum": "#dda0dd",
  467. "powderblue": "#b0e0e6",
  468. "purple": "#800080",
  469. "red": "#ff0000",
  470. "rosybrown": "#bc8f8f",
  471. "royalblue": "#4169e1",
  472. "saddlebrown": "#8b4513",
  473. "salmon": "#fa8072",
  474. "sandybrown": "#f4a460",
  475. "seagreen": "#2e8b57",
  476. "seashell": "#fff5ee",
  477. "sienna": "#a0522d",
  478. "silver": "#c0c0c0",
  479. "skyblue": "#87ceeb",
  480. "slateblue": "#6a5acd",
  481. "slategray": "#708090",
  482. "snow": "#fffafa",
  483. "springgreen": "#00ff7f",
  484. "steelblue": "#4682b4",
  485. "tan": "#d2b48c",
  486. "teal": "#008080",
  487. "thistle": "#d8bfd8",
  488. "tomato": "#ff6347",
  489. "turquoise": "#40e0d0",
  490. "violet": "#ee82ee",
  491. "wheat": "#f5deb3",
  492. "white": "#ffffff",
  493. "whitesmoke": "#f5f5f5",
  494. "yellow": "#ffff00",
  495. "yellowgreen": "#9acd32"
  496. };
  497. if (typeof colors[name.toLowerCase()] !== 'undefined') {
  498. return colors[name.toLowerCase()];
  499. }
  500. return false;
  501. }
  502. };
  503. var defaults = {
  504. horizontal: false, // horizontal mode layout ?
  505. inline: false, //forces to show the colorpicker as an inline element
  506. color: false, //forces a color
  507. format: false, //forces a format
  508. input: 'input', // children input selector
  509. container: false, // container selector
  510. component: '.add-on, .input-group-addon', // children component selector
  511. sliders: {
  512. saturation: {
  513. maxLeft: 100,
  514. maxTop: 100,
  515. callLeft: 'setSaturation',
  516. callTop: 'setBrightness'
  517. },
  518. hue: {
  519. maxLeft: 0,
  520. maxTop: 100,
  521. callLeft: false,
  522. callTop: 'setHue'
  523. },
  524. alpha: {
  525. maxLeft: 0,
  526. maxTop: 100,
  527. callLeft: false,
  528. callTop: 'setAlpha'
  529. }
  530. },
  531. slidersHorz: {
  532. saturation: {
  533. maxLeft: 100,
  534. maxTop: 100,
  535. callLeft: 'setSaturation',
  536. callTop: 'setBrightness'
  537. },
  538. hue: {
  539. maxLeft: 100,
  540. maxTop: 0,
  541. callLeft: 'setHue',
  542. callTop: false
  543. },
  544. alpha: {
  545. maxLeft: 100,
  546. maxTop: 0,
  547. callLeft: 'setAlpha',
  548. callTop: false
  549. }
  550. },
  551. template: '<div class="colorpicker dropdown-menu">' +
  552. '<div class="colorpicker-saturation"><i><b></b></i></div>' +
  553. '<div class="colorpicker-hue"><i></i></div>' +
  554. '<div class="colorpicker-alpha"><i></i></div>' +
  555. '<div class="colorpicker-color"><div /></div>' +
  556. '</div>'
  557. };
  558. var Colorpicker = function(element, options) {
  559. this.element = $(element).addClass('colorpicker-element');
  560. this.options = $.extend({}, defaults, this.element.data(), options);
  561. this.component = this.options.component;
  562. this.component = (this.component !== false) ? this.element.find(this.component) : false;
  563. if (this.component && (this.component.length === 0)) {
  564. this.component = false;
  565. }
  566. this.container = (this.options.container === true) ? this.element : this.options.container;
  567. this.container = (this.container !== false) ? $(this.container) : false;
  568. // Is the element an input? Should we search inside for any input?
  569. this.input = this.element.is('input') ? this.element : (this.options.input ?
  570. this.element.find(this.options.input) : false);
  571. if (this.input && (this.input.length === 0)) {
  572. this.input = false;
  573. }
  574. // Set HSB color
  575. this.color = new Color(this.options.color !== false ? this.options.color : this.getValue());
  576. this.format = this.options.format !== false ? this.options.format : this.color.origFormat;
  577. // Setup picker
  578. this.picker = $(this.options.template);
  579. if (this.options.inline) {
  580. this.picker.addClass('colorpicker-inline colorpicker-visible');
  581. } else {
  582. this.picker.addClass('colorpicker-hidden');
  583. }
  584. if (this.options.horizontal) {
  585. this.picker.addClass('colorpicker-horizontal');
  586. }
  587. if (this.format === 'rgba' || this.format === 'hsla') {
  588. this.picker.addClass('colorpicker-with-alpha');
  589. }
  590. this.picker.on('mousedown.colorpicker', $.proxy(this.mousedown, this));
  591. this.picker.appendTo(this.container ? this.container : $('body'));
  592. // Bind events
  593. if (this.input !== false) {
  594. this.input.on({
  595. 'keyup.colorpicker': $.proxy(this.keyup, this)
  596. });
  597. if (this.component === false) {
  598. this.element.on({
  599. 'focus.colorpicker': $.proxy(this.show, this)
  600. });
  601. }
  602. if (this.options.inline === false) {
  603. this.element.on({
  604. 'focusout.colorpicker': $.proxy(this.hide, this)
  605. });
  606. }
  607. }
  608. if (this.component !== false) {
  609. this.component.on({
  610. 'click.colorpicker': $.proxy(this.show, this)
  611. });
  612. }
  613. if ((this.input === false) && (this.component === false)) {
  614. this.element.on({
  615. 'click.colorpicker': $.proxy(this.show, this)
  616. });
  617. }
  618. this.update();
  619. $($.proxy(function() {
  620. this.element.trigger('create');
  621. }, this));
  622. };
  623. Colorpicker.version = '2.0.0-beta';
  624. Colorpicker.Color = Color;
  625. Colorpicker.prototype = {
  626. constructor: Colorpicker,
  627. destroy: function() {
  628. this.picker.remove();
  629. this.element.removeData('colorpicker').off('.colorpicker');
  630. if (this.input !== false) {
  631. this.input.off('.colorpicker');
  632. }
  633. if (this.component !== false) {
  634. this.component.off('.colorpicker');
  635. }
  636. this.element.removeClass('colorpicker-element');
  637. this.element.trigger({
  638. type: 'destroy'
  639. });
  640. },
  641. reposition: function() {
  642. if (this.options.inline !== false) {
  643. return false;
  644. }
  645. var offset = this.component ? this.component.offset() : this.element.offset();
  646. this.picker.css({
  647. top: offset.top + (this.component ? this.component.outerHeight() : this.element.outerHeight()),
  648. left: offset.left
  649. });
  650. },
  651. show: function(e) {
  652. if (this.isDisabled()) {
  653. return false;
  654. }
  655. this.picker.addClass('colorpicker-visible').removeClass('colorpicker-hidden');
  656. this.reposition();
  657. $(window).on('resize.colorpicker', $.proxy(this.reposition, this));
  658. if (!this.hasInput() && e) {
  659. if (e.stopPropagation && e.preventDefault) {
  660. e.stopPropagation();
  661. e.preventDefault();
  662. }
  663. }
  664. if (this.options.inline === false) {
  665. $(window.document).on({
  666. 'mousedown.colorpicker': $.proxy(this.hide, this)
  667. });
  668. }
  669. this.element.trigger({
  670. type: 'showPicker',
  671. color: this.color
  672. });
  673. },
  674. hide: function() {
  675. this.picker.addClass('colorpicker-hidden').removeClass('colorpicker-visible');
  676. $(window).off('resize.colorpicker', this.reposition);
  677. $(document).off({
  678. 'mousedown.colorpicker': this.hide
  679. });
  680. this.update();
  681. this.element.trigger({
  682. type: 'hidePicker',
  683. color: this.color
  684. });
  685. },
  686. updateData: function(val) {
  687. val = val ||  this.color.toString(this.format);
  688. this.element.data('color', val);
  689. return val;
  690. },
  691. updateInput: function(val) {
  692. val = val ||  this.color.toString(this.format);
  693. if (this.input !== false) {
  694. this.input.prop('value', val);
  695. }
  696. return val;
  697. },
  698. updatePicker: function(val) {
  699. if (val !== undefined) {
  700. this.color = new Color(val);
  701. }
  702. var sl = (this.options.horizontal === false) ? this.options.sliders : this.options.slidersHorz;
  703. var icns = this.picker.find('i');
  704. if (icns.length === 0) {
  705. return;
  706. }
  707. if (this.options.horizontal === false) {
  708. sl = this.options.sliders;
  709. icns.eq(1).css('top', sl.hue.maxTop * (1 - this.color.value.h)).end()
  710. .eq(2).css('top', sl.alpha.maxTop * (1 - this.color.value.a));
  711. } else {
  712. sl = this.options.slidersHorz;
  713. icns.eq(1).css('left', sl.hue.maxLeft * (1 - this.color.value.h)).end()
  714. .eq(2).css('left', sl.alpha.maxLeft * (1 - this.color.value.a));
  715. }
  716. icns.eq(0).css({
  717. 'top': sl.saturation.maxTop - this.color.value.b * sl.saturation.maxTop,
  718. 'left': this.color.value.s * sl.saturation.maxLeft
  719. });
  720. this.picker.find('.colorpicker-saturation').css('backgroundColor', this.color.toHex(this.color.value.h, 1, 1, 1));
  721. this.picker.find('.colorpicker-alpha').css('backgroundColor', this.color.toHex());
  722. this.picker.find('.colorpicker-color, .colorpicker-color div').css('backgroundColor', this.color.toString(this.format));
  723. return val;
  724. },
  725. updateComponent: function(val) {
  726. val = val ||  this.color.toString(this.format);
  727. if (this.component !== false) {
  728. var icn = this.component.find('i').eq(0);
  729. if (icn.length > 0) {
  730. icn.css({
  731. 'backgroundColor': val
  732. });
  733. } else {
  734. this.component.css({
  735. 'backgroundColor': val
  736. });
  737. }
  738. }
  739. return val;
  740. },
  741. update: function(force) {
  742. var val = this.updateComponent();
  743. if ((this.getValue(false) !== false) || (force === true)) {
  744. // Update input/data only if the current value is not blank
  745. this.updateInput(val);
  746. this.updateData(val);
  747. }
  748. this.updatePicker();
  749. return val;
  750. },
  751. setValue: function(val) { // set color manually
  752. this.color = new Color(val);
  753. this.update();
  754. this.element.trigger({
  755. type: 'changeColor',
  756. color: this.color,
  757. value: val
  758. });
  759. },
  760. getValue: function(defaultValue) {
  761. defaultValue = (defaultValue === undefined) ? '#000000' : defaultValue;
  762. var val;
  763. if (this.hasInput()) {
  764. val = this.input.val();
  765. } else {
  766. val = this.element.data('color');
  767. }
  768. if ((val === undefined) || (val === '') || (val === null)) {
  769. // if not defined or empty, return default
  770. val = defaultValue;
  771. }
  772. return val;
  773. },
  774. hasInput: function() {
  775. return (this.input !== false);
  776. },
  777. isDisabled: function() {
  778. if (this.hasInput()) {
  779. return (this.input.prop('disabled') === true);
  780. }
  781. return false;
  782. },
  783. disable: function() {
  784. if (this.hasInput()) {
  785. this.input.prop('disabled', true);
  786. return true;
  787. }
  788. return false;
  789. },
  790. enable: function() {
  791. if (this.hasInput()) {
  792. this.input.prop('disabled', false);
  793. return true;
  794. }
  795. return false;
  796. },
  797. currentSlider: null,
  798. mousePointer: {
  799. left: 0,
  800. top: 0
  801. },
  802. mousedown: function(e) {
  803. e.stopPropagation();
  804. e.preventDefault();
  805. var target = $(e.target);
  806. //detect the slider and set the limits and callbacks
  807. var zone = target.closest('div');
  808. var sl = this.options.horizontal ? this.options.slidersHorz : this.options.sliders;
  809. if (!zone.is('.colorpicker')) {
  810. if (zone.is('.colorpicker-saturation')) {
  811. this.currentSlider = $.extend({}, sl.saturation);
  812. } else if (zone.is('.colorpicker-hue')) {
  813. this.currentSlider = $.extend({}, sl.hue);
  814. } else if (zone.is('.colorpicker-alpha')) {
  815. this.currentSlider = $.extend({}, sl.alpha);
  816. } else {
  817. return false;
  818. }
  819. var offset = zone.offset();
  820. //reference to guide's style
  821. this.currentSlider.guide = zone.find('i')[0].style;
  822. this.currentSlider.left = e.pageX - offset.left;
  823. this.currentSlider.top = e.pageY - offset.top;
  824. this.mousePointer = {
  825. left: e.pageX,
  826. top: e.pageY
  827. };
  828. //trigger mousemove to move the guide to the current position
  829. $(document).on({
  830. 'mousemove.colorpicker': $.proxy(this.mousemove, this),
  831. 'mouseup.colorpicker': $.proxy(this.mouseup, this)
  832. }).trigger('mousemove');
  833. }
  834. return false;
  835. },
  836. mousemove: function(e) {
  837. e.stopPropagation();
  838. e.preventDefault();
  839. var left = Math.max(
  840. 0,
  841. Math.min(
  842. this.currentSlider.maxLeft,
  843. this.currentSlider.left + ((e.pageX || this.mousePointer.left) - this.mousePointer.left)
  844. )
  845. );
  846. var top = Math.max(
  847. 0,
  848. Math.min(
  849. this.currentSlider.maxTop,
  850. this.currentSlider.top + ((e.pageY || this.mousePointer.top) - this.mousePointer.top)
  851. )
  852. );
  853. this.currentSlider.guide.left = left + 'px';
  854. this.currentSlider.guide.top = top + 'px';
  855. if (this.currentSlider.callLeft) {
  856. this.color[this.currentSlider.callLeft].call(this.color, left / 100);
  857. }
  858. if (this.currentSlider.callTop) {
  859. this.color[this.currentSlider.callTop].call(this.color, top / 100);
  860. }
  861. this.update(true);
  862. this.element.trigger({
  863. type: 'changeColor',
  864. color: this.color
  865. });
  866. return false;
  867. },
  868. mouseup: function(e) {
  869. e.stopPropagation();
  870. e.preventDefault();
  871. $(document).off({
  872. 'mousemove.colorpicker': this.mousemove,
  873. 'mouseup.colorpicker': this.mouseup
  874. });
  875. return false;
  876. },
  877. keyup: function(e) {
  878. if ((e.keyCode === 38)) {
  879. if (this.color.value.a < 1) {
  880. this.color.value.a = Math.round((this.color.value.a + 0.01) * 100) / 100;
  881. }
  882. this.update(true);
  883. } else if ((e.keyCode === 40)) {
  884. if (this.color.value.a > 0) {
  885. this.color.value.a = Math.round((this.color.value.a - 0.01) * 100) / 100;
  886. }
  887. this.update(true);
  888. } else {
  889. var val = this.input.val();
  890. this.color = new Color(val);
  891. if (this.getValue(false) !== false) {
  892. this.updateData();
  893. this.updateComponent();
  894. this.updatePicker();
  895. }
  896. }
  897. this.element.trigger({
  898. type: 'changeColor',
  899. color: this.color,
  900. value: val
  901. });
  902. }
  903. };
  904. $.colorpicker = Colorpicker;
  905. $.fn.colorpicker = function(option) {
  906. return this.each(function() {
  907. var $this = $(this),
  908. inst = $this.data('colorpicker'),
  909. options = ((typeof option === 'object') ? option : {});
  910. if ((!inst) && (typeof option !== 'string')) {
  911. $this.data('colorpicker', new Colorpicker(this, options));
  912. } else {
  913. if (typeof option === 'string') {
  914. inst[option].apply(inst, Array.prototype.slice.call(arguments, 1));
  915. }
  916. }
  917. });
  918. };
  919. $.fn.colorpicker.constructor = Colorpicker;
  920. })(window.jQuery);