2f1cdd39414c3de1962fd781ae67ba81c2eb54b7a5028212a66b1a7cb1ecd2e99f405f38185fdd2ab0755e809b6676429b798e2756874afaa79d628ec40eab 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327
  1. /*!
  2. * Bootstrap Colorpicker v2.5.2
  3. * https://itsjavi.com/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. */
  10. (function(root, factory) {
  11. if (typeof define === 'function' && define.amd) {
  12. // AMD. Register as an anonymous module unless amdModuleId is set
  13. define(["jquery"], function(jq) {
  14. return (factory(jq));
  15. });
  16. } else if (typeof exports === 'object') {
  17. // Node. Does not work with strict CommonJS, but
  18. // only CommonJS-like environments that support module.exports,
  19. // like Node.
  20. module.exports = factory(require("jquery"));
  21. } else if (jQuery && !jQuery.fn.colorpicker) {
  22. factory(jQuery);
  23. }
  24. }(this, function($) {
  25. 'use strict';
  26. /**
  27. * Color manipulation helper class
  28. *
  29. * @param {Object|String} [val]
  30. * @param {Object} [predefinedColors]
  31. * @param {String|null} [fallbackColor]
  32. * @param {String|null} [fallbackFormat]
  33. * @param {Boolean} [hexNumberSignPrefix]
  34. * @constructor
  35. */
  36. var Color = function(
  37. val, predefinedColors, fallbackColor, fallbackFormat, hexNumberSignPrefix) {
  38. this.fallbackValue = fallbackColor ?
  39. (
  40. (typeof fallbackColor === 'string') ?
  41. this.parse(fallbackColor) :
  42. fallbackColor
  43. ) :
  44. null;
  45. this.fallbackFormat = fallbackFormat ? fallbackFormat : 'rgba';
  46. this.hexNumberSignPrefix = hexNumberSignPrefix === true;
  47. this.value = this.fallbackValue;
  48. this.origFormat = null; // original string format
  49. this.predefinedColors = predefinedColors ? predefinedColors : {};
  50. // We don't want to share aliases across instances so we extend new object
  51. this.colors = $.extend({}, Color.webColors, this.predefinedColors);
  52. if (val) {
  53. if (typeof val.h !== 'undefined') {
  54. this.value = val;
  55. } else {
  56. this.setColor(String(val));
  57. }
  58. }
  59. if (!this.value) {
  60. // Initial value is always black if no arguments are passed or val is empty
  61. this.value = {
  62. h: 0,
  63. s: 0,
  64. b: 0,
  65. a: 1
  66. };
  67. }
  68. };
  69. Color.webColors = { // 140 predefined colors from the HTML Colors spec
  70. "aliceblue": "f0f8ff",
  71. "antiquewhite": "faebd7",
  72. "aqua": "00ffff",
  73. "aquamarine": "7fffd4",
  74. "azure": "f0ffff",
  75. "beige": "f5f5dc",
  76. "bisque": "ffe4c4",
  77. "black": "000000",
  78. "blanchedalmond": "ffebcd",
  79. "blue": "0000ff",
  80. "blueviolet": "8a2be2",
  81. "brown": "a52a2a",
  82. "burlywood": "deb887",
  83. "cadetblue": "5f9ea0",
  84. "chartreuse": "7fff00",
  85. "chocolate": "d2691e",
  86. "coral": "ff7f50",
  87. "cornflowerblue": "6495ed",
  88. "cornsilk": "fff8dc",
  89. "crimson": "dc143c",
  90. "cyan": "00ffff",
  91. "darkblue": "00008b",
  92. "darkcyan": "008b8b",
  93. "darkgoldenrod": "b8860b",
  94. "darkgray": "a9a9a9",
  95. "darkgreen": "006400",
  96. "darkkhaki": "bdb76b",
  97. "darkmagenta": "8b008b",
  98. "darkolivegreen": "556b2f",
  99. "darkorange": "ff8c00",
  100. "darkorchid": "9932cc",
  101. "darkred": "8b0000",
  102. "darksalmon": "e9967a",
  103. "darkseagreen": "8fbc8f",
  104. "darkslateblue": "483d8b",
  105. "darkslategray": "2f4f4f",
  106. "darkturquoise": "00ced1",
  107. "darkviolet": "9400d3",
  108. "deeppink": "ff1493",
  109. "deepskyblue": "00bfff",
  110. "dimgray": "696969",
  111. "dodgerblue": "1e90ff",
  112. "firebrick": "b22222",
  113. "floralwhite": "fffaf0",
  114. "forestgreen": "228b22",
  115. "fuchsia": "ff00ff",
  116. "gainsboro": "dcdcdc",
  117. "ghostwhite": "f8f8ff",
  118. "gold": "ffd700",
  119. "goldenrod": "daa520",
  120. "gray": "808080",
  121. "green": "008000",
  122. "greenyellow": "adff2f",
  123. "honeydew": "f0fff0",
  124. "hotpink": "ff69b4",
  125. "indianred": "cd5c5c",
  126. "indigo": "4b0082",
  127. "ivory": "fffff0",
  128. "khaki": "f0e68c",
  129. "lavender": "e6e6fa",
  130. "lavenderblush": "fff0f5",
  131. "lawngreen": "7cfc00",
  132. "lemonchiffon": "fffacd",
  133. "lightblue": "add8e6",
  134. "lightcoral": "f08080",
  135. "lightcyan": "e0ffff",
  136. "lightgoldenrodyellow": "fafad2",
  137. "lightgrey": "d3d3d3",
  138. "lightgreen": "90ee90",
  139. "lightpink": "ffb6c1",
  140. "lightsalmon": "ffa07a",
  141. "lightseagreen": "20b2aa",
  142. "lightskyblue": "87cefa",
  143. "lightslategray": "778899",
  144. "lightsteelblue": "b0c4de",
  145. "lightyellow": "ffffe0",
  146. "lime": "00ff00",
  147. "limegreen": "32cd32",
  148. "linen": "faf0e6",
  149. "magenta": "ff00ff",
  150. "maroon": "800000",
  151. "mediumaquamarine": "66cdaa",
  152. "mediumblue": "0000cd",
  153. "mediumorchid": "ba55d3",
  154. "mediumpurple": "9370d8",
  155. "mediumseagreen": "3cb371",
  156. "mediumslateblue": "7b68ee",
  157. "mediumspringgreen": "00fa9a",
  158. "mediumturquoise": "48d1cc",
  159. "mediumvioletred": "c71585",
  160. "midnightblue": "191970",
  161. "mintcream": "f5fffa",
  162. "mistyrose": "ffe4e1",
  163. "moccasin": "ffe4b5",
  164. "navajowhite": "ffdead",
  165. "navy": "000080",
  166. "oldlace": "fdf5e6",
  167. "olive": "808000",
  168. "olivedrab": "6b8e23",
  169. "orange": "ffa500",
  170. "orangered": "ff4500",
  171. "orchid": "da70d6",
  172. "palegoldenrod": "eee8aa",
  173. "palegreen": "98fb98",
  174. "paleturquoise": "afeeee",
  175. "palevioletred": "d87093",
  176. "papayawhip": "ffefd5",
  177. "peachpuff": "ffdab9",
  178. "peru": "cd853f",
  179. "pink": "ffc0cb",
  180. "plum": "dda0dd",
  181. "powderblue": "b0e0e6",
  182. "purple": "800080",
  183. "red": "ff0000",
  184. "rosybrown": "bc8f8f",
  185. "royalblue": "4169e1",
  186. "saddlebrown": "8b4513",
  187. "salmon": "fa8072",
  188. "sandybrown": "f4a460",
  189. "seagreen": "2e8b57",
  190. "seashell": "fff5ee",
  191. "sienna": "a0522d",
  192. "silver": "c0c0c0",
  193. "skyblue": "87ceeb",
  194. "slateblue": "6a5acd",
  195. "slategray": "708090",
  196. "snow": "fffafa",
  197. "springgreen": "00ff7f",
  198. "steelblue": "4682b4",
  199. "tan": "d2b48c",
  200. "teal": "008080",
  201. "thistle": "d8bfd8",
  202. "tomato": "ff6347",
  203. "turquoise": "40e0d0",
  204. "violet": "ee82ee",
  205. "wheat": "f5deb3",
  206. "white": "ffffff",
  207. "whitesmoke": "f5f5f5",
  208. "yellow": "ffff00",
  209. "yellowgreen": "9acd32",
  210. "transparent": "transparent"
  211. };
  212. Color.prototype = {
  213. constructor: Color,
  214. colors: {}, // merged web and predefined colors
  215. predefinedColors: {},
  216. /**
  217. * @return {Object}
  218. */
  219. getValue: function() {
  220. return this.value;
  221. },
  222. /**
  223. * @param {Object} val
  224. */
  225. setValue: function(val) {
  226. this.value = val;
  227. },
  228. _sanitizeNumber: function(val) {
  229. if (typeof val === 'number') {
  230. return val;
  231. }
  232. if (isNaN(val) || (val === null) || (val === '') || (val === undefined)) {
  233. return 1;
  234. }
  235. if (val === '') {
  236. return 0;
  237. }
  238. if (typeof val.toLowerCase !== 'undefined') {
  239. if (val.match(/^\./)) {
  240. val = "0" + val;
  241. }
  242. return Math.ceil(parseFloat(val) * 100) / 100;
  243. }
  244. return 1;
  245. },
  246. isTransparent: function(strVal) {
  247. if (!strVal || !(typeof strVal === 'string' || strVal instanceof String)) {
  248. return false;
  249. }
  250. strVal = strVal.toLowerCase().trim();
  251. return (strVal === 'transparent') || (strVal.match(/#?00000000/)) || (strVal.match(/(rgba|hsla)\(0,0,0,0?\.?0\)/));
  252. },
  253. rgbaIsTransparent: function(rgba) {
  254. return ((rgba.r === 0) && (rgba.g === 0) && (rgba.b === 0) && (rgba.a === 0));
  255. },
  256. // parse a string to HSB
  257. /**
  258. * @protected
  259. * @param {String} strVal
  260. * @returns {boolean} Returns true if it could be parsed, false otherwise
  261. */
  262. setColor: function(strVal) {
  263. strVal = strVal.toLowerCase().trim();
  264. if (strVal) {
  265. if (this.isTransparent(strVal)) {
  266. this.value = {
  267. h: 0,
  268. s: 0,
  269. b: 0,
  270. a: 0
  271. };
  272. return true;
  273. } else {
  274. var parsedColor = this.parse(strVal);
  275. if (parsedColor) {
  276. this.value = this.value = {
  277. h: parsedColor.h,
  278. s: parsedColor.s,
  279. b: parsedColor.b,
  280. a: parsedColor.a
  281. };
  282. if (!this.origFormat) {
  283. this.origFormat = parsedColor.format;
  284. }
  285. } else if (this.fallbackValue) {
  286. // if parser fails, defaults to fallbackValue if defined, otherwise the value won't be changed
  287. this.value = this.fallbackValue;
  288. }
  289. }
  290. }
  291. return false;
  292. },
  293. setHue: function(h) {
  294. this.value.h = 1 - h;
  295. },
  296. setSaturation: function(s) {
  297. this.value.s = s;
  298. },
  299. setBrightness: function(b) {
  300. this.value.b = 1 - b;
  301. },
  302. setAlpha: function(a) {
  303. this.value.a = Math.round((parseInt((1 - a) * 100, 10) / 100) * 100) / 100;
  304. },
  305. toRGB: function(h, s, b, a) {
  306. if (arguments.length === 0) {
  307. h = this.value.h;
  308. s = this.value.s;
  309. b = this.value.b;
  310. a = this.value.a;
  311. }
  312. h *= 360;
  313. var R, G, B, X, C;
  314. h = (h % 360) / 60;
  315. C = b * s;
  316. X = C * (1 - Math.abs(h % 2 - 1));
  317. R = G = B = b - C;
  318. h = ~~h;
  319. R += [C, X, 0, 0, X, C][h];
  320. G += [X, C, C, X, 0, 0][h];
  321. B += [0, 0, X, C, C, X][h];
  322. return {
  323. r: Math.round(R * 255),
  324. g: Math.round(G * 255),
  325. b: Math.round(B * 255),
  326. a: a
  327. };
  328. },
  329. toHex: function(ignoreFormat, h, s, b, a) {
  330. if (arguments.length <= 1) {
  331. h = this.value.h;
  332. s = this.value.s;
  333. b = this.value.b;
  334. a = this.value.a;
  335. }
  336. var prefix = '#';
  337. var rgb = this.toRGB(h, s, b, a);
  338. if (this.rgbaIsTransparent(rgb)) {
  339. return 'transparent';
  340. }
  341. if (!ignoreFormat) {
  342. prefix = (this.hexNumberSignPrefix ? '#' : '');
  343. }
  344. var hexStr = prefix + (
  345. (1 << 24) +
  346. (parseInt(rgb.r) << 16) +
  347. (parseInt(rgb.g) << 8) +
  348. parseInt(rgb.b))
  349. .toString(16)
  350. .slice(1);
  351. return hexStr;
  352. },
  353. toHSL: function(h, s, b, a) {
  354. if (arguments.length === 0) {
  355. h = this.value.h;
  356. s = this.value.s;
  357. b = this.value.b;
  358. a = this.value.a;
  359. }
  360. var H = h,
  361. L = (2 - s) * b,
  362. S = s * b;
  363. if (L > 0 && L <= 1) {
  364. S /= L;
  365. } else {
  366. S /= 2 - L;
  367. }
  368. L /= 2;
  369. if (S > 1) {
  370. S = 1;
  371. }
  372. return {
  373. h: isNaN(H) ? 0 : H,
  374. s: isNaN(S) ? 0 : S,
  375. l: isNaN(L) ? 0 : L,
  376. a: isNaN(a) ? 0 : a
  377. };
  378. },
  379. toAlias: function(r, g, b, a) {
  380. var c, rgb = (arguments.length === 0) ? this.toHex(true) : this.toHex(true, r, g, b, a);
  381. // support predef. colors in non-hex format too, as defined in the alias itself
  382. var original = this.origFormat === 'alias' ? rgb : this.toString(false, this.origFormat);
  383. for (var alias in this.colors) {
  384. c = this.colors[alias].toLowerCase().trim();
  385. if ((c === rgb) || (c === original)) {
  386. return alias;
  387. }
  388. }
  389. return false;
  390. },
  391. RGBtoHSB: function(r, g, b, a) {
  392. r /= 255;
  393. g /= 255;
  394. b /= 255;
  395. var H, S, V, C;
  396. V = Math.max(r, g, b);
  397. C = V - Math.min(r, g, b);
  398. H = (C === 0 ? null :
  399. V === r ? (g - b) / C :
  400. V === g ? (b - r) / C + 2 :
  401. (r - g) / C + 4
  402. );
  403. H = ((H + 360) % 6) * 60 / 360;
  404. S = C === 0 ? 0 : C / V;
  405. return {
  406. h: this._sanitizeNumber(H),
  407. s: S,
  408. b: V,
  409. a: this._sanitizeNumber(a)
  410. };
  411. },
  412. HueToRGB: function(p, q, h) {
  413. if (h < 0) {
  414. h += 1;
  415. } else if (h > 1) {
  416. h -= 1;
  417. }
  418. if ((h * 6) < 1) {
  419. return p + (q - p) * h * 6;
  420. } else if ((h * 2) < 1) {
  421. return q;
  422. } else if ((h * 3) < 2) {
  423. return p + (q - p) * ((2 / 3) - h) * 6;
  424. } else {
  425. return p;
  426. }
  427. },
  428. HSLtoRGB: function(h, s, l, a) {
  429. if (s < 0) {
  430. s = 0;
  431. }
  432. var q;
  433. if (l <= 0.5) {
  434. q = l * (1 + s);
  435. } else {
  436. q = l + s - (l * s);
  437. }
  438. var p = 2 * l - q;
  439. var tr = h + (1 / 3);
  440. var tg = h;
  441. var tb = h - (1 / 3);
  442. var r = Math.round(this.HueToRGB(p, q, tr) * 255);
  443. var g = Math.round(this.HueToRGB(p, q, tg) * 255);
  444. var b = Math.round(this.HueToRGB(p, q, tb) * 255);
  445. return [r, g, b, this._sanitizeNumber(a)];
  446. },
  447. /**
  448. * @param {String} strVal
  449. * @returns {Object} Object containing h,s,b,a,format properties or FALSE if failed to parse
  450. */
  451. parse: function(strVal) {
  452. if (typeof strVal !== 'string') {
  453. return this.fallbackValue;
  454. }
  455. if (arguments.length === 0) {
  456. return false;
  457. }
  458. var that = this,
  459. result = false,
  460. isAlias = (typeof this.colors[strVal] !== 'undefined'),
  461. values, format;
  462. if (isAlias) {
  463. strVal = this.colors[strVal].toLowerCase().trim();
  464. }
  465. $.each(this.stringParsers, function(i, parser) {
  466. var match = parser.re.exec(strVal);
  467. values = match && parser.parse.apply(that, [match]);
  468. if (values) {
  469. result = {};
  470. format = (isAlias ? 'alias' : (parser.format ? parser.format : that.getValidFallbackFormat()));
  471. if (format.match(/hsla?/)) {
  472. result = that.RGBtoHSB.apply(that, that.HSLtoRGB.apply(that, values));
  473. } else {
  474. result = that.RGBtoHSB.apply(that, values);
  475. }
  476. if (result instanceof Object) {
  477. result.format = format;
  478. }
  479. return false; // stop iterating
  480. }
  481. return true;
  482. });
  483. return result;
  484. },
  485. getValidFallbackFormat: function() {
  486. var formats = [
  487. 'rgba', 'rgb', 'hex', 'hsla', 'hsl'
  488. ];
  489. if (this.origFormat && (formats.indexOf(this.origFormat) !== -1)) {
  490. return this.origFormat;
  491. }
  492. if (this.fallbackFormat && (formats.indexOf(this.fallbackFormat) !== -1)) {
  493. return this.fallbackFormat;
  494. }
  495. return 'rgba'; // By default, return a format that will not lose the alpha info
  496. },
  497. /**
  498. *
  499. * @param {string} [format] (default: rgba)
  500. * @param {boolean} [translateAlias] Return real color for pre-defined (non-standard) aliases (default: false)
  501. * @param {boolean} [forceRawValue] Forces hashtag prefix when getting hex color (default: false)
  502. * @returns {String}
  503. */
  504. toString: function(forceRawValue, format, translateAlias) {
  505. format = format || this.origFormat || this.fallbackFormat;
  506. translateAlias = translateAlias || false;
  507. var c = false;
  508. switch (format) {
  509. case 'rgb':
  510. {
  511. c = this.toRGB();
  512. if (this.rgbaIsTransparent(c)) {
  513. return 'transparent';
  514. }
  515. return 'rgb(' + c.r + ',' + c.g + ',' + c.b + ')';
  516. }
  517. break;
  518. case 'rgba':
  519. {
  520. c = this.toRGB();
  521. return 'rgba(' + c.r + ',' + c.g + ',' + c.b + ',' + c.a + ')';
  522. }
  523. break;
  524. case 'hsl':
  525. {
  526. c = this.toHSL();
  527. return 'hsl(' + Math.round(c.h * 360) + ',' + Math.round(c.s * 100) + '%,' + Math.round(c.l * 100) + '%)';
  528. }
  529. break;
  530. case 'hsla':
  531. {
  532. c = this.toHSL();
  533. return 'hsla(' + Math.round(c.h * 360) + ',' + Math.round(c.s * 100) + '%,' + Math.round(c.l * 100) + '%,' + c.a + ')';
  534. }
  535. break;
  536. case 'hex':
  537. {
  538. return this.toHex(forceRawValue);
  539. }
  540. break;
  541. case 'alias':
  542. {
  543. c = this.toAlias();
  544. if (c === false) {
  545. return this.toString(forceRawValue, this.getValidFallbackFormat());
  546. }
  547. if (translateAlias && !(c in Color.webColors) && (c in this.predefinedColors)) {
  548. return this.predefinedColors[c];
  549. }
  550. return c;
  551. }
  552. default:
  553. {
  554. return c;
  555. }
  556. break;
  557. }
  558. },
  559. // a set of RE's that can match strings and generate color tuples.
  560. // from John Resig color plugin
  561. // https://github.com/jquery/jquery-color/
  562. stringParsers: [{
  563. re: /rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*?\)/,
  564. format: 'rgb',
  565. parse: function(execResult) {
  566. return [
  567. execResult[1],
  568. execResult[2],
  569. execResult[3],
  570. 1
  571. ];
  572. }
  573. }, {
  574. re: /rgb\(\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*?\)/,
  575. format: 'rgb',
  576. parse: function(execResult) {
  577. return [
  578. 2.55 * execResult[1],
  579. 2.55 * execResult[2],
  580. 2.55 * execResult[3],
  581. 1
  582. ];
  583. }
  584. }, {
  585. re: /rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d*(?:\.\d+)?)\s*)?\)/,
  586. format: 'rgba',
  587. parse: function(execResult) {
  588. return [
  589. execResult[1],
  590. execResult[2],
  591. execResult[3],
  592. execResult[4]
  593. ];
  594. }
  595. }, {
  596. re: /rgba\(\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*(?:,\s*(\d*(?:\.\d+)?)\s*)?\)/,
  597. format: 'rgba',
  598. parse: function(execResult) {
  599. return [
  600. 2.55 * execResult[1],
  601. 2.55 * execResult[2],
  602. 2.55 * execResult[3],
  603. execResult[4]
  604. ];
  605. }
  606. }, {
  607. re: /hsl\(\s*(\d*(?:\.\d+)?)\s*,\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*?\)/,
  608. format: 'hsl',
  609. parse: function(execResult) {
  610. return [
  611. execResult[1] / 360,
  612. execResult[2] / 100,
  613. execResult[3] / 100,
  614. execResult[4]
  615. ];
  616. }
  617. }, {
  618. re: /hsla\(\s*(\d*(?:\.\d+)?)\s*,\s*(\d*(?:\.\d+)?)\%\s*,\s*(\d*(?:\.\d+)?)\%\s*(?:,\s*(\d*(?:\.\d+)?)\s*)?\)/,
  619. format: 'hsla',
  620. parse: function(execResult) {
  621. return [
  622. execResult[1] / 360,
  623. execResult[2] / 100,
  624. execResult[3] / 100,
  625. execResult[4]
  626. ];
  627. }
  628. }, {
  629. re: /#?([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/,
  630. format: 'hex',
  631. parse: function(execResult) {
  632. return [
  633. parseInt(execResult[1], 16),
  634. parseInt(execResult[2], 16),
  635. parseInt(execResult[3], 16),
  636. 1
  637. ];
  638. }
  639. }, {
  640. re: /#?([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/,
  641. format: 'hex',
  642. parse: function(execResult) {
  643. return [
  644. parseInt(execResult[1] + execResult[1], 16),
  645. parseInt(execResult[2] + execResult[2], 16),
  646. parseInt(execResult[3] + execResult[3], 16),
  647. 1
  648. ];
  649. }
  650. }],
  651. colorNameToHex: function(name) {
  652. if (typeof this.colors[name.toLowerCase()] !== 'undefined') {
  653. return this.colors[name.toLowerCase()];
  654. }
  655. return false;
  656. }
  657. };
  658. /*
  659. * Default plugin options
  660. */
  661. var defaults = {
  662. horizontal: false, // horizontal mode layout ?
  663. inline: false, //forces to show the colorpicker as an inline element
  664. color: false, //forces a color
  665. format: false, //forces a format
  666. input: 'input', // children input selector
  667. container: false, // container selector
  668. component: '.add-on, .input-group-addon', // children component selector
  669. fallbackColor: false, // fallback color value. null = keeps current color.
  670. fallbackFormat: 'hex', // fallback color format
  671. hexNumberSignPrefix: true, // put a '#' (number sign) before hex strings
  672. sliders: {
  673. saturation: {
  674. maxLeft: 100,
  675. maxTop: 100,
  676. callLeft: 'setSaturation',
  677. callTop: 'setBrightness'
  678. },
  679. hue: {
  680. maxLeft: 0,
  681. maxTop: 100,
  682. callLeft: false,
  683. callTop: 'setHue'
  684. },
  685. alpha: {
  686. maxLeft: 0,
  687. maxTop: 100,
  688. callLeft: false,
  689. callTop: 'setAlpha'
  690. }
  691. },
  692. slidersHorz: {
  693. saturation: {
  694. maxLeft: 100,
  695. maxTop: 100,
  696. callLeft: 'setSaturation',
  697. callTop: 'setBrightness'
  698. },
  699. hue: {
  700. maxLeft: 100,
  701. maxTop: 0,
  702. callLeft: 'setHue',
  703. callTop: false
  704. },
  705. alpha: {
  706. maxLeft: 100,
  707. maxTop: 0,
  708. callLeft: 'setAlpha',
  709. callTop: false
  710. }
  711. },
  712. template: '<div class="colorpicker dropdown-menu">' +
  713. '<div class="colorpicker-saturation"><i><b></b></i></div>' +
  714. '<div class="colorpicker-hue"><i></i></div>' +
  715. '<div class="colorpicker-alpha"><i></i></div>' +
  716. '<div class="colorpicker-color"><div /></div>' +
  717. '<div class="colorpicker-selectors"></div>' +
  718. '</div>',
  719. align: 'right',
  720. customClass: null, // custom class added to the colorpicker element
  721. colorSelectors: null // custom color aliases
  722. };
  723. /**
  724. * Colorpicker component class
  725. *
  726. * @param {Object|String} element
  727. * @param {Object} options
  728. * @constructor
  729. */
  730. var Colorpicker = function(element, options) {
  731. this.element = $(element).addClass('colorpicker-element');
  732. this.options = $.extend(true, {}, defaults, this.element.data(), options);
  733. this.component = this.options.component;
  734. this.component = (this.component !== false) ? this.element.find(this.component) : false;
  735. if (this.component && (this.component.length === 0)) {
  736. this.component = false;
  737. }
  738. this.container = (this.options.container === true) ? this.element : this.options.container;
  739. this.container = (this.container !== false) ? $(this.container) : false;
  740. // Is the element an input? Should we search inside for any input?
  741. this.input = this.element.is('input') ? this.element : (this.options.input ?
  742. this.element.find(this.options.input) : false);
  743. if (this.input && (this.input.length === 0)) {
  744. this.input = false;
  745. }
  746. // Set HSB color
  747. this.color = this.createColor(this.options.color !== false ? this.options.color : this.getValue());
  748. this.format = this.options.format !== false ? this.options.format : this.color.origFormat;
  749. if (this.options.color !== false) {
  750. this.updateInput(this.color);
  751. this.updateData(this.color);
  752. }
  753. this.disabled = false;
  754. // Setup picker
  755. var $picker = this.picker = $(this.options.template);
  756. if (this.options.customClass) {
  757. $picker.addClass(this.options.customClass);
  758. }
  759. if (this.options.inline) {
  760. $picker.addClass('colorpicker-inline colorpicker-visible');
  761. } else {
  762. $picker.addClass('colorpicker-hidden');
  763. }
  764. if (this.options.horizontal) {
  765. $picker.addClass('colorpicker-horizontal');
  766. }
  767. if (
  768. (['rgba', 'hsla', 'alias'].indexOf(this.format) !== -1) ||
  769. this.options.format === false ||
  770. this.getValue() === 'transparent'
  771. ) {
  772. $picker.addClass('colorpicker-with-alpha');
  773. }
  774. if (this.options.align === 'right') {
  775. $picker.addClass('colorpicker-right');
  776. }
  777. if (this.options.inline === true) {
  778. $picker.addClass('colorpicker-no-arrow');
  779. }
  780. if (this.options.colorSelectors) {
  781. var colorpicker = this,
  782. selectorsContainer = colorpicker.picker.find('.colorpicker-selectors');
  783. if (selectorsContainer.length > 0) {
  784. $.each(this.options.colorSelectors, function(name, color) {
  785. var $btn = $('<i />')
  786. .addClass('colorpicker-selectors-color')
  787. .css('background-color', color)
  788. .data('class', name).data('alias', name);
  789. $btn.on('mousedown.colorpicker touchstart.colorpicker', function(event) {
  790. event.preventDefault();
  791. colorpicker.setValue(
  792. colorpicker.format === 'alias' ? $(this).data('alias') : $(this).css('background-color')
  793. );
  794. });
  795. selectorsContainer.append($btn);
  796. });
  797. selectorsContainer.show().addClass('colorpicker-visible');
  798. }
  799. }
  800. // Prevent closing the colorpicker when clicking on itself
  801. $picker.on('mousedown.colorpicker touchstart.colorpicker', $.proxy(function(e) {
  802. if (e.target === e.currentTarget) {
  803. e.preventDefault();
  804. }
  805. }, this));
  806. // Bind click/tap events on the sliders
  807. $picker.find('.colorpicker-saturation, .colorpicker-hue, .colorpicker-alpha')
  808. .on('mousedown.colorpicker touchstart.colorpicker', $.proxy(this.mousedown, this));
  809. $picker.appendTo(this.container ? this.container : $('body'));
  810. // Bind other events
  811. if (this.input !== false) {
  812. this.input.on({
  813. 'keyup.colorpicker': $.proxy(this.keyup, this)
  814. });
  815. this.input.on({
  816. 'input.colorpicker': $.proxy(this.change, this)
  817. });
  818. if (this.component === false) {
  819. this.element.on({
  820. 'focus.colorpicker': $.proxy(this.show, this)
  821. });
  822. }
  823. if (this.options.inline === false) {
  824. this.element.on({
  825. 'focusout.colorpicker': $.proxy(this.hide, this)
  826. });
  827. }
  828. }
  829. if (this.component !== false) {
  830. this.component.on({
  831. 'click.colorpicker': $.proxy(this.show, this)
  832. });
  833. }
  834. if ((this.input === false) && (this.component === false)) {
  835. this.element.on({
  836. 'click.colorpicker': $.proxy(this.show, this)
  837. });
  838. }
  839. // for HTML5 input[type='color']
  840. if ((this.input !== false) && (this.component !== false) && (this.input.attr('type') === 'color')) {
  841. this.input.on({
  842. 'click.colorpicker': $.proxy(this.show, this),
  843. 'focus.colorpicker': $.proxy(this.show, this)
  844. });
  845. }
  846. this.update();
  847. $($.proxy(function() {
  848. this.element.trigger('create');
  849. }, this));
  850. };
  851. Colorpicker.Color = Color;
  852. Colorpicker.prototype = {
  853. constructor: Colorpicker,
  854. destroy: function() {
  855. this.picker.remove();
  856. this.element.removeData('colorpicker', 'color').off('.colorpicker');
  857. if (this.input !== false) {
  858. this.input.off('.colorpicker');
  859. }
  860. if (this.component !== false) {
  861. this.component.off('.colorpicker');
  862. }
  863. this.element.removeClass('colorpicker-element');
  864. this.element.trigger({
  865. type: 'destroy'
  866. });
  867. },
  868. reposition: function() {
  869. if (this.options.inline !== false || this.options.container) {
  870. return false;
  871. }
  872. var type = this.container && this.container[0] !== window.document.body ? 'position' : 'offset';
  873. var element = this.component || this.element;
  874. var offset = element[type]();
  875. if (this.options.align === 'right') {
  876. offset.left -= this.picker.outerWidth() - element.outerWidth();
  877. }
  878. this.picker.css({
  879. top: offset.top + element.outerHeight(),
  880. left: offset.left
  881. });
  882. },
  883. show: function(e) {
  884. if (this.isDisabled()) {
  885. // Don't show the widget if it's disabled (the input)
  886. return;
  887. }
  888. this.picker.addClass('colorpicker-visible').removeClass('colorpicker-hidden');
  889. this.reposition();
  890. $(window).on('resize.colorpicker', $.proxy(this.reposition, this));
  891. if (e && (!this.hasInput() || this.input.attr('type') === 'color')) {
  892. if (e.stopPropagation && e.preventDefault) {
  893. e.stopPropagation();
  894. e.preventDefault();
  895. }
  896. }
  897. if ((this.component || !this.input) && (this.options.inline === false)) {
  898. $(window.document).on({
  899. 'mousedown.colorpicker': $.proxy(this.hide, this)
  900. });
  901. }
  902. this.element.trigger({
  903. type: 'showPicker',
  904. color: this.color
  905. });
  906. },
  907. hide: function(e) {
  908. if ((typeof e !== 'undefined') && e.target) {
  909. // Prevent hide if triggered by an event and an element inside the colorpicker has been clicked/touched
  910. if (
  911. $(e.currentTarget).parents('.colorpicker').length > 0 ||
  912. $(e.target).parents('.colorpicker').length > 0
  913. ) {
  914. return false;
  915. }
  916. }
  917. this.picker.addClass('colorpicker-hidden').removeClass('colorpicker-visible');
  918. $(window).off('resize.colorpicker', this.reposition);
  919. $(window.document).off({
  920. 'mousedown.colorpicker': this.hide
  921. });
  922. this.update();
  923. this.element.trigger({
  924. type: 'hidePicker',
  925. color: this.color
  926. });
  927. },
  928. updateData: function(val) {
  929. val = val || this.color.toString(false, this.format);
  930. this.element.data('color', val);
  931. return val;
  932. },
  933. updateInput: function(val) {
  934. val = val || this.color.toString(false, this.format);
  935. if (this.input !== false) {
  936. this.input.prop('value', val);
  937. this.input.trigger('change');
  938. }
  939. return val;
  940. },
  941. updatePicker: function(val) {
  942. if (typeof val !== 'undefined') {
  943. this.color = this.createColor(val);
  944. }
  945. var sl = (this.options.horizontal === false) ? this.options.sliders : this.options.slidersHorz;
  946. var icns = this.picker.find('i');
  947. if (icns.length === 0) {
  948. return;
  949. }
  950. if (this.options.horizontal === false) {
  951. sl = this.options.sliders;
  952. icns.eq(1).css('top', sl.hue.maxTop * (1 - this.color.value.h)).end()
  953. .eq(2).css('top', sl.alpha.maxTop * (1 - this.color.value.a));
  954. } else {
  955. sl = this.options.slidersHorz;
  956. icns.eq(1).css('left', sl.hue.maxLeft * (1 - this.color.value.h)).end()
  957. .eq(2).css('left', sl.alpha.maxLeft * (1 - this.color.value.a));
  958. }
  959. icns.eq(0).css({
  960. 'top': sl.saturation.maxTop - this.color.value.b * sl.saturation.maxTop,
  961. 'left': this.color.value.s * sl.saturation.maxLeft
  962. });
  963. this.picker.find('.colorpicker-saturation')
  964. .css('backgroundColor', this.color.toHex(true, this.color.value.h, 1, 1, 1));
  965. this.picker.find('.colorpicker-alpha')
  966. .css('backgroundColor', this.color.toHex(true));
  967. this.picker.find('.colorpicker-color, .colorpicker-color div')
  968. .css('backgroundColor', this.color.toString(true, this.format));
  969. return val;
  970. },
  971. updateComponent: function(val) {
  972. var color;
  973. if (typeof val !== 'undefined') {
  974. color = this.createColor(val);
  975. } else {
  976. color = this.color;
  977. }
  978. if (this.component !== false) {
  979. var icn = this.component.find('i').eq(0);
  980. if (icn.length > 0) {
  981. icn.css({
  982. 'backgroundColor': color.toString(true, this.format)
  983. });
  984. } else {
  985. this.component.css({
  986. 'backgroundColor': color.toString(true, this.format)
  987. });
  988. }
  989. }
  990. return color.toString(false, this.format);
  991. },
  992. update: function(force) {
  993. var val;
  994. if ((this.getValue(false) !== false) || (force === true)) {
  995. // Update input/data only if the current value is not empty
  996. val = this.updateComponent();
  997. this.updateInput(val);
  998. this.updateData(val);
  999. this.updatePicker(); // only update picker if value is not empty
  1000. }
  1001. return val;
  1002. },
  1003. setValue: function(val) { // set color manually
  1004. this.color = this.createColor(val);
  1005. this.update(true);
  1006. this.element.trigger({
  1007. type: 'changeColor',
  1008. color: this.color,
  1009. value: val
  1010. });
  1011. },
  1012. /**
  1013. * Creates a new color using the instance options
  1014. * @protected
  1015. * @param {String} val
  1016. * @returns {Color}
  1017. */
  1018. createColor: function(val) {
  1019. return new Color(
  1020. val ? val : null,
  1021. this.options.colorSelectors,
  1022. this.options.fallbackColor ? this.options.fallbackColor : this.color,
  1023. this.options.fallbackFormat,
  1024. this.options.hexNumberSignPrefix
  1025. );
  1026. },
  1027. getValue: function(defaultValue) {
  1028. defaultValue = (typeof defaultValue === 'undefined') ? this.options.fallbackColor : defaultValue;
  1029. var val;
  1030. if (this.hasInput()) {
  1031. val = this.input.val();
  1032. } else {
  1033. val = this.element.data('color');
  1034. }
  1035. if ((val === undefined) || (val === '') || (val === null)) {
  1036. // if not defined or empty, return default
  1037. val = defaultValue;
  1038. }
  1039. return val;
  1040. },
  1041. hasInput: function() {
  1042. return (this.input !== false);
  1043. },
  1044. isDisabled: function() {
  1045. return this.disabled;
  1046. },
  1047. disable: function() {
  1048. if (this.hasInput()) {
  1049. this.input.prop('disabled', true);
  1050. }
  1051. this.disabled = true;
  1052. this.element.trigger({
  1053. type: 'disable',
  1054. color: this.color,
  1055. value: this.getValue()
  1056. });
  1057. return true;
  1058. },
  1059. enable: function() {
  1060. if (this.hasInput()) {
  1061. this.input.prop('disabled', false);
  1062. }
  1063. this.disabled = false;
  1064. this.element.trigger({
  1065. type: 'enable',
  1066. color: this.color,
  1067. value: this.getValue()
  1068. });
  1069. return true;
  1070. },
  1071. currentSlider: null,
  1072. mousePointer: {
  1073. left: 0,
  1074. top: 0
  1075. },
  1076. mousedown: function(e) {
  1077. if (!e.pageX && !e.pageY && e.originalEvent && e.originalEvent.touches) {
  1078. e.pageX = e.originalEvent.touches[0].pageX;
  1079. e.pageY = e.originalEvent.touches[0].pageY;
  1080. }
  1081. e.stopPropagation();
  1082. e.preventDefault();
  1083. var target = $(e.target);
  1084. //detect the slider and set the limits and callbacks
  1085. var zone = target.closest('div');
  1086. var sl = this.options.horizontal ? this.options.slidersHorz : this.options.sliders;
  1087. if (!zone.is('.colorpicker')) {
  1088. if (zone.is('.colorpicker-saturation')) {
  1089. this.currentSlider = $.extend({}, sl.saturation);
  1090. } else if (zone.is('.colorpicker-hue')) {
  1091. this.currentSlider = $.extend({}, sl.hue);
  1092. } else if (zone.is('.colorpicker-alpha')) {
  1093. this.currentSlider = $.extend({}, sl.alpha);
  1094. } else {
  1095. return false;
  1096. }
  1097. var offset = zone.offset();
  1098. //reference to guide's style
  1099. this.currentSlider.guide = zone.find('i')[0].style;
  1100. this.currentSlider.left = e.pageX - offset.left;
  1101. this.currentSlider.top = e.pageY - offset.top;
  1102. this.mousePointer = {
  1103. left: e.pageX,
  1104. top: e.pageY
  1105. };
  1106. //trigger mousemove to move the guide to the current position
  1107. $(window.document).on({
  1108. 'mousemove.colorpicker': $.proxy(this.mousemove, this),
  1109. 'touchmove.colorpicker': $.proxy(this.mousemove, this),
  1110. 'mouseup.colorpicker': $.proxy(this.mouseup, this),
  1111. 'touchend.colorpicker': $.proxy(this.mouseup, this)
  1112. }).trigger('mousemove');
  1113. }
  1114. return false;
  1115. },
  1116. mousemove: function(e) {
  1117. if (!e.pageX && !e.pageY && e.originalEvent && e.originalEvent.touches) {
  1118. e.pageX = e.originalEvent.touches[0].pageX;
  1119. e.pageY = e.originalEvent.touches[0].pageY;
  1120. }
  1121. e.stopPropagation();
  1122. e.preventDefault();
  1123. var left = Math.max(
  1124. 0,
  1125. Math.min(
  1126. this.currentSlider.maxLeft,
  1127. this.currentSlider.left + ((e.pageX || this.mousePointer.left) - this.mousePointer.left)
  1128. )
  1129. );
  1130. var top = Math.max(
  1131. 0,
  1132. Math.min(
  1133. this.currentSlider.maxTop,
  1134. this.currentSlider.top + ((e.pageY || this.mousePointer.top) - this.mousePointer.top)
  1135. )
  1136. );
  1137. this.currentSlider.guide.left = left + 'px';
  1138. this.currentSlider.guide.top = top + 'px';
  1139. if (this.currentSlider.callLeft) {
  1140. this.color[this.currentSlider.callLeft].call(this.color, left / this.currentSlider.maxLeft);
  1141. }
  1142. if (this.currentSlider.callTop) {
  1143. this.color[this.currentSlider.callTop].call(this.color, top / this.currentSlider.maxTop);
  1144. }
  1145. // Change format dynamically
  1146. // Only occurs if user choose the dynamic format by
  1147. // setting option format to false
  1148. if (
  1149. this.options.format === false &&
  1150. (this.currentSlider.callTop === 'setAlpha' ||
  1151. this.currentSlider.callLeft === 'setAlpha')
  1152. ) {
  1153. // Converting from hex / rgb to rgba
  1154. if (this.color.value.a !== 1) {
  1155. this.format = 'rgba';
  1156. this.color.origFormat = 'rgba';
  1157. }
  1158. // Converting from rgba to hex
  1159. else {
  1160. this.format = 'hex';
  1161. this.color.origFormat = 'hex';
  1162. }
  1163. }
  1164. this.update(true);
  1165. this.element.trigger({
  1166. type: 'changeColor',
  1167. color: this.color
  1168. });
  1169. return false;
  1170. },
  1171. mouseup: function(e) {
  1172. e.stopPropagation();
  1173. e.preventDefault();
  1174. $(window.document).off({
  1175. 'mousemove.colorpicker': this.mousemove,
  1176. 'touchmove.colorpicker': this.mousemove,
  1177. 'mouseup.colorpicker': this.mouseup,
  1178. 'touchend.colorpicker': this.mouseup
  1179. });
  1180. return false;
  1181. },
  1182. change: function(e) {
  1183. this.color = this.createColor(this.input.val());
  1184. // Change format dynamically
  1185. // Only occurs if user choose the dynamic format by
  1186. // setting option format to false
  1187. if (this.color.origFormat && this.options.format === false) {
  1188. this.format = this.color.origFormat;
  1189. }
  1190. if (this.getValue(false) !== false) {
  1191. this.updateData();
  1192. this.updateComponent();
  1193. this.updatePicker();
  1194. }
  1195. this.element.trigger({
  1196. type: 'changeColor',
  1197. color: this.color,
  1198. value: this.input.val()
  1199. });
  1200. },
  1201. keyup: function(e) {
  1202. if ((e.keyCode === 38)) {
  1203. if (this.color.value.a < 1) {
  1204. this.color.value.a = Math.round((this.color.value.a + 0.01) * 100) / 100;
  1205. }
  1206. this.update(true);
  1207. } else if ((e.keyCode === 40)) {
  1208. if (this.color.value.a > 0) {
  1209. this.color.value.a = Math.round((this.color.value.a - 0.01) * 100) / 100;
  1210. }
  1211. this.update(true);
  1212. }
  1213. this.element.trigger({
  1214. type: 'changeColor',
  1215. color: this.color,
  1216. value: this.input.val()
  1217. });
  1218. }
  1219. };
  1220. $.colorpicker = Colorpicker;
  1221. $.fn.colorpicker = function(option) {
  1222. var apiArgs = Array.prototype.slice.call(arguments, 1),
  1223. isSingleElement = (this.length === 1),
  1224. returnValue = null;
  1225. var $jq = this.each(function() {
  1226. var $this = $(this),
  1227. inst = $this.data('colorpicker'),
  1228. options = ((typeof option === 'object') ? option : {});
  1229. if (!inst) {
  1230. inst = new Colorpicker(this, options);
  1231. $this.data('colorpicker', inst);
  1232. }
  1233. if (typeof option === 'string') {
  1234. if ($.isFunction(inst[option])) {
  1235. returnValue = inst[option].apply(inst, apiArgs);
  1236. } else { // its a property ?
  1237. if (apiArgs.length) {
  1238. // set property
  1239. inst[option] = apiArgs[0];
  1240. }
  1241. returnValue = inst[option];
  1242. }
  1243. } else {
  1244. returnValue = $this;
  1245. }
  1246. });
  1247. return isSingleElement ? returnValue : $jq;
  1248. };
  1249. $.fn.colorpicker.constructor = Colorpicker;
  1250. }));