├── .babelrc ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── assets ├── screenshot.png └── screenshot.psd ├── dev ├── app │ ├── app.html │ └── app.js └── public │ └── index.html ├── dist ├── ngjs-color-picker.js └── ngjs-color-picker.js.map ├── package.json ├── source └── ngjs-color-picker.js ├── test ├── directive.spec.js └── karma.conf.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # /node_modules/* and /bower_components/* ignored by default 2 | 3 | # Ignore built files except build/index.js 4 | dist/* 5 | dev/* 6 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "angular", 3 | "rules": { 4 | "array-bracket-spacing": [2, "never"], 5 | "camelcase": 2, 6 | "comma-dangle": [2, "never"], 7 | "comma-spacing": [2, { "before": false, "after": true }], 8 | "comma-style": [2, "last"], 9 | "computed-property-spacing": [2, "never"], 10 | "default-case": 2, 11 | "dot-notation": 2, 12 | "eol-last": [2, "always"], 13 | "eqeqeq": [2, "always"], 14 | "func-call-spacing": [2, "never"], 15 | "indent": [2, 4], 16 | "key-spacing": [2, { "beforeColon": false }], 17 | "keyword-spacing": [2, { "before": true }], 18 | "linebreak-style": [2, "unix"], 19 | "max-len": [2, 100], 20 | "no-debugger": 2, 21 | "no-else-return": 2, 22 | "no-extra-semi": 2, 23 | "no-fallthrough": 2, 24 | "no-lonely-if": 2, 25 | "no-multiple-empty-lines": [2, {"max": 2, "maxEOF": 1}], 26 | "no-restricted-globals": [2, "event"], 27 | "no-trailing-spaces": 2, 28 | "no-unreachable": 2, 29 | "no-unused-vars": 2, 30 | "quotes": [2, "single"], 31 | "radix": 2, 32 | "semi": [2, "always"], 33 | "semi-spacing": [2, { "before": false, "after": true }], 34 | "strict": [2, "global"], 35 | "use-isnan": 2 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ 3 | .DS_Store 4 | .DS_Store? 5 | ._* 6 | .Spotlight-V100 7 | .Trashes 8 | ehthumbs.db 9 | Thumbs.db 10 | .idea 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | os: 3 | - linux 4 | - windows 5 | node_js: 6 | - "stable" 7 | - "6" 8 | sudo: false 9 | before_script: 10 | - npm install -g jasmine-node codecov istanbul 11 | script: 12 | - npm run lint 13 | - npm run test 14 | - istanbul cover node_modules/jasmine/bin/jasmine.js 15 | - codecov 16 | cache: 17 | directories: 18 | - node_modules 19 | after_success: 20 | - bash <(curl -s https://codecov.io/bash) 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Simon Egersand 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ngjs-color-picker [![npm](https://img.shields.io/npm/dm/ngjs-color-picker.svg)](https://npmjs.org/package/ngjs-color-picker) [![Build Status](https://travis-ci.org/simeg/ngjs-color-picker.svg?branch=master)](https://travis-ci.org/simeg/ngjs-color-picker) 2 | 3 | A small directive which essentially is a color picker but with a few extra functions - for AngularJS. Based on [ng-color-picker](https://github.com/joujiahe/ng-color-picker). 4 | 5 | **Requirements**: Angular 1.2+ 6 | 7 | ![Screenshot](assets/screenshot.png) 8 | 9 | # Features 10 | - Customize the appearance of the color picker (vertical, horizontal, columns etc.) 11 | - Generate random colors 12 | - Generate gradient colors 13 | 14 | # Demo 15 | - [Demo](http://simeg.github.io/ngjs-color-picker) 16 | - [Plunker](http://embed.plnkr.co/INXf3efkYeP1gWaF9SId/preview) 17 | 18 | # Installation 19 | ## npm: 20 | ``` bash 21 | npm install --save ngjs-color-picker 22 | ``` 23 | 24 | You may have to run 25 | 26 | ``` bash 27 | grunt wiredep 28 | ``` 29 | 30 | to make grunt automatically add the needed files to your `index.html`. 31 | 32 | ## Manually: 33 | Clone or [download](https://github.com/simeg/ngjs-color-picker/archive/master.zip) the repository and include the production file in your application. 34 | 35 | ``` html 36 | 37 | ``` 38 | 39 | Inject the directive as a dependency in your app: 40 | 41 | ``` javascript 42 | angular.module('myApp', ['ngjsColorPicker']); 43 | ``` 44 | 45 | # Usage and documentation 46 | For documentation, examples and usage see the [GitHub page for this repository](http://simeg.github.io/ngjs-color-picker). 47 | 48 | ## Option prioritization 49 | 1. Custom colors 50 | 2. Random colors 51 | 3. Gradient 52 | 4. Default colors 53 | 54 | # Contribute :raised_hands: 55 | Run `npm install` and then you're able to start dev server with 56 | ``` bash 57 | npm run serve 58 | ``` 59 | 60 | The server is then available at [http://localhost:8080](http://localhost:8080). 61 | 62 | The file `dev/app/ngjs-color-picker.js` is a symlink to `source/ngjs-color-picker.js`, so you can edit either one of them and the change will be shown on the dev server. 63 | 64 | (Development server environment created using awesome [angular-webpack](https://github.com/preboot/angular-webpack)). 65 | 66 | # TODO 67 | * **See [issues](https://github.com/simeg/ngjs-color-picker/issues)** 68 | * Click (or something) to get the hex-code for the color (rgb should also be available) 69 | * Add reverse option for gradient 70 | * Include color themes (Good palettes: http://jsfiddle.net/nicgirault/bqph3pkL/) 71 | * Add option to select rows instead of columns 72 | -------------------------------------------------------------------------------- /assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simeg/ngjs-color-picker/d98dfe8cc0fd09d8043819ecae3eed20542c8870/assets/screenshot.png -------------------------------------------------------------------------------- /assets/screenshot.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simeg/ngjs-color-picker/d98dfe8cc0fd09d8043819ecae3eed20542c8870/assets/screenshot.psd -------------------------------------------------------------------------------- /dev/app/app.html: -------------------------------------------------------------------------------- 1 |

Basic usage example

2 | 3 | 4 |
5 |
6 | 7 |

Example with larger size and round corners

8 | 9 | 10 |
11 |
12 | 13 |

Example with random colors

14 | 15 | 16 |
17 |
18 | 19 |

Example with gradient

20 | 21 | 22 |
23 |
24 | 25 |

Example with vertical color picker

26 | 27 | 28 |
29 |
30 | 31 |

Example with columns defined

32 | 33 | 34 |
35 |
36 | -------------------------------------------------------------------------------- /dev/app/app.js: -------------------------------------------------------------------------------- 1 | import angular from 'angular'; 2 | require('../../source/ngjs-color-picker.js'); 3 | 4 | class AppCtrl { 5 | constructor() { 6 | 7 | // Set $scope variables here on _this_ 8 | this.customOptions = { 9 | size: 30, 10 | roundCorners: true 11 | }; 12 | 13 | this.optionsRandom = { 14 | randomColors: 10 15 | }; 16 | 17 | this.optionsGradient = { 18 | start: '#BA693E', 19 | count: 10, 20 | step: 1 21 | }; 22 | 23 | this.optionsVertical = { 24 | horizontal: false, 25 | total: 5 26 | }; 27 | 28 | this.optionsColumn = { 29 | columns: 4, 30 | roundCorners: true 31 | }; 32 | } 33 | } 34 | 35 | /* Angular configuration (no need to touch this) */ 36 | let app = () => { 37 | return { 38 | template: require('./app.html'), 39 | controller: 'AppCtrl', 40 | controllerAs: 'app' 41 | } 42 | }; 43 | 44 | const MODULE_NAME = 'app'; 45 | angular.module(MODULE_NAME, ['ngjsColorPicker']) 46 | .directive('app', app) 47 | .controller('AppCtrl', AppCtrl); 48 | 49 | export default MODULE_NAME; 50 | -------------------------------------------------------------------------------- /dev/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Dev server - ngjs-color-picker 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /dist/ngjs-color-picker.js: -------------------------------------------------------------------------------- 1 | !function(o){function s(n){if(r[n])return r[n].exports;var t=r[n]={exports:{},id:n,loaded:!1};return o[n].call(t.exports,t,t.exports,s),t.loaded=!0,t.exports}var r={};return s.m=o,s.c=r,s.p="/",s(0)}([function(o,s){"use strict";angular.module("ngjsColorPicker",[]).directive("ngjsColorPicker",function(){var o='',s=[{selector:"ul",rules:["padding: 0","outline: none","list-style-type: none"]},{selector:"li",rules:["padding: 0","margin: 0","box-sizing: border-box","outline: none"]},{selector:"li.selectedColor",rules:["border: 1px solid #333"]},{selector:"li.hRDF",rules:["border-radius: 5px 0 0 5px"]},{selector:"li.hRDL",rules:["border-radius: 0 5px 5px 0"]},{selector:"li.vRDF",rules:["border-radius: 5px 5px 0 0"]},{selector:"li.vRDL",rules:["border-radius: 0 0 5px 5px"]},{selector:"li.tlRound",rules:["border-radius: 5px 0 0 0"]},{selector:"li.trRound",rules:["border-radius: 0 5px 0 0;"]},{selector:"li.brRound",rules:["border-radius: 0 0 5px 0;"]},{selector:"li.blRound",rules:["border-radius: 0 0 0 5px;"]}],r=["#7bd148","#5484ed","#a4bdfc","#46d6db","#7ae7bf","#51b749","#fbd75b","#ffb878","#ff887c","#dc2127","#dbadff","#e1e1e1"],n={colors:r,options:{size:20,columns:null,randomColors:null},gradient:null},t=function(o){o.colors=r,o.options=o.options||{},o.options.size=o.options.size||n.options.size,o.options.columns=o.options.columns||n.options.columns,o.options.randomColors=o.options.randomColors||n.options.randomColors,o.options.total=o.options.total||o.colors.length,o.options.horizontal=!o.options.hasOwnProperty("horizontal")||o.options.horizontal,o.options.roundCorners=!!o.options.hasOwnProperty("roundCorners")&&o.options.roundCorners,o.gradient=o.gradient||n.gradient,o.ulCss={},o.css={},o.css.display=o.options.horizontal?"inline-block":"block",o.css.width=o.css.height=o.options.size+"px"},e=function(o){if(o.customColors)o.colors=o.customColors;else if(o.options&&o.options.randomColors){if(o.options.randomColors>0){o.colors=[];for(var s=o.options.randomColors;0!==s;)o.colors.push(p()),s--}}else if(o.gradient){var r=a(o.gradient.start),n=/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(r);if(n){o.colors=[];for(var t=o.gradient.hasOwnProperty("count")?o.gradient.count:10,e=o.gradient.hasOwnProperty("step")?o.gradient.step:1;0!==t;)o.colors.push(f(0===o.colors.length?r:o.colors[o.colors.length-1],e)),e+=o.gradient.step,t--,"#ffffff"!==o.colors[o.colors.length-1].toLowerCase()&&"#000000"!==o.colors[o.colors.length-1]||(t=0)}}},l=function(o){var s=o.css.width.indexOf("p");o.ulCss.width=o.options.columns*parseInt(o.css.width.substr(0,s),10)+"px",o.ulCss.height=o.options.size*(o.colors.length/o.options.columns)+"px",o.css.cssFloat="left";var r=o.colors.length%o.options.columns===0;o.columnRound=r&&o.options.columns&&o.options.roundCorners},i=function(o){o.hzRound=o.options.horizontal&&o.options.roundCorners&&!o.options.columns,o.vertRound=!o.options.horizontal&&o.options.roundCorners&&!o.options.columns},c=function(o){o.selectedColor=o.selectedColor||o.colors[0]},u=function(o,s){var r="ngjs-color-picker";return r+" "+o+" {"+s.join(";")+"}"},d=function(){var o=s.map(function(o){return u(o.selector,o.rules)});angular.element(document).find("head").prepend('")},p=function(){return"#"+(Math.random().toString(16)+"000000").slice(2,8)},a=function(o){var s=+("#"===o.charAt(0));return"#"+o.substr(s).toLowerCase()},f=function(o,s){var r=parseInt(o.slice(1),16),n=Math.round(2.55*s),t=(r>>16)+n,e=(r>>8&255)+n,l=(255&r)+n;return"#"+(16777216+65536*(t<255?t<1?0:t:255)+256*(e<255?e<1?0:e:255)+(l<255?l<1?0:l:255)).toString(16).slice(1)};return{scope:{selectedColor:"=?",customColors:"=?",options:"=?",gradient:"=?"},restrict:"E",template:o,link:function(o){t(o),e(o),c(o),i(o),d(),o.options.columns&&l(o),o.getCss=function(s){return o.css.background=s,o.css},o.pick=function(s){o.selectedColor=s}}}})}]); 2 | //# sourceMappingURL=ngjs-color-picker.js.map -------------------------------------------------------------------------------- /dist/ngjs-color-picker.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///ngjs-color-picker.js","webpack:///webpack/bootstrap e410ed00d5e1740fb921","webpack:///./source/ngjs-color-picker.js"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","id","loaded","call","m","c","p","angular","directive","template","styling","selector","rules","defaultColors","defaultValues","colors","options","size","columns","randomColors","gradient","setInitValues","scope","total","length","horizontal","hasOwnProperty","roundCorners","ulCss","css","display","width","height","setColors","customColors","push","getRandomHexColor","validHex","formatToHex","start","isOkHex","test","count","interval","step","shadeColor","toLowerCase","setColumns","indexOfPx","indexOf","parseInt","substr","cssFloat","isOkColumn","columnRound","setRoundedCorners","hzRound","vertRound","setInitialSelectedColor","selectedColor","getHtmlCssStyle","prefix","join","applyCssToHtml","styles","map","element","document","find","prepend","Math","random","toString","slice","hex","index","charAt","color","percent","num","amt","round","R","G","B","restrict","link","getCss","background","pick"],"mappings":"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","file":"ngjs-color-picker.js","sourcesContent":["/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"/\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\tangular.module('ngjsColorPicker', []).directive('ngjsColorPicker', function () {\n\t var template = '';\n\t\n\t var styling = [{\n\t selector: 'ul',\n\t rules: ['padding: 0', 'outline: none', 'list-style-type: none']\n\t }, {\n\t selector: 'li',\n\t rules: ['padding: 0', 'margin: 0', 'box-sizing: border-box', 'outline: none']\n\t }, {\n\t selector: 'li.selectedColor',\n\t rules: ['border: 1px solid #333']\n\t }, {\n\t selector: 'li.hRDF',\n\t rules: ['border-radius: 5px 0 0 5px']\n\t }, {\n\t selector: 'li.hRDL',\n\t rules: ['border-radius: 0 5px 5px 0']\n\t }, {\n\t selector: 'li.vRDF',\n\t rules: ['border-radius: 5px 5px 0 0']\n\t }, {\n\t selector: 'li.vRDL',\n\t rules: ['border-radius: 0 0 5px 5px']\n\t }, {\n\t selector: 'li.tlRound',\n\t rules: ['border-radius: 5px 0 0 0']\n\t }, {\n\t selector: 'li.trRound',\n\t rules: ['border-radius: 0 5px 0 0;']\n\t }, {\n\t selector: 'li.brRound',\n\t rules: ['border-radius: 0 0 5px 0;']\n\t }, {\n\t selector: 'li.blRound',\n\t rules: ['border-radius: 0 0 0 5px;']\n\t }];\n\t\n\t var defaultColors = ['#7bd148', '#5484ed', '#a4bdfc', '#46d6db', '#7ae7bf', '#51b749', '#fbd75b', '#ffb878', '#ff887c', '#dc2127', '#dbadff', '#e1e1e1'];\n\t\n\t var defaultValues = {\n\t colors: defaultColors,\n\t options: {\n\t size: 20,\n\t columns: null,\n\t randomColors: null\n\t },\n\t gradient: null\n\t };\n\t\n\t var setInitValues = function setInitValues(scope) {\n\t scope.colors = defaultColors;\n\t scope.options = scope.options || {};\n\t scope.options.size = scope.options.size || defaultValues.options.size;\n\t scope.options.columns = scope.options.columns || defaultValues.options.columns;\n\t scope.options.randomColors = scope.options.randomColors || defaultValues.options.randomColors;\n\t scope.options.total = scope.options.total || scope.colors.length;\n\t scope.options.horizontal = scope.options.hasOwnProperty('horizontal') ? scope.options.horizontal : true;\n\t scope.options.roundCorners = scope.options.hasOwnProperty('roundCorners') ? scope.options.roundCorners : false;\n\t scope.gradient = scope.gradient || defaultValues.gradient;\n\t\n\t scope.ulCss = {};\n\t scope.css = {};\n\t scope.css.display = scope.options.horizontal ? 'inline-block' : 'block';\n\t scope.css.width = scope.css.height = scope.options.size + 'px';\n\t };\n\t\n\t var setColors = function setColors(scope) {\n\t if (!!scope.customColors) {\n\t scope.colors = scope.customColors;\n\t } else if (scope.options && !!scope.options.randomColors) {\n\t if (scope.options.randomColors > 0) {\n\t scope.colors = [];\n\t var randomColors = scope.options.randomColors;\n\t while (randomColors !== 0) {\n\t scope.colors.push(getRandomHexColor());\n\t randomColors--;\n\t }\n\t } else {\n\t // TODO: Handle this\n\t // Random colors array is empty\n\t }\n\t } else if (!!scope.gradient) {\n\t // If step === 0 => nothing will happen.\n\t // If step === 1 => it will add 3 shades to all\n\t // colors (2.55 shades per 1%, rounded)\n\t var validHex = formatToHex(scope.gradient.start);\n\t var isOkHex = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(validHex);\n\t if (isOkHex) {\n\t scope.colors = [];\n\t var count = scope.gradient.hasOwnProperty('count') ? scope.gradient.count : 10;\n\t var interval = scope.gradient.hasOwnProperty('step') ? scope.gradient.step : 1;\n\t while (count !== 0) {\n\t scope.colors.push(shadeColor(scope.colors.length === 0 ? validHex : scope.colors[scope.colors.length - 1], interval));\n\t interval += scope.gradient.step;\n\t count--;\n\t\n\t // If black or white - stop generating more colors\n\t if (scope.colors[scope.colors.length - 1].toLowerCase() === '#ffffff' || scope.colors[scope.colors.length - 1] === '#000000') count = 0;\n\t }\n\t } else {\n\t // TODO: Handle this\n\t // Hex is not valid\n\t }\n\t }\n\t };\n\t\n\t var setColumns = function setColumns(scope) {\n\t // Uneven amount of columns => no round corners\n\t // => horizontal or vertical has no effect\n\t var indexOfPx = scope.css.width.indexOf('p');\n\t scope.ulCss.width = scope.options.columns * parseInt(scope.css.width.substr(0, indexOfPx), 10) + 'px';\n\t scope.ulCss.height = scope.options.size * (scope.colors.length / scope.options.columns) + 'px';\n\t scope.css.cssFloat = 'left';\n\t\n\t // Set rounded corners\n\t var isOkColumn = scope.colors.length % scope.options.columns === 0;\n\t scope.columnRound = isOkColumn && scope.options.columns && scope.options.roundCorners;\n\t };\n\t\n\t var setRoundedCorners = function setRoundedCorners(scope) {\n\t scope.hzRound = scope.options.horizontal && scope.options.roundCorners && !scope.options.columns;\n\t scope.vertRound = !scope.options.horizontal && scope.options.roundCorners && !scope.options.columns;\n\t };\n\t\n\t var setInitialSelectedColor = function setInitialSelectedColor(scope) {\n\t scope.selectedColor = scope.selectedColor || scope.colors[0];\n\t };\n\t\n\t var getHtmlCssStyle = function getHtmlCssStyle(selector, rules) {\n\t var prefix = 'ngjs-color-picker';\n\t return prefix + ' ' + selector + ' {' + rules.join(';') + '}';\n\t };\n\t\n\t var applyCssToHtml = function applyCssToHtml() {\n\t var styles = styling.map(function (element) {\n\t return getHtmlCssStyle(element.selector, element.rules);\n\t });\n\t\n\t angular.element(document).find('head').prepend('');\n\t };\n\t\n\t /* Util functions */\n\t var getRandomHexColor = function getRandomHexColor() {\n\t return '#' + (Math.random().toString(16) + '000000').slice(2, 8);\n\t };\n\t\n\t var formatToHex = function formatToHex(hex) {\n\t var index = +(hex.charAt(0) === '#');\n\t return '#' + hex.substr(index).toLowerCase();\n\t };\n\t\n\t var shadeColor = function shadeColor(color, percent) {\n\t var num = parseInt(color.slice(1), 16),\n\t amt = Math.round(2.55 * percent),\n\t R = (num >> 16) + amt,\n\t G = (num >> 8 & 0x00FF) + amt,\n\t B = (num & 0x0000FF) + amt;\n\t return '#' + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);\n\t };\n\t\n\t return {\n\t scope: {\n\t selectedColor: '=?',\n\t customColors: '=?',\n\t options: '=?',\n\t gradient: '=?'\n\t },\n\t restrict: 'E',\n\t template: template,\n\t link: function link(scope) {\n\t // element, attr\n\t\n\t setInitValues(scope);\n\t setColors(scope);\n\t setInitialSelectedColor(scope);\n\t setRoundedCorners(scope);\n\t applyCssToHtml();\n\t\n\t if (!!scope.options.columns) {\n\t setColumns(scope);\n\t }\n\t\n\t scope.getCss = function (color) {\n\t scope.css.background = color;\n\t return scope.css;\n\t };\n\t\n\t scope.pick = function (color) {\n\t scope.selectedColor = color;\n\t };\n\t }\n\t };\n\t});\n\n/***/ }\n/******/ ]);\n\n\n// WEBPACK FOOTER //\n// ngjs-color-picker.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap e410ed00d5e1740fb921","'use strict';\n\nangular.module('ngjsColorPicker', [])\n .directive('ngjsColorPicker', function() {\n var template =\n '';\n\n var styling = [\n {\n selector: 'ul',\n rules: [\n 'padding: 0',\n 'outline: none',\n 'list-style-type: none'\n ]\n },\n {\n selector: 'li',\n rules: [\n 'padding: 0',\n 'margin: 0',\n 'box-sizing: border-box',\n 'outline: none'\n ]\n },\n {\n selector: 'li.selectedColor',\n rules: [\n 'border: 1px solid #333'\n ]\n },\n {\n selector: 'li.hRDF',\n rules: [\n 'border-radius: 5px 0 0 5px'\n ]\n },\n {\n selector: 'li.hRDL',\n rules: [\n 'border-radius: 0 5px 5px 0'\n ]\n },\n {\n selector: 'li.vRDF',\n rules: [\n 'border-radius: 5px 5px 0 0'\n ]\n },\n {\n selector: 'li.vRDL',\n rules: [\n 'border-radius: 0 0 5px 5px'\n ]\n },\n {\n selector: 'li.tlRound',\n rules: [\n 'border-radius: 5px 0 0 0'\n ]\n },\n {\n selector: 'li.trRound',\n rules: [\n 'border-radius: 0 5px 0 0;'\n ]\n },\n {\n selector: 'li.brRound',\n rules: [\n 'border-radius: 0 0 5px 0;'\n ]\n },\n {\n selector: 'li.blRound',\n rules: [\n 'border-radius: 0 0 0 5px;'\n ]\n }\n ];\n\n var defaultColors = [\n '#7bd148',\n '#5484ed',\n '#a4bdfc',\n '#46d6db',\n '#7ae7bf',\n '#51b749',\n '#fbd75b',\n '#ffb878',\n '#ff887c',\n '#dc2127',\n '#dbadff',\n '#e1e1e1'\n ];\n\n var defaultValues = {\n colors: defaultColors,\n options: {\n size: 20,\n columns: null,\n randomColors: null\n },\n gradient: null\n };\n\n var setInitValues = function(scope) {\n scope.colors = defaultColors;\n scope.options = scope.options || {};\n scope.options.size = scope.options.size || defaultValues.options.size;\n scope.options.columns = scope.options.columns || defaultValues.options.columns;\n scope.options.randomColors =\n scope.options.randomColors || defaultValues.options.randomColors;\n scope.options.total = scope.options.total || scope.colors.length;\n scope.options.horizontal =\n (scope.options.hasOwnProperty('horizontal') ? scope.options.horizontal : true);\n scope.options.roundCorners =\n (scope.options.hasOwnProperty('roundCorners') ?\n scope.options.roundCorners : false);\n scope.gradient = scope.gradient || defaultValues.gradient;\n\n scope.ulCss = {};\n scope.css = {};\n scope.css.display = (scope.options.horizontal ? 'inline-block' : 'block');\n scope.css.width = scope.css.height = scope.options.size + 'px';\n };\n\n var setColors = function(scope) {\n if (!!scope.customColors) {\n scope.colors = scope.customColors;\n } else if (scope.options && !!scope.options.randomColors) {\n if (scope.options.randomColors > 0) {\n scope.colors = [];\n var randomColors = scope.options.randomColors;\n while (randomColors !== 0) {\n scope.colors.push(getRandomHexColor());\n randomColors--;\n }\n } else {\n // TODO: Handle this\n // Random colors array is empty\n }\n } else if (!!scope.gradient) {\n // If step === 0 => nothing will happen.\n // If step === 1 => it will add 3 shades to all\n // colors (2.55 shades per 1%, rounded)\n var validHex = formatToHex(scope.gradient.start);\n var isOkHex = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(validHex);\n if (isOkHex) {\n scope.colors = [];\n var count =\n (scope.gradient.hasOwnProperty('count') ? scope.gradient.count : 10);\n var interval =\n (scope.gradient.hasOwnProperty('step') ? scope.gradient.step : 1);\n while (count !== 0) {\n scope.colors.push(shadeColor(scope.colors.length === 0 ?\n validHex : scope.colors[scope.colors.length - 1], interval));\n interval+=scope.gradient.step;\n count--;\n\n // If black or white - stop generating more colors\n if (scope.colors[scope.colors.length - 1].toLowerCase() === '#ffffff' ||\n scope.colors[scope.colors.length - 1] === '#000000')\n count = 0;\n }\n } else {\n // TODO: Handle this\n // Hex is not valid\n }\n }\n };\n\n var setColumns = function(scope) {\n // Uneven amount of columns => no round corners\n // => horizontal or vertical has no effect\n var indexOfPx = scope.css.width.indexOf('p');\n scope.ulCss.width = scope.options.columns *\n (parseInt(scope.css.width.substr(0, indexOfPx), 10)) + 'px';\n scope.ulCss.height =\n scope.options.size * (scope.colors.length / scope.options.columns) + 'px';\n scope.css.cssFloat = 'left';\n\n // Set rounded corners\n var isOkColumn = (scope.colors.length % scope.options.columns) === 0;\n scope.columnRound =\n (isOkColumn && scope.options.columns && scope.options.roundCorners);\n };\n\n var setRoundedCorners = function(scope) {\n scope.hzRound = scope.options.horizontal && scope.options.roundCorners &&\n !scope.options.columns;\n scope.vertRound = !scope.options.horizontal && scope.options.roundCorners &&\n !scope.options.columns;\n };\n\n var setInitialSelectedColor = function(scope) {\n scope.selectedColor = scope.selectedColor || scope.colors[0];\n };\n\n var getHtmlCssStyle = function(selector, rules) {\n var prefix = 'ngjs-color-picker';\n return prefix + ' ' + selector + ' {' + rules.join(';') + '}';\n };\n\n var applyCssToHtml = function() {\n var styles = styling.map(function(element) {\n return getHtmlCssStyle(element.selector, element.rules);\n });\n\n angular.element(document).find('head').prepend(\n '');\n };\n\n /* Util functions */\n var getRandomHexColor = function() {\n return ('#' + (Math.random().toString(16) + '000000').slice(2, 8));\n };\n\n var formatToHex = function(hex) {\n var index = +(hex.charAt(0) === '#');\n return '#' + hex.substr(index).toLowerCase();\n };\n\n var shadeColor = function(color, percent) {\n var num = parseInt(color.slice(1), 16),\n amt = Math.round(2.55 * percent),\n R = (num >> 16) + amt,\n G = (num >> 8 & 0x00FF) + amt,\n B = (num & 0x0000FF) + amt;\n return '#' + (0x1000000 + (R<255?R<1?0:R:255)*0x10000 +\n (G<255?G<1?0:G:255)*0x100 + (B<255?B<1?0:B:255)).toString(16).slice(1);\n };\n\n return {\n scope: {\n selectedColor: '=?',\n customColors: '=?',\n options: '=?',\n gradient: '=?'\n },\n restrict: 'E',\n template: template,\n link: function(scope) { // element, attr\n\n setInitValues(scope);\n setColors(scope);\n setInitialSelectedColor(scope);\n setRoundedCorners(scope);\n applyCssToHtml();\n\n if (!!scope.options.columns) {\n setColumns(scope);\n }\n\n scope.getCss = function(color) {\n scope.css.background = color;\n return scope.css;\n };\n\n scope.pick = function(color) {\n scope.selectedColor = color;\n };\n\n }\n };\n\n });\n\n\n\n// WEBPACK FOOTER //\n// ./source/ngjs-color-picker.js"],"sourceRoot":""} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngjs-color-picker", 3 | "version": "1.1.2", 4 | "description": "A color picker with a few extra functions - for AngularJS", 5 | "main": "dist/ngjs-color-picker.js", 6 | "files": [ 7 | "dist", 8 | "!dist/index.html" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/simeg/ngjs-color-picker.git" 13 | }, 14 | "keywords": [ 15 | "colors", 16 | "color", 17 | "picker", 18 | "color-picker", 19 | "gradient", 20 | "angularjs", 21 | "directive" 22 | ], 23 | "author": "Simon Egersand ", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/simeg/ngjs-color-picker/issues" 27 | }, 28 | "homepage": "https://github.com/simeg/ngjs-color-picker", 29 | "dependencies": { 30 | "angular": "^1.2" 31 | }, 32 | "devDependencies": { 33 | "angular-mocks": "^1.5.8", 34 | "babel-core": "^6.2.1", 35 | "babel-loader": "^7.1.1", 36 | "babel-preset-es2015": "^6.1.18", 37 | "copy-webpack-plugin": "^4.0.1", 38 | "eslint": "^4.3.0", 39 | "eslint-config-angular": "^0.5.0", 40 | "eslint-plugin-angular": "^3.0.0", 41 | "extract-text-webpack-plugin": "^3.0.0", 42 | "file-loader": "^0.11.2", 43 | "html-webpack-plugin": "^2.7.1", 44 | "istanbul": "^0.4.5", 45 | "jasmine": "^2.5.2", 46 | "jasmine-core": "^2.5.2", 47 | "jasmine-node": "^1.14.5", 48 | "karma": "^1.3.0", 49 | "karma-jasmine": "^1.0.2", 50 | "karma-jasmine-jquery": "^0.1.1", 51 | "karma-mocha-reporter": "^2.2.0", 52 | "karma-phantomjs-launcher": "^1.0.2", 53 | "null-loader": "^0.1.1", 54 | "phantomjs-prebuilt": "^2.1.13", 55 | "postcss-loader": "^2.0.6", 56 | "raw-loader": "^0.5.1", 57 | "rimraf": "^2.5.1", 58 | "style-loader": "^0.18.2", 59 | "webpack": "^3.4.1", 60 | "webpack-dev-server": "^2.6.1", 61 | "webpack-node-externals": "^1.5.4" 62 | }, 63 | "scripts": { 64 | "build": "rimraf dist && webpack --bail --progress --profile", 65 | "commit": "npm run pre-commit", 66 | "lint": "./node_modules/eslint/bin/eslint.js .eslintrc.yml './**/*.js'", 67 | "pre-commit": "npm run lint && npm run test", 68 | "serve": "webpack-dev-server --history-api-fallback --inline --progress", 69 | "test": "./node_modules/karma/bin/karma start ./test/karma.conf.js --single-run", 70 | "test:watch": "./node_modules/karma/bin/karma start ./test/karma.conf.js" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /source/ngjs-color-picker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('ngjsColorPicker', []) 4 | .directive('ngjsColorPicker', function() { 5 | var template = 6 | ''; 24 | 25 | var styling = [ 26 | { 27 | selector: 'ul', 28 | rules: [ 29 | 'padding: 0', 30 | 'outline: none', 31 | 'list-style-type: none' 32 | ] 33 | }, 34 | { 35 | selector: 'li', 36 | rules: [ 37 | 'padding: 0', 38 | 'margin: 0', 39 | 'box-sizing: border-box', 40 | 'outline: none' 41 | ] 42 | }, 43 | { 44 | selector: 'li.selectedColor', 45 | rules: [ 46 | 'border: 1px solid #333' 47 | ] 48 | }, 49 | { 50 | selector: 'li.hRDF', 51 | rules: [ 52 | 'border-radius: 5px 0 0 5px' 53 | ] 54 | }, 55 | { 56 | selector: 'li.hRDL', 57 | rules: [ 58 | 'border-radius: 0 5px 5px 0' 59 | ] 60 | }, 61 | { 62 | selector: 'li.vRDF', 63 | rules: [ 64 | 'border-radius: 5px 5px 0 0' 65 | ] 66 | }, 67 | { 68 | selector: 'li.vRDL', 69 | rules: [ 70 | 'border-radius: 0 0 5px 5px' 71 | ] 72 | }, 73 | { 74 | selector: 'li.tlRound', 75 | rules: [ 76 | 'border-radius: 5px 0 0 0' 77 | ] 78 | }, 79 | { 80 | selector: 'li.trRound', 81 | rules: [ 82 | 'border-radius: 0 5px 0 0;' 83 | ] 84 | }, 85 | { 86 | selector: 'li.brRound', 87 | rules: [ 88 | 'border-radius: 0 0 5px 0;' 89 | ] 90 | }, 91 | { 92 | selector: 'li.blRound', 93 | rules: [ 94 | 'border-radius: 0 0 0 5px;' 95 | ] 96 | } 97 | ]; 98 | 99 | var defaultColors = [ 100 | '#7bd148', 101 | '#5484ed', 102 | '#a4bdfc', 103 | '#46d6db', 104 | '#7ae7bf', 105 | '#51b749', 106 | '#fbd75b', 107 | '#ffb878', 108 | '#ff887c', 109 | '#dc2127', 110 | '#dbadff', 111 | '#e1e1e1' 112 | ]; 113 | 114 | var defaultValues = { 115 | colors: defaultColors, 116 | options: { 117 | size: 20, 118 | columns: null, 119 | randomColors: null 120 | }, 121 | gradient: null 122 | }; 123 | 124 | var setInitValues = function(scope) { 125 | scope.colors = defaultColors; 126 | scope.options = scope.options || {}; 127 | scope.options.size = scope.options.size || defaultValues.options.size; 128 | scope.options.columns = scope.options.columns || defaultValues.options.columns; 129 | scope.options.randomColors = 130 | scope.options.randomColors || defaultValues.options.randomColors; 131 | scope.options.total = scope.options.total || scope.colors.length; 132 | scope.options.horizontal = 133 | (scope.options.hasOwnProperty('horizontal') ? scope.options.horizontal : true); 134 | scope.options.roundCorners = 135 | (scope.options.hasOwnProperty('roundCorners') ? 136 | scope.options.roundCorners : false); 137 | scope.gradient = scope.gradient || defaultValues.gradient; 138 | 139 | scope.ulCss = {}; 140 | scope.css = {}; 141 | scope.css.display = (scope.options.horizontal ? 'inline-block' : 'block'); 142 | scope.css.width = scope.css.height = scope.options.size + 'px'; 143 | }; 144 | 145 | var setColors = function(scope) { 146 | if (!!scope.customColors) { 147 | scope.colors = scope.customColors; 148 | } else if (scope.options && !!scope.options.randomColors) { 149 | if (scope.options.randomColors > 0) { 150 | scope.colors = []; 151 | var randomColors = scope.options.randomColors; 152 | while (randomColors !== 0) { 153 | scope.colors.push(getRandomHexColor()); 154 | randomColors--; 155 | } 156 | } else { 157 | // TODO: Handle this 158 | // Random colors array is empty 159 | } 160 | } else if (!!scope.gradient) { 161 | // If step === 0 => nothing will happen. 162 | // If step === 1 => it will add 3 shades to all 163 | // colors (2.55 shades per 1%, rounded) 164 | var validHex = formatToHex(scope.gradient.start); 165 | var isOkHex = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(validHex); 166 | if (isOkHex) { 167 | scope.colors = []; 168 | var count = 169 | (scope.gradient.hasOwnProperty('count') ? scope.gradient.count : 10); 170 | var interval = 171 | (scope.gradient.hasOwnProperty('step') ? scope.gradient.step : 1); 172 | while (count !== 0) { 173 | scope.colors.push(shadeColor(scope.colors.length === 0 ? 174 | validHex : scope.colors[scope.colors.length - 1], interval)); 175 | interval+=scope.gradient.step; 176 | count--; 177 | 178 | // If black or white - stop generating more colors 179 | if (scope.colors[scope.colors.length - 1].toLowerCase() === '#ffffff' || 180 | scope.colors[scope.colors.length - 1] === '#000000') 181 | count = 0; 182 | } 183 | } else { 184 | // TODO: Handle this 185 | // Hex is not valid 186 | } 187 | } 188 | }; 189 | 190 | var setColumns = function(scope) { 191 | // Uneven amount of columns => no round corners 192 | // => horizontal or vertical has no effect 193 | var indexOfPx = scope.css.width.indexOf('p'); 194 | scope.ulCss.width = scope.options.columns * 195 | (parseInt(scope.css.width.substr(0, indexOfPx), 10)) + 'px'; 196 | scope.ulCss.height = 197 | scope.options.size * (scope.colors.length / scope.options.columns) + 'px'; 198 | scope.css.cssFloat = 'left'; 199 | 200 | // Set rounded corners 201 | var isOkColumn = (scope.colors.length % scope.options.columns) === 0; 202 | scope.columnRound = 203 | (isOkColumn && scope.options.columns && scope.options.roundCorners); 204 | }; 205 | 206 | var setRoundedCorners = function(scope) { 207 | scope.hzRound = scope.options.horizontal && scope.options.roundCorners && 208 | !scope.options.columns; 209 | scope.vertRound = !scope.options.horizontal && scope.options.roundCorners && 210 | !scope.options.columns; 211 | }; 212 | 213 | var setInitialSelectedColor = function(scope) { 214 | scope.selectedColor = scope.selectedColor || scope.colors[0]; 215 | }; 216 | 217 | var getHtmlCssStyle = function(selector, rules) { 218 | var prefix = 'ngjs-color-picker'; 219 | return prefix + ' ' + selector + ' {' + rules.join(';') + '}'; 220 | }; 221 | 222 | var applyCssToHtml = function() { 223 | var styles = styling.map(function(element) { 224 | return getHtmlCssStyle(element.selector, element.rules); 225 | }); 226 | 227 | angular.element(document).find('head').prepend( 228 | ''); 229 | }; 230 | 231 | /* Util functions */ 232 | var getRandomHexColor = function() { 233 | return ('#' + (Math.random().toString(16) + '000000').slice(2, 8)); 234 | }; 235 | 236 | var formatToHex = function(hex) { 237 | var index = +(hex.charAt(0) === '#'); 238 | return '#' + hex.substr(index).toLowerCase(); 239 | }; 240 | 241 | var shadeColor = function(color, percent) { 242 | var num = parseInt(color.slice(1), 16), 243 | amt = Math.round(2.55 * percent), 244 | R = (num >> 16) + amt, 245 | G = (num >> 8 & 0x00FF) + amt, 246 | B = (num & 0x0000FF) + amt; 247 | return '#' + (0x1000000 + (R<255?R<1?0:R:255)*0x10000 + 248 | (G<255?G<1?0:G:255)*0x100 + (B<255?B<1?0:B:255)).toString(16).slice(1); 249 | }; 250 | 251 | return { 252 | scope: { 253 | selectedColor: '=?', 254 | customColors: '=?', 255 | options: '=?', 256 | gradient: '=?' 257 | }, 258 | restrict: 'E', 259 | template: template, 260 | link: function(scope) { // element, attr 261 | 262 | setInitValues(scope); 263 | setColors(scope); 264 | setInitialSelectedColor(scope); 265 | setRoundedCorners(scope); 266 | applyCssToHtml(); 267 | 268 | if (!!scope.options.columns) { 269 | setColumns(scope); 270 | } 271 | 272 | scope.getCss = function(color) { 273 | scope.css.background = color; 274 | return scope.css; 275 | }; 276 | 277 | scope.pick = function(color) { 278 | scope.selectedColor = color; 279 | }; 280 | 281 | } 282 | }; 283 | 284 | }); 285 | -------------------------------------------------------------------------------- /test/directive.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('ngjs-color-picker', function() { 4 | var $compile, $rootScope; 5 | 6 | beforeEach(module('ngjsColorPicker')); 7 | 8 | beforeEach(inject(function(_$compile_, _$rootScope_) { 9 | $compile = _$compile_; 10 | $rootScope = _$rootScope_; 11 | })); 12 | 13 | it('changes selected color on click', function() { 14 | var element = $compile('')($rootScope); 15 | $rootScope.$digest(); 16 | var content = element.contents(); 17 | 18 | var listItems = content.find('li'); 19 | var firstListItem = listItems[0]; 20 | var secondListItem = listItems[1]; 21 | expect(firstListItem.outerHTML).toContain('class="ng-scope selectedColor"'); 22 | secondListItem.click(); 23 | expect(firstListItem.outerHTML).not.toContain('class="ng-scope selectedColor"'); 24 | expect(secondListItem.outerHTML).toContain('class="ng-scope selectedColor"'); 25 | }); 26 | 27 | describe('without custom options', function() { 28 | var element, content; 29 | beforeEach(function() { 30 | element = $compile('')($rootScope); 31 | // angular.element(document).find('body').append(element); 32 | $rootScope.$digest(); 33 | content = element.contents(); 34 | }); 35 | 36 | it('has default scope variables set', function() { 37 | var defaultOptions = { 38 | size: 20, 39 | columns: null, 40 | randomColors: null, 41 | total: 12, 42 | horizontal: true, 43 | roundCorners: false 44 | }; 45 | expect(element.isolateScope().options).toEqual(defaultOptions); 46 | var defaultColors = [ 47 | '#7bd148', 48 | '#5484ed', 49 | '#a4bdfc', 50 | '#46d6db', 51 | '#7ae7bf', 52 | '#51b749', 53 | '#fbd75b', 54 | '#ffb878', 55 | '#ff887c', 56 | '#dc2127', 57 | '#dbadff', 58 | '#e1e1e1' 59 | ]; 60 | expect(element.isolateScope().colors).toEqual(defaultColors); 61 | }); 62 | 63 | describe('renders', function() { 64 | it('list container element', function() { 65 | var listElement = element.find('ul'); 66 | expect(listElement.length).toBe(1); 67 | }); 68 | 69 | it('correct amount of color boxes', function() { 70 | var listItems = content.find('li'); 71 | expect(listItems.length).toBe(12); 72 | }); 73 | 74 | it('one selected color box', function() { 75 | var selectedItem = content.find('li.selectedColor'); 76 | expect(selectedItem.length).toBe(1); 77 | }); 78 | 79 | it('first color box as selected', function() { 80 | var listItems = content.find('li'); 81 | var firstListItem = listItems[0]; 82 | expect(firstListItem.outerHTML).toContain('class="ng-scope selectedColor"'); 83 | }); 84 | 85 | it('with default width and height', function() { 86 | var defaultWidth = '20px'; 87 | var defaultHeight = '20px'; 88 | var listItems = content.find('li'); 89 | var listElement = listItems[0]; 90 | expect(listElement.style.width).toEqual(defaultWidth); 91 | expect(listElement.style.height).toEqual(defaultHeight); 92 | }); 93 | 94 | it('in horizontal mode', function() { 95 | var listItems = content.find('li'); 96 | var blockElements = listItems.filter(function (index, item) { 97 | return item.style.display === 'block'; 98 | }); 99 | expect(blockElements.length).toEqual(0); 100 | }); 101 | 102 | it('with default colors', function() { 103 | var defaultColors = [ 104 | 'rgb(123, 209, 72)', 105 | 'rgb(84, 132, 237)', 106 | 'rgb(164, 189, 252)', 107 | 'rgb(70, 214, 219)', 108 | 'rgb(122, 231, 191)', 109 | 'rgb(81, 183, 73)', 110 | 'rgb(251, 215, 91)', 111 | 'rgb(255, 184, 120)', 112 | 'rgb(255, 136, 124)', 113 | 'rgb(220, 33, 39)', 114 | 'rgb(219, 173, 255)', 115 | 'rgb(225, 225, 225)' 116 | ]; 117 | var listItems = content.find('li'); 118 | var matches = listItems.filter(function (index, item) { 119 | return item.style.backgroundColor === defaultColors[index]; 120 | }); 121 | expect(matches.length).toEqual(listItems.length); 122 | }); 123 | }); 124 | }); 125 | 126 | describe('with single custom option', function() { 127 | it('adds provided option to scope', function() { 128 | var $scope = $rootScope.$new(); 129 | $scope.options = { 130 | customOption: 'shouldExist' 131 | }; 132 | var element = $compile( 133 | '')($scope); 134 | expect(element.isolateScope().options.hasOwnProperty('customOption')).toEqual(true); 135 | expect(element.isolateScope().options.customOption).toEqual('shouldExist'); 136 | }); 137 | 138 | describe('(customColors)', function() { 139 | var element, content, customColors; 140 | beforeEach(function() { 141 | customColors = [ 142 | 'rgb(27, 209, 72)', 143 | 'rgb(20, 132, 237)', 144 | 'rgb(161, 189, 252)', 145 | 'rgb(22, 214, 219)', 146 | 'rgb(26, 231, 191)', 147 | 'rgb(17, 183, 73)' 148 | ]; 149 | var $scope = $rootScope.$new(); 150 | $scope.customColors = customColors; 151 | element = $compile( 152 | '')($scope); 153 | $rootScope.$digest(); 154 | content = element.contents(); 155 | }); 156 | 157 | it('renders with custom colors', function() { 158 | var listItems = content.find('li'); 159 | var matches = listItems.filter(function (index, item) { 160 | return item.style.backgroundColor === customColors[index]; 161 | }); 162 | expect(matches.length).toEqual(listItems.length); 163 | }); 164 | }); 165 | 166 | describe('(total)', function() { 167 | var element, content; 168 | beforeEach(function() { 169 | var $scope = $rootScope.$new(); 170 | $scope.options = { total: 3 }; 171 | element = $compile( 172 | '')($scope); 173 | $rootScope.$digest(); 174 | content = element.contents(); 175 | }); 176 | 177 | it('limits rendered list items', function() { 178 | var listItems = content.find('li'); 179 | expect(listItems.length).toBe(3); 180 | }); 181 | }); 182 | 183 | describe('(selectedColor)', function() { 184 | var element, content; 185 | beforeEach(function() { 186 | var $scope = $rootScope.$new(); 187 | $scope.selectedColor = '#46d6db'; 188 | element = $compile('' + 189 | '')($scope); 190 | $rootScope.$digest(); 191 | content = element.contents(); 192 | }); 193 | 194 | it('sets selected color as selected', function() { 195 | var listItems = content.find('li'); 196 | var selectedListItem = listItems[3]; 197 | expect(selectedListItem.outerHTML).toContain('class="ng-scope selectedColor"'); 198 | }); 199 | }); 200 | 201 | describe('(size)', function() { 202 | var element, content; 203 | beforeEach(function() { 204 | var $scope = $rootScope.$new(); 205 | $scope.options = { size: 30 }; 206 | element = $compile( 207 | '')($scope); 208 | $rootScope.$digest(); 209 | content = element.contents(); 210 | }); 211 | 212 | it('renders with correct size', function() { 213 | var customWidth = '30px'; 214 | var customHeight = '30px'; 215 | var listItems = content.find('li'); 216 | var listElement = listItems[0]; 217 | expect(listElement.style.width).toEqual(customWidth); 218 | expect(listElement.style.height).toEqual(customHeight); 219 | }); 220 | }); 221 | 222 | describe('(round corners)', function() { 223 | var element, content; 224 | beforeEach(function() { 225 | var $scope = $rootScope.$new(); 226 | $scope.options = { roundCorners: true }; 227 | element = $compile( 228 | '')($scope); 229 | $rootScope.$digest(); 230 | content = element.contents(); 231 | }); 232 | 233 | it('renders with rounded corners', function() { 234 | var listItems = content.find('li'); 235 | var firstListItem = listItems[0]; 236 | var lastListItem = listItems[listItems.length - 1]; 237 | expect(firstListItem.outerHTML).toContain('class="ng-scope selectedColor hRDF"'); 238 | expect(lastListItem.outerHTML).toContain('class="ng-scope hRDL"'); 239 | }); 240 | }); 241 | 242 | describe('(random colors)', function() { 243 | var element, content; 244 | beforeEach(function() { 245 | var $scope = $rootScope.$new(); 246 | $scope.options = { randomColors: 10 }; 247 | element = $compile( 248 | '')($scope); 249 | $rootScope.$digest(); 250 | content = element.contents(); 251 | }); 252 | 253 | it('renders with random colors', function() { 254 | var sortedDefaultColorsInRgb = [ 255 | 'rgb(123, 209, 72)', 256 | 'rgb(84, 132, 237)', 257 | 'rgb(164, 189, 252)', 258 | 'rgb(70, 214, 219)', 259 | 'rgb(122, 231, 191)', 260 | 'rgb(81, 183, 73)', 261 | 'rgb(251, 215, 91)', 262 | 'rgb(255, 184, 120)', 263 | 'rgb(255, 136, 124)', 264 | 'rgb(220, 33, 39)', 265 | 'rgb(219, 173, 255)', 266 | 'rgb(225, 225, 225)' 267 | ]; 268 | sortedDefaultColorsInRgb.sort(); 269 | var listItems = content.find('li'); 270 | var randomColors = []; 271 | for (var i = 0; i < listItems.length; i++) { 272 | var item = listItems[i]; 273 | randomColors.push(item.style.backgroundColor); 274 | } 275 | var sortedRandomColors = randomColors.slice(); 276 | sortedRandomColors.sort(); 277 | expect(sortedDefaultColorsInRgb).not.toEqual(sortedRandomColors); 278 | }); 279 | }); 280 | 281 | describe('(gradient colors)', function() { 282 | var element, content; 283 | beforeEach(function() { 284 | var $scope = $rootScope.$new(); 285 | $scope.gradient = { 286 | start: '#BA693E', 287 | count: 10, 288 | step: 1 289 | }; 290 | element = $compile( 291 | '')($scope); 292 | $rootScope.$digest(); 293 | content = element.contents(); 294 | }); 295 | 296 | it('renders with gradient colors', function() { 297 | var listItems = content.find('li'); 298 | var firstListItem = listItems[0]; 299 | var lastListItem = listItems[listItems.length - 1]; 300 | expect(firstListItem.style.backgroundColor).toEqual('rgb(189, 108, 65)'); 301 | expect(lastListItem.style.backgroundColor).toEqual('rgb(255, 246, 203)'); 302 | }); 303 | }); 304 | 305 | describe('(vertical direction)', function() { 306 | var element, content; 307 | beforeEach(function() { 308 | var $scope = $rootScope.$new(); 309 | $scope.options = { 310 | horizontal: true 311 | }; 312 | element = $compile( 313 | '')($scope); 314 | $rootScope.$digest(); 315 | content = element.contents(); 316 | }); 317 | 318 | it('renders directive in vertical mode', function() { 319 | var listItems = content.find('li'); 320 | var inlineBlockElements = listItems.filter(function (index, item) { 321 | return item.style.display === 'inline-block'; 322 | }); 323 | expect(inlineBlockElements.length).toEqual(listItems.length); 324 | }); 325 | }); 326 | 327 | describe('(columns)', function() { 328 | var element, content; 329 | 330 | var setupDirectiveWithNColumns = function (n) { 331 | var $scope = $rootScope.$new(); 332 | $scope.options = { 333 | columns: n 334 | }; 335 | element = $compile( 336 | '')($scope); 337 | $rootScope.$digest(); 338 | content = element.contents(); 339 | }; 340 | 341 | var getListWidth = function(columns, listItemWidth) { 342 | listItemWidth = listItemWidth || 20; // 20 is default width 343 | return columns * listItemWidth + 'px'; 344 | }; 345 | 346 | var getListHeight = function (columns, listItemWidth, listLength) { 347 | return (listItemWidth * (listLength / columns)) + 'px'; 348 | }; 349 | 350 | it('renders directive in column mode', function() { 351 | setupDirectiveWithNColumns(4); 352 | var listContainer = element.find('ul')[0]; 353 | expect(listContainer.style.width).not.toEqual(''); 354 | expect(listContainer.style.height).not.toEqual(''); 355 | var listItems = content.find('li'); 356 | var floatLeftItems = listItems.filter(function (index, item) { 357 | return item.style.float === 'left'; 358 | }); 359 | expect(floatLeftItems.length).toEqual(listItems.length); 360 | }); 361 | 362 | it('renders with specified columns', function() { 363 | for (var i = 1; i <= 10; i++) { 364 | var columns = i; 365 | setupDirectiveWithNColumns(columns); 366 | var listContainer = element.find('ul')[0]; 367 | var listItems = content.find('li'); 368 | var columnDirectiveWidth = getListWidth(columns, 20); 369 | var columnDirectiveHeight = getListHeight(columns, 20, listItems.length); 370 | expect(listContainer.style.width).toEqual(columnDirectiveWidth); 371 | expect(listContainer.style.height).toEqual(columnDirectiveHeight); 372 | } 373 | }); 374 | }); 375 | }); 376 | 377 | describe('with multiple custom options', function () { 378 | describe('with prioritizes', function () { 379 | it('has custom colors as prio 1', function () { 380 | var $scope = $rootScope.$new(); 381 | $scope.customColors = [ 382 | 'rgb(27, 209, 72)', 383 | 'rgb(20, 132, 237)', 384 | 'rgb(161, 189, 252)', 385 | 'rgb(22, 214, 219)', 386 | 'rgb(26, 231, 191)', 387 | 'rgb(17, 183, 73)' 388 | ]; 389 | 390 | $scope.options = { 391 | randomColors: 10 392 | }; 393 | 394 | $scope.gradient = { 395 | start: '#BA693E', 396 | count: 10, 397 | step: 1 398 | }; 399 | 400 | var element = $compile( 401 | '' + 402 | '')($scope); 403 | $rootScope.$digest(); 404 | var content = element.contents(); 405 | 406 | var listItems = content.find('li'); 407 | var matches = listItems.filter(function (index, item) { 408 | return item.style.backgroundColor === $scope.customColors[index]; 409 | }); 410 | expect(matches.length).toEqual(listItems.length); 411 | }); 412 | 413 | it('has random colors as prio 2', function () { 414 | var $scope = $rootScope.$new(); 415 | $scope.options = { 416 | randomColors: 10 417 | }; 418 | 419 | $scope.gradient = { 420 | start: '#BA693E', 421 | count: 10, 422 | step: 1 423 | }; 424 | 425 | var element = $compile( 426 | '')($scope); 427 | $rootScope.$digest(); 428 | var content = element.contents(); 429 | 430 | // Check that first and last list elements do not match 431 | // provided gradient spectre. That is good enough. 432 | var listItems = content.find('li'); 433 | var firstListItem = listItems[0]; 434 | var lastListItem = listItems[listItems.length - 1]; 435 | expect(firstListItem.style.backgroundColor).not.toEqual('rgb(189, 108, 65)'); 436 | expect(lastListItem.style.backgroundColor).not.toEqual('rgb(255, 246, 203)'); 437 | }); 438 | }); 439 | }); 440 | 441 | }); 442 | -------------------------------------------------------------------------------- /test/karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(config) { 4 | config.set({ 5 | 6 | // base path that will be used to resolve all patterns (eg. files, exclude) 7 | basePath: '../', 8 | 9 | 10 | // frameworks to use 11 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 12 | frameworks: ['jasmine-jquery', 'jasmine'], 13 | 14 | 15 | // list of files / patterns to load in the browser 16 | files: [ 17 | 'node_modules/angular/angular.js', 18 | 'node_modules/angular-mocks/angular-mocks.js', 19 | 'source/**/*.js', 20 | 'css/**/*.css', 21 | 'test/**/*.spec.js' 22 | ], 23 | 24 | 25 | // list of files to exclude 26 | exclude: [ 27 | ], 28 | 29 | 30 | // preprocess matching files before serving them to the browser 31 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 32 | preprocessors: { 33 | }, 34 | 35 | 36 | // test results reporter to use 37 | // possible values: 'dots', 'progress' 38 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 39 | reporters: ['mocha'], 40 | 41 | 42 | // web server port 43 | port: 9876, 44 | 45 | 46 | // enable / disable colors in the output (reporters and logs) 47 | colors: true, 48 | 49 | 50 | // level of logging 51 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || 52 | // config.LOG_INFO || config.LOG_DEBUG 53 | logLevel: config.LOG_INFO, 54 | 55 | 56 | // enable / disable watching file and executing tests whenever any file changes 57 | autoWatch: true, 58 | 59 | 60 | // start these browsers 61 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 62 | browsers: ['PhantomJS'], 63 | 64 | 65 | // Continuous Integration mode 66 | // if true, Karma captures browsers, runs the tests and exits 67 | singleRun: false, 68 | 69 | 70 | // Concurrency level 71 | // how many browser should be started simultaneous 72 | concurrency: Infinity 73 | }); 74 | }; 75 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Modules 4 | var webpack = require('webpack'); 5 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 6 | var CopyWebpackPlugin = require('copy-webpack-plugin'); 7 | 8 | /** 9 | * Env 10 | * Get npm lifecycle event to identify the environment 11 | */ 12 | var ENV = process.env.npm_lifecycle_event; 13 | var isProd = ENV === 'build'; 14 | 15 | module.exports = function makeWebpackConfig () { 16 | /** 17 | * Config 18 | * Reference: http://webpack.github.io/docs/configuration.html 19 | * This is the object where all configuration gets set 20 | */ 21 | var config = {}; 22 | 23 | /** 24 | * Entry 25 | * Reference: http://webpack.github.io/docs/configuration.html#entry 26 | * Should be an empty object if it's generating a test build 27 | * Karma will set this when it's a test build 28 | */ 29 | config.entry = { 30 | app: isProd ? './source/ngjs-color-picker.js' : './dev/app/app.js' 31 | }; 32 | 33 | /** 34 | * Output 35 | * Reference: http://webpack.github.io/docs/configuration.html#output 36 | * Should be an empty object if it's generating a test build 37 | * Karma will handle setting it up for you when it's a test build 38 | */ 39 | config.output = { 40 | // Absolute output directory 41 | path: __dirname + '/dist', 42 | 43 | // Output path from the view of the page 44 | // Uses webpack-dev-server in development 45 | publicPath: isProd ? '/' : 'http://localhost:8080/', 46 | 47 | // Filename for entry points 48 | // Only adds hash in build mode 49 | filename: isProd ? 'ngjs-color-picker.js' : '[name].bundle.js', 50 | 51 | // Filename for non-entry points 52 | // Only adds hash in build mode 53 | chunkFilename: isProd ? 'ngjs-color-picker.js' : '[name].bundle.js' 54 | }; 55 | 56 | /** 57 | * Devtool 58 | * Reference: http://webpack.github.io/docs/configuration.html#devtool 59 | * Type of sourcemap to use per build type 60 | */ 61 | if (isProd) { 62 | config.devtool = 'source-map'; 63 | } else { 64 | config.devtool = 'eval-source-map'; 65 | } 66 | 67 | /** 68 | * Loaders 69 | * Reference: http://webpack.github.io/docs/configuration.html#module-loaders 70 | * List: http://webpack.github.io/docs/list-of-loaders.html 71 | * This handles most of the magic responsible for converting modules 72 | */ 73 | 74 | // Initialize module 75 | config.module = { 76 | loaders: [{ 77 | // JS LOADER 78 | // Reference: https://github.com/babel/babel-loader 79 | // Transpile .js files using babel-loader 80 | // Compiles ES6 and ES7 into ES5 code 81 | test: /\.js$/, 82 | loader: 'babel-loader', 83 | exclude: /node_modules/ 84 | }, { 85 | // ASSET LOADER 86 | // Reference: https://github.com/webpack/file-loader 87 | // Copy png, jpg, jpeg, gif, svg, woff, woff2, ttf, eot files to output 88 | // Rename the file using the asset hash 89 | // Pass along the updated reference to your code 90 | // You can add here any file extension you want to get copied to your output 91 | test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/, 92 | loader: 'file' 93 | }, { 94 | // HTML LOADER 95 | // Reference: https://github.com/webpack/raw-loader 96 | // Allow loading html through js 97 | test: /\.html$/, 98 | loader: 'raw-loader' 99 | }] 100 | }; 101 | 102 | /** 103 | * Plugins 104 | * Reference: http://webpack.github.io/docs/configuration.html#plugins 105 | * List: http://webpack.github.io/docs/list-of-plugins.html 106 | */ 107 | config.plugins = []; 108 | 109 | // Reference: https://github.com/ampedandwired/html-webpack-plugin 110 | // Render index.html 111 | config.plugins.push( 112 | new HtmlWebpackPlugin({ 113 | template: './dev/public/index.html', 114 | inject: 'body' 115 | }) 116 | ); 117 | 118 | // Add build specific plugins 119 | if (isProd) { 120 | config.plugins.push( 121 | // Reference: http://webpack.github.io/docs/list-of-plugins.html#noerrorsplugin 122 | // Only emit files when there are no errors 123 | new webpack.NoErrorsPlugin(), 124 | 125 | // Reference: http://webpack.github.io/docs/list-of-plugins.html#dedupeplugin 126 | // Dedupe modules in the output 127 | new webpack.optimize.DedupePlugin(), 128 | 129 | // Reference: http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin 130 | // Minify all javascript, switch loaders to minimizing mode 131 | new webpack.optimize.UglifyJsPlugin(), 132 | 133 | // Copy assets from the public folder 134 | // Reference: https://github.com/kevlened/copy-webpack-plugin 135 | new CopyWebpackPlugin([{ 136 | from: __dirname + '/public' 137 | }]) 138 | ); 139 | } 140 | 141 | /** 142 | * Dev server configuration 143 | * Reference: http://webpack.github.io/docs/configuration.html#devserver 144 | * Reference: http://webpack.github.io/docs/webpack-dev-server.html 145 | */ 146 | config.devServer = { 147 | contentBase: './dev/public', 148 | stats: 'minimal' 149 | }; 150 | 151 | return config; 152 | }(); 153 | --------------------------------------------------------------------------------