├── .codeclimate.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── RELEASE.md ├── bower.json ├── dist ├── angularjs-color-picker.css ├── angularjs-color-picker.js ├── angularjs-color-picker.min.css ├── angularjs-color-picker.min.js └── themes │ ├── angularjs-color-picker-bootstrap.css │ └── angularjs-color-picker-bootstrap.min.css ├── examples ├── 01-simple.html ├── 02-app.js ├── 02-getterSetter.html ├── 03-angular-1.5.html ├── 04-app.js ├── 04-delayed-initial-value.html └── app.js ├── grunt ├── build.js ├── options │ ├── clean.js │ ├── connect.js │ ├── cssmin.js │ ├── jshint.js │ ├── less.js │ ├── notify.js │ ├── rollup.js │ └── run.js └── rollup.js ├── package.json ├── src ├── scripts │ ├── controller.js │ ├── directive.js │ ├── module.js │ ├── options-service.js │ └── template.js └── styles │ ├── angularjs-color-picker.less │ └── themes │ └── angularjs-color-picker-bootstrap.less └── test ├── e2e ├── allow-empty.protractor.js ├── alpha.protractor.js ├── button-clear.protractor.js ├── button-close.protractor.js ├── button-reset.protractor.js ├── dynamic-alpha.js ├── dynamic-hue.js ├── dynamic-lightness.js ├── dynamic-saturation.js ├── hide.protractor.js ├── hue.protractor.js ├── id.protractor.js ├── input-class.protractor.js ├── lightness.protractor.js ├── name.protractor.js ├── placeholder.protractor.js ├── preserve-input-format.protractor.js ├── restrict-to-format.protractor.js ├── saturation.protractor.js ├── show.protractor.js ├── swatch-only.protractor.js ├── swatch-pos.protractor.js └── swatch.protractor.js ├── page-object.js ├── protractor-config.js ├── test-app.js └── test.html /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | duplication: 4 | enabled: true 5 | config: 6 | languages: 7 | javascript: 8 | mass_threshold: 155 9 | eslint: 10 | enabled: true 11 | fixme: 12 | enabled: true 13 | ratings: 14 | paths: 15 | - "**.js" 16 | exclude_paths: 17 | - dist/ 18 | - test/ 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | indent_style = space 12 | indent_size = 4 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | **/*{.,-}min.js 3 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | --- 2 | parserOptions: 3 | sourceType: module 4 | ecmaFeatures: 5 | jsx: true 6 | 7 | env: 8 | amd: true 9 | browser: true 10 | es6: true 11 | jquery: true 12 | node: true 13 | 14 | # http://eslint.org/docs/rules/ 15 | rules: 16 | # Possible Errors 17 | no-await-in-loop: off 18 | no-cond-assign: error 19 | no-console: off 20 | no-constant-condition: error 21 | no-control-regex: error 22 | no-debugger: error 23 | no-dupe-args: error 24 | no-dupe-keys: error 25 | no-duplicate-case: error 26 | no-empty-character-class: error 27 | no-empty: error 28 | no-ex-assign: error 29 | no-extra-boolean-cast: error 30 | no-extra-parens: off 31 | no-extra-semi: error 32 | no-func-assign: error 33 | no-inner-declarations: 34 | - error 35 | - functions 36 | no-invalid-regexp: error 37 | no-irregular-whitespace: error 38 | no-negated-in-lhs: error 39 | no-obj-calls: error 40 | no-prototype-builtins: off 41 | no-regex-spaces: error 42 | no-sparse-arrays: error 43 | no-template-curly-in-string: off 44 | no-unexpected-multiline: error 45 | no-unreachable: error 46 | no-unsafe-finally: off 47 | no-unsafe-negation: off 48 | use-isnan: error 49 | valid-jsdoc: off 50 | valid-typeof: error 51 | 52 | # Best Practices 53 | accessor-pairs: error 54 | array-callback-return: off 55 | block-scoped-var: off 56 | class-methods-use-this: off 57 | complexity: 58 | - error 59 | - 8 60 | consistent-return: off 61 | curly: off 62 | default-case: off 63 | dot-location: off 64 | dot-notation: off 65 | eqeqeq: error 66 | guard-for-in: error 67 | no-alert: error 68 | no-caller: error 69 | no-case-declarations: error 70 | no-div-regex: error 71 | no-else-return: off 72 | no-empty-function: off 73 | no-empty-pattern: error 74 | no-eq-null: error 75 | no-eval: error 76 | no-extend-native: error 77 | no-extra-bind: error 78 | no-extra-label: off 79 | no-fallthrough: error 80 | no-floating-decimal: off 81 | no-global-assign: off 82 | no-implicit-coercion: off 83 | no-implied-eval: error 84 | no-invalid-this: off 85 | no-iterator: error 86 | no-labels: 87 | - error 88 | - allowLoop: true 89 | allowSwitch: true 90 | no-lone-blocks: error 91 | no-loop-func: error 92 | no-magic-number: off 93 | no-multi-spaces: off 94 | no-multi-str: off 95 | no-native-reassign: error 96 | no-new-func: error 97 | no-new-wrappers: error 98 | no-new: error 99 | no-octal-escape: error 100 | no-octal: error 101 | no-param-reassign: off 102 | no-proto: error 103 | no-redeclare: error 104 | no-restricted-properties: off 105 | no-return-assign: error 106 | no-return-await: off 107 | no-script-url: error 108 | no-self-assign: off 109 | no-self-compare: error 110 | no-sequences: off 111 | no-throw-literal: off 112 | no-unmodified-loop-condition: off 113 | no-unused-expressions: error 114 | no-unused-labels: off 115 | no-useless-call: error 116 | no-useless-concat: error 117 | no-useless-escape: off 118 | no-useless-return: off 119 | no-void: error 120 | no-warning-comments: off 121 | no-with: error 122 | prefer-promise-reject-errors: off 123 | radix: error 124 | require-await: off 125 | vars-on-top: off 126 | wrap-iife: error 127 | yoda: off 128 | 129 | # Strict 130 | strict: off 131 | 132 | # Variables 133 | init-declarations: off 134 | no-catch-shadow: error 135 | no-delete-var: error 136 | no-label-var: error 137 | no-restricted-globals: off 138 | no-shadow-restricted-names: error 139 | no-shadow: off 140 | no-undef-init: error 141 | no-undef: off 142 | no-undefined: off 143 | no-unused-vars: off 144 | no-use-before-define: off 145 | 146 | # Node.js and CommonJS 147 | callback-return: error 148 | global-require: off 149 | handle-callback-err: error 150 | no-mixed-requires: off 151 | no-new-require: off 152 | no-path-concat: error 153 | no-process-env: off 154 | no-process-exit: error 155 | no-restricted-modules: off 156 | no-sync: off 157 | 158 | # Stylistic Issues 159 | array-bracket-spacing: off 160 | block-spacing: off 161 | brace-style: off 162 | camelcase: off 163 | capitalized-comments: off 164 | comma-dangle: off 165 | comma-spacing: off 166 | comma-style: off 167 | computed-property-spacing: off 168 | consistent-this: off 169 | eol-last: off 170 | func-call-spacing: off 171 | func-name-matching: off 172 | func-names: off 173 | func-style: off 174 | id-length: off 175 | id-match: off 176 | indent: off 177 | jsx-quotes: off 178 | key-spacing: off 179 | keyword-spacing: off 180 | line-comment-position: off 181 | linebreak-style: off 182 | lines-around-comment: off 183 | lines-around-directive: off 184 | max-depth: off 185 | max-len: off 186 | max-nested-callbacks: off 187 | max-params: off 188 | max-statements-per-line: off 189 | max-statements: 190 | - error 191 | - 50 192 | multiline-ternary: off 193 | new-cap: off 194 | new-parens: off 195 | newline-after-var: off 196 | newline-before-return: off 197 | newline-per-chained-call: off 198 | no-array-constructor: off 199 | no-bitwise: off 200 | no-continue: off 201 | no-inline-comments: off 202 | no-lonely-if: off 203 | no-mixed-operators: off 204 | no-mixed-spaces-and-tabs: off 205 | no-multi-assign: off 206 | no-multiple-empty-lines: off 207 | no-negated-condition: off 208 | no-nested-ternary: off 209 | no-new-object: off 210 | no-plusplus: off 211 | no-restricted-syntax: off 212 | no-spaced-func: off 213 | no-tabs: off 214 | no-ternary: off 215 | no-trailing-spaces: off 216 | no-underscore-dangle: off 217 | no-unneeded-ternary: off 218 | object-curly-newline: off 219 | object-curly-spacing: off 220 | object-property-newline: off 221 | one-var-declaration-per-line: off 222 | one-var: off 223 | operator-assignment: off 224 | operator-linebreak: off 225 | padded-blocks: off 226 | quote-props: off 227 | quotes: off 228 | require-jsdoc: off 229 | semi-spacing: off 230 | semi: off 231 | sort-keys: off 232 | sort-vars: off 233 | space-before-blocks: off 234 | space-before-function-paren: off 235 | space-in-parens: off 236 | space-infix-ops: off 237 | space-unary-ops: off 238 | spaced-comment: off 239 | template-tag-spacing: off 240 | unicode-bom: off 241 | wrap-regex: off 242 | 243 | # ECMAScript 6 244 | arrow-body-style: off 245 | arrow-parens: off 246 | arrow-spacing: off 247 | constructor-super: off 248 | generator-star-spacing: off 249 | no-class-assign: off 250 | no-confusing-arrow: off 251 | no-const-assign: off 252 | no-dupe-class-members: off 253 | no-duplicate-imports: off 254 | no-new-symbol: off 255 | no-restricted-imports: off 256 | no-this-before-super: off 257 | no-useless-computed-key: off 258 | no-useless-constructor: off 259 | no-useless-rename: off 260 | no-var: off 261 | object-shorthand: off 262 | prefer-arrow-callback: off 263 | prefer-const: off 264 | prefer-destructuring: off 265 | prefer-numeric-literals: off 266 | prefer-rest-params: off 267 | prefer-reflect: off 268 | prefer-spread: off 269 | prefer-template: off 270 | require-yield: off 271 | rest-spread-spacing: off 272 | sort-imports: off 273 | symbol-description: off 274 | template-curly-spacing: off 275 | yield-star-spacing: off 276 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | .idea 4 | web.config 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | language: node_js 4 | notifications: 5 | email: false 6 | node_js: 7 | - "6" 8 | 9 | env: 10 | - ANGULAR_VERSION=1.3.20 11 | - ANGULAR_VERSION=1.4.14 12 | - ANGULAR_VERSION=1.5.11 13 | - ANGULAR_VERSION=1.6.5 14 | 15 | before_install: 16 | - export CHROME_BIN=/usr/bin/google-chrome 17 | - export DISPLAY=:99.0 18 | - sh -e /etc/init.d/xvfb start 19 | - sudo apt-get update 20 | - sudo apt-get install -y libappindicator1 fonts-liberation 21 | - wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 22 | - sudo dpkg -i google-chrome*.deb 23 | - npm install -g json 24 | - json -I -f package.json -e 'this.dependencies.angular="'$ANGULAR_VERSION'"' 25 | - json -I -f bower.json -e 'this.dependencies.angular="'$ANGULAR_VERSION'"' 26 | 27 | before_script: 28 | - grunt connect:test:keepalive & 29 | - npm install -g bower 30 | - bower install 31 | 32 | script: 33 | - npm test 34 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | This is a summary of the changes. For a full list of changes see https://github.com/ruhley/angular-color-picker/releases. 4 | 5 | ## v3.4.8 6 | 7 | #### Breaking Changes 8 | * None 9 | 10 | #### New Features 11 | * Feature #176 - Adding `dynamicHue`, `dynamicSaturation`, `dynamicLightness`, and `dynamicAlpha` options for the sliders 12 | 13 | #### Bug Fixes 14 | * None 15 | 16 | ## v3.4.7 17 | 18 | #### Breaking Changes 19 | * None 20 | 21 | #### New Features 22 | * None 23 | 24 | #### Bug Fixes 25 | * Fixing up clear and reset buttons for initial values that are not set when color picker is initialised 26 | 27 | ## v3.4.6 28 | 29 | #### Breaking Changes 30 | * None 31 | 32 | #### New Features 33 | * None 34 | 35 | #### Bug Fixes 36 | * Bug #170 - Internal model not updating when changed programmatically 37 | 38 | ## v3.4.5 39 | 40 | #### Breaking Changes 41 | * None 42 | 43 | #### New Features 44 | * Call update function when closing popup 45 | * Rewrote some sections to reduce code duplication and file size by over 10% 46 | 47 | #### Bug Fixes 48 | * Bug #146 - Sliders no longer lose position when going to black or white 49 | * Bug #173 - Unable to Use hexString Format with restrictToFormat 50 | * Bug #174 - Clicking on swatch when disabled still opens popup 51 | 52 | ## v3.4.4 53 | 54 | #### Breaking Changes 55 | * None 56 | 57 | #### New Features 58 | * None 59 | 60 | #### Bug Fixes 61 | * Bug #169 - Initial colors could be wrong 62 | 63 | ## v3.4.3 64 | 65 | #### Breaking Changes 66 | * None 67 | 68 | #### New Features 69 | * None 70 | 71 | #### Bug Fixes 72 | * Bug #167 - Cannot read property 'updateOn' of undefined `ngModelOptions` 73 | * Fixing up getterSetter = true setting internal ngModel to a function 74 | 75 | ## v3.4.2 76 | 77 | #### Breaking Changes 78 | * None 79 | 80 | #### New Features 81 | * Feature #160 - Support `ng-model-options="{getterSetter:true}"` 82 | * Feature #164 - Add `preserveInputFormat` option to control whether or not a valid input color of a different format should change to the configured format. For a visual explanation see https://github.com/ruhley/angular-color-picker/pull/164 83 | 84 | #### Bug Fixes 85 | * Bug #161 - Format option is now case insensitive 86 | 87 | ## v3.4.1 88 | 89 | #### Breaking Changes 90 | * None 91 | 92 | #### New Features 93 | * None 94 | 95 | #### Bug Fixes 96 | * Bug #159 - Fixing slider positioning in grid 97 | 98 | ## v3.4.0 99 | 100 | #### Breaking Changes 101 | * None 102 | 103 | #### New Features 104 | * Feature #158 - New option for `horizontal` sliders 105 | 106 | #### Bug Fixes 107 | * None 108 | 109 | ## v3.3.0 110 | 111 | #### Breaking Changes 112 | * `hex` and `hex8` formats are now returning the hex value without the hash `#` character. 113 | 114 | #### New Features 115 | * Now supporting values with and without the `#` for both hex and hex8 formats. 116 | 117 | #### Bug Fixes 118 | * None 119 | 120 | ## v3.2.1 121 | 122 | #### Breaking Changes 123 | * None 124 | 125 | #### New Features 126 | * None 127 | 128 | #### Bug Fixes 129 | * Bug #153 Hue selector reset to 0 after closing picker and reopening 130 | * Bug #154 Conflict with angular animate 131 | 132 | ## v3.2.0 133 | 134 | #### Breaking Changes 135 | * None 136 | 137 | #### New Features 138 | * Feature #149 New `allowEmpty` option for validation 139 | 140 | #### Bug Fixes 141 | * Bug #150 Field wasn't always being set to dirty 142 | * Bug #152 Improve slider background colors to be more accurate 143 | * Bug #149 Fix validation field being set to `undefined` 144 | 145 | ## v3.1.2 146 | 147 | #### Breaking Changes 148 | * None 149 | 150 | #### New Features 151 | * None 152 | 153 | #### Bug Fixes 154 | * Bug #148 Color picker hue looks empty on IE 155 | 156 | ## v3.1.1 157 | 158 | #### Breaking Changes 159 | * None 160 | 161 | #### New Features 162 | * None 163 | 164 | #### Bug Fixes 165 | * Bug #147 Switching from focus/blur to focusin/focusout for IE compatibility - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/101237/ 166 | 167 | ## v3.1.0 168 | 169 | #### Breaking Changes 170 | * Changing `input_class` to camel case `inputClass` to match the other options 171 | 172 | #### New Features 173 | * Feature #145 New `restrictToFormat` option 174 | 175 | #### Bug Fixes 176 | * Bug #144 remove color string limit of 4 characters 177 | 178 | ## v3.0.1 179 | 180 | #### Breaking Changes 181 | * None 182 | 183 | #### New Features 184 | * None 185 | 186 | #### Bug Fixes 187 | * Bug #142 Explicitly specify that saturation and lightness are percentages 188 | * Bug #143 Gradient shown below picker in Firefox 189 | 190 | ## v3.0.0 191 | 192 | #### Breaking Changes 193 | * Removed the bootstrap `form-control` class from the input box. You can add it to all color pickers again using the `ColorPickerOptions` decorator. 194 | * The hue and saturation controls are now no longer hidden if the round option is changed. 195 | 196 | #### New Features 197 | * New `input_class` option 198 | * The styles of all the controls now change when the values of other controls change 199 | * Optimised the css to be 1/4 of the file size 200 | * Added `raw` format option 201 | 202 | #### Bug Fixes 203 | * #136 swatch color not matching picker color 204 | * #138 missing qoutes within template 205 | 206 | ## v2.7.1 207 | 208 | #### Breaking Changes 209 | * None 210 | 211 | #### New Features 212 | * None 213 | 214 | #### Bug Fixes 215 | * Bug #127 add default lightness for round color picker 216 | 217 | ## v2.7.0 218 | 219 | #### Breaking Changes 220 | * None 221 | 222 | #### New Features 223 | * Feature #126 Add open/closed class 224 | * Feature #125 add show/hide control 225 | 226 | #### Bug Fixes 227 | * None 228 | 229 | ## v2.6.2 230 | 231 | #### Breaking Changes 232 | * None 233 | 234 | #### New Features 235 | * None 236 | 237 | #### Bug Fixes 238 | * Bug #124 remove some rounding that could interfere when translating between color types 239 | 240 | ## v2.6.1 241 | 242 | #### Breaking Changes 243 | * None 244 | 245 | #### New Features 246 | * None 247 | 248 | #### Bug Fixes 249 | * Bug #123 Add type to buttons to not interfere with form submit buttons 250 | 251 | ## v2.6.0 252 | 253 | #### Breaking Changes 254 | * None 255 | 256 | #### New Features 257 | * New saturation and lightness options 258 | 259 | #### Bug Fixes 260 | * Bug #120 - Set $touched on blur 261 | * Fixing up color calculation in the differences between square and round 262 | 263 | ## v2.5.0 264 | 265 | #### Breaking Changes 266 | * None 267 | 268 | #### New Features 269 | * Improvement #116 Allow access to $scope 270 | 271 | #### Bug Fixes 272 | * None 273 | 274 | ## v2.4.8 275 | 276 | #### Breaking Changes 277 | * None 278 | 279 | #### New Features 280 | * None 281 | 282 | #### Bug Fixes 283 | * Bug #115 - Touch events not getting proper position 284 | 285 | ## v2.4.7 286 | 287 | #### Breaking Changes 288 | * None 289 | 290 | #### New Features 291 | * Pressing escape will close the popup panel 292 | 293 | #### Bug Fixes 294 | * Bug #113 - Tab focus opens panel, tab blur does not close it 295 | 296 | ## v2.4.6 297 | 298 | #### Breaking Changes 299 | * None 300 | 301 | #### New Features 302 | * None 303 | 304 | #### Bug Fixes 305 | * Bug #109 - Properly remove event listeners on destroy 306 | 307 | ## v2.4.5 308 | 309 | #### Breaking Changes 310 | * None 311 | 312 | #### New Features 313 | * Added `id` and `name` to the options object 314 | 315 | #### Bug Fixes 316 | * None 317 | 318 | ## v2.4.4 319 | 320 | #### Breaking Changes 321 | * None 322 | 323 | #### New Features 324 | * None 325 | 326 | #### Bug Fixes 327 | * Bug - First change event was not firing if mouse drag 328 | 329 | ## v2.4.3 330 | 331 | #### Breaking Changes 332 | * None 333 | 334 | #### New Features 335 | * None 336 | 337 | #### Bug Fixes 338 | * Bug #103 error creating options if none provided 339 | 340 | ## v2.4.2 341 | 342 | #### Breaking Changes 343 | * None 344 | 345 | #### New Features 346 | * None 347 | 348 | #### Bug Fixes 349 | * Bug #102 non assign error if options was set in html 350 | 351 | ## v2.4.1 352 | 353 | #### Breaking Changes 354 | * None 355 | 356 | #### New Features 357 | * New `required` option 358 | 359 | #### Bug Fixes 360 | * None 361 | 362 | ## v2.4.0 363 | 364 | #### Breaking Changes 365 | * None 366 | 367 | #### New Features 368 | * New `ColorPickerOptions` decorator 369 | 370 | #### Bug Fixes 371 | * Add import for `tinycolor` for webpack 372 | 373 | ## v2.3.0 374 | 375 | #### Breaking Changes 376 | * None 377 | 378 | #### New Features 379 | * New `round` option to show a round color picker 380 | 381 | #### Bug Fixes 382 | * None 383 | 384 | ## v2.2.0 385 | 386 | #### Breaking Changes 387 | * None 388 | 389 | #### New Features 390 | * New `hue` option to show or hide the hue selector 391 | * New `close`, `clear` and `reset` options to show extra buttons 392 | 393 | #### Bug Fixes 394 | * Bug #82 Support touch events 395 | 396 | ## v2.1.6 397 | 398 | #### Breaking Changes 399 | * None 400 | 401 | #### New Features 402 | * None 403 | 404 | #### Bug Fixes 405 | * Bug #92 Fire click would trigger onChange twice 406 | 407 | ## v2.1.5 408 | 409 | #### Breaking Changes 410 | * None 411 | 412 | #### New Features 413 | * None 414 | 415 | #### Bug Fixes 416 | * Bug #91 setDirty being called on instantiation 417 | 418 | ## v2.1.4 419 | 420 | #### Breaking Changes 421 | * None 422 | 423 | #### New Features 424 | * New `placeholder` option 425 | 426 | #### Bug Fixes 427 | * None 428 | 429 | ## v2.1.3 430 | 431 | #### Breaking Changes 432 | * None 433 | 434 | #### New Features 435 | * None 436 | 437 | #### Bug Fixes 438 | * Don't presume a default color 439 | 440 | ## v2.1.2 441 | 442 | #### Breaking Changes 443 | * None 444 | 445 | #### New Features 446 | * None 447 | 448 | #### Bug Fixes 449 | * Delaying init until directive link function, to fix a bug in complex multi color picker pages 450 | 451 | ## v2.1.1 452 | 453 | #### Breaking Changes 454 | * None 455 | 456 | #### New Features 457 | * None 458 | 459 | #### Bug Fixes 460 | * #87 fixing onBlur and onClose 461 | * #88 Fixing hue updating when moving in grid on rgb and hex 462 | 463 | ## v2.1.0 464 | 465 | #### Breaking Changes 466 | * Seperated the `api` into `api` and `eventApi`. This allows for shared event handling 467 | * `api` now has `open`, `close`, and `getElement` 468 | * `eventApi` now has `onOpen`, `onClose`, `onChange`, `onBlur`, and `onDestroy` 469 | 470 | #### New Features 471 | * `api` has a new `getElement` function 472 | * `eventApi` functions now all have `api` and `color` passed in as the first arguments, and `event` if it is available 473 | 474 | #### Bug Fixes 475 | * None 476 | 477 | ## v2.0.0 478 | 479 | #### Breaking Changes 480 | 481 | * All the directive bindings are now passed in as an `options` object. The functionality has stayed the same and the names are the same but without `color-picker` at the front (e.g. `color-pick-swatch-pos` is now just `swatchPos`). 482 | 483 | #### New Features 484 | * New `api` binding is available. It exposes `open` and `close` and can handle `onOpen`, `onClose`, `onChange`, `onBlur`, and `onDestroy` events. 485 | 486 | #### Bug Fixes 487 | * None 488 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at https://github.com/ruhley/angular-color-picker. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Issues 2 | 3 | Think you've found a bug or have a new feature to suggest? [Let us know!](https://github.com/ruhley/angular-color-picker/issues) 4 | 5 | ## Reporting a Bug 6 | 1. Update to the most recent master release if possible. We may have already 7 | fixed your bug. 8 | 9 | 2. Search for similar issues. It's possible somebody has encountered 10 | this bug already. 11 | 12 | 3. Provide JSFiddle or JSBin demo that specifically shows the problem. This 13 | demo should be fully operational with the exception of the bug you want to 14 | demonstrate. The more pared down, the better. 15 | 16 | If it is not possible to produce a fiddle, please make sure you provide very 17 | specific steps to reproduce the error. If we cannot reproduce it, we will 18 | close the ticket. 19 | 20 | The more information you provide, the easier it is for us to validate that 21 | there is a bug and the faster we'll be able to take action. 22 | 23 | ## Requesting a Feature 24 | 25 | 1. Search Issues for similar feature requests. It's possible somebody has 26 | already asked for this feature or provided a pull request that we're still 27 | discussing. 28 | 29 | 2. Provide a clear and detailed explanation of the feature you want and why 30 | it's important to add. Keep in mind that we want features that will be useful 31 | to the majority of our users and not just a small subset. 32 | 33 | 3. If the feature is complex, consider writing some initial documentation for 34 | it. If we do end up accepting the feature it will need to be documented and 35 | this will also help us to understand it better ourselves. 36 | 37 | 4. Attempt a Pull Request. If you're at all able, start writing some code. We 38 | always have more work to do than time to do it. If you can write some code 39 | then that will speed the process along. 40 | 41 | # Pull Requests 42 | 43 | We love pull requests. Here's a quick guide: 44 | 45 | 1. Fork the repo. 46 | 47 | 2. Update files only in lib 48 | 49 | 3. Add a test for your change. Only refactoring and documentation changes 50 | require no new tests. If you are adding functionality or fixing a bug, we need 51 | a test! 52 | 53 | 3. Make the test pass. 54 | 55 | 5. Build the dist folder following RELEASE.md 56 | 57 | 4. Commit your changes. Please use an appropriate commit prefix. 58 | If your pull request fixes an issue specify it in the commit message. 59 | 60 | 5. Push to your fork and submit a pull request. Please provide us with some 61 | explanation of why you made the changes you made. For new features make sure to 62 | explain a standard use case to us. 63 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | 'use strict'; 4 | 5 | module.exports = function (grunt) { 6 | // if this variable exists we have already set up grunt 7 | if (!grunt || !grunt.config || !grunt.config.data || !grunt.config.data.config || !grunt.config.data.config.dev) { 8 | // Load grunt modules from package.json automatically 9 | require('load-grunt-tasks')(grunt); 10 | 11 | // config variables, these are accessible like '<%= config.dev %>' 12 | var gruntConfig = {config: { 13 | // folders 14 | src: 'src', 15 | dist: 'dist', 16 | tests: 'tests', 17 | grunt: 'grunt', 18 | scripts: 'scripts', 19 | styles: 'styles', 20 | // misc 21 | filename: 'angularjs-color-picker', 22 | pkg: grunt.file.readJSON('package.json') 23 | }}; 24 | 25 | // loads tasks in the 'grunt' folder 26 | grunt.loadTasks('grunt'); 27 | // loads task options in the 'grunt/options' folder 28 | grunt.initConfig(grunt.util._.extend(gruntConfig, gruntLoadConfig('./grunt/options/', grunt))); 29 | } 30 | }; 31 | 32 | function gruntLoadConfig(path, grunt) { 33 | var glob = require('glob'); 34 | var object = {}; 35 | var key; 36 | 37 | glob.sync('*', {cwd: path}).forEach(function(option) { 38 | key = option.replace(/\.js$/,''); 39 | object[key] = require(process.cwd() + path.replace('.', '') + option); 40 | if (typeof object[key] === 'function') { 41 | object[key] = object[key](grunt); 42 | } 43 | }); 44 | 45 | return object; 46 | } 47 | }(module)); 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 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 | # Angular Color Picker 2 | 3 | Vanilla AngularJS Color Picker Directive with no requirement on jQuery 4 | 5 | [![Build Status](https://travis-ci.org/ruhley/angular-color-picker.svg?branch=master)](https://travis-ci.org/ruhley/angular-color-picker) 6 | [![Code Climate](https://lima.codeclimate.com/github/ruhley/angular-color-picker/badges/gpa.svg)](https://lima.codeclimate.com/github/ruhley/angular-color-picker) 7 | 8 | ## Demo 9 | https://ruhley.github.io/angular-color-picker/ 10 | 11 | ## Installation 12 | 13 | #### Bower 14 | 15 | ```shell 16 | bower install angularjs-color-picker --save 17 | ``` 18 | 19 | #### Npm 20 | ```shell 21 | npm install angularjs-color-picker --save 22 | ``` 23 | 24 | #### Usage 25 | 26 | * Include files 27 | 28 | * Bower 29 | 30 | ```html 31 | 32 | 33 | 34 | 35 | 36 | 37 | ``` 38 | 39 | * Node 40 | 41 | ```html 42 | 43 | 44 | 45 | 46 | 47 | 48 | ``` 49 | 50 | 51 | * Add the module to your app 52 | ```javascript 53 | angular.module('app', ['color.picker']); 54 | ``` 55 | 56 | * Include in your view 57 | ```html 58 | 59 | ``` 60 | 61 | ## Options 62 | 63 | HTML - Only ```ng-model``` is required. If supplying an api it must be a unique object per color picker. However the event api can be shared among color pickers. 64 | 65 | ```html 66 | 72 | ``` 73 | Javascript 74 | 75 | ```js 76 | $scope.color = '#FF0000'; 77 | 78 | // options - if a list is given then choose one of the items. The first item in the list will be the default 79 | $scope.options = { 80 | // html attributes 81 | required: [false, true], 82 | disabled: [false, true], 83 | placeholder: '', 84 | inputClass: '', 85 | id: undefined, 86 | name: undefined, 87 | // validation 88 | restrictToFormat: [false, true], 89 | preserveInputFormat: [false, true], 90 | allowEmpty: [false, true], 91 | // color 92 | format: ['hsl', 'hsv', 'rgb', 'hex', 'hexString', 'hex8', 'hex8String', 'raw'], 93 | case: ['upper', 'lower'], 94 | // sliders 95 | hue: [true, false], 96 | saturation: [false, true], 97 | lightness: [false, true], // Note: In the square mode this is HSV and in round mode this is HSL 98 | alpha: [true, false], 99 | dynamicHue: [true, false], 100 | dynamicSaturation: [true, false], 101 | dynamicLightness: [true, false], 102 | dynamicAlpha: [true, false], 103 | // swatch 104 | swatch: [true, false], 105 | swatchPos: ['left', 'right'], 106 | swatchBootstrap: [true, false], 107 | swatchOnly: [true, false], 108 | // popup 109 | round: [false, true], 110 | pos: ['bottom left', 'bottom right', 'top left', 'top right'], 111 | inline: [false, true], 112 | horizontal: [false, true], 113 | // show/hide 114 | show: { 115 | swatch: [true, false], 116 | focus: [true, false], 117 | }, 118 | hide: { 119 | blur: [true, false], 120 | escape: [true, false], 121 | click: [true, false], 122 | }, 123 | // buttons 124 | close: { 125 | show: [false, true], 126 | label: 'Close', 127 | class: '', 128 | }, 129 | clear: { 130 | show: [false, true], 131 | label: 'Clear', 132 | class: '', 133 | }, 134 | reset: { 135 | show: [false, true], 136 | label: 'Reset', 137 | class: '', 138 | }, 139 | }; 140 | 141 | // exposed api functions 142 | $scope.api.open(); // opens the popup 143 | $scope.api.close(); // closes the popup 144 | $scope.api.clear(); // removes value 145 | $scope.api.reset(); // resets color value to original value 146 | $scope.api.getElement(); // returns the wrapping element 147 | $scope.api.getScope(); // returns the color picker $scope 148 | 149 | // api event handlers 150 | $scope.eventApi = { 151 | onChange: function(api, color, $event) {}, 152 | onBlur: function(api, color, $event) {}, 153 | onOpen: function(api, color, $event) {}, 154 | onClose: function(api, color, $event) {}, 155 | onClear: function(api, color, $event) {}, 156 | onReset: function(api, color, $event) {}, 157 | onDestroy: function(api, color) {}, 158 | }; 159 | 160 | // decorator - all variables in options can be globally overridden here 161 | angular 162 | .module('app', ['color.picker']) 163 | .config(function($provide) { 164 | $provide.decorator('ColorPickerOptions', function($delegate) { 165 | var options = angular.copy($delegate); 166 | options.round = true; 167 | options.alpha = false; 168 | options.format = 'hex'; 169 | return options; 170 | }); 171 | }); 172 | ``` 173 | 174 | ## Requirements 175 | 176 | * angularjs (v1.3 and higher) 177 | * tinycolor.js (18.8 KB minified) 178 | 179 | NO requirement for jQuery! 180 | 181 | ## Inspiration 182 | 183 | Inspiration and code taken from projects like 184 | * http://kaihenzler.github.io/angular-minicolors/ 185 | * http://mjolnic.github.io/bootstrap-colorpicker/ 186 | * https://github.com/buberdds/angular-bootstrap-colorpicker/ 187 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release 2 | 3 | #### Versioning should follow [Semantic Versioning](http://semver.org/) 4 | 5 | The build steps to releasing a new version. Before you can do this you need to to make sure the node packages are up to date - ``` npm update ``` 6 | 7 | * Commit and push all changes with a meaningful message 8 | * Update version in bower.json and package.json 9 | * Build the dist files - ``` grunt build ``` 10 | * Run `npm test` to make sure all the tests pass 11 | * Update CHANGELOG.md 12 | * Update documentation if needed 13 | * Commit and push with the message "Bumping to v\*.\*.\*" 14 | * [Create a new release](https://github.com/ruhley/angular-color-picker/releases/new) 15 | * Tag version is v\*.\*.\* 16 | * Release title is "Angular Color Picker v\*.\*.\*" 17 | * The comment section should be a list of commits and the changes the commit made. See below for an example 18 | * If it is under v1.0.0 then mark "This is a pre-release" as true 19 | * Publish to npm ```npm publish``` 20 | 21 | 22 | ## Example github release comment 23 | Changelog: 24 | 25 | * 33efce58357b654bc3ec7c5d59e5b36503d5bb13 - [BUGFIX] Fixing spaces in automatic api endpoint 26 | * ba36c1d5e3a30c6de295771adb59a51ce151c25b - [BUGFIX] Fixing #1: Improve bower.json ignore 27 | * 93e89af673509d075dfc8c6137d97645ab392646 - Bumping to v0.1.2 28 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-color-picker", 3 | "description": "Color Picker Directive For AngularJS", 4 | "version": "3.4.8", 5 | "homepage": "https://github.com/ruhley/angular-color-picker", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/ruhley/angular-color-picker.git" 9 | }, 10 | "authors": [ 11 | "ruhley " 12 | ], 13 | "contributors": [ 14 | "Benjamin Orozco " 15 | ], 16 | "main": [ 17 | "dist/angularjs-color-picker.js", 18 | "dist/angularjs-color-picker.css" 19 | ], 20 | "moduleType": [ 21 | "globals" 22 | ], 23 | "keywords": [ 24 | "Color", 25 | "Color Picker", 26 | "Directive", 27 | "Angular", 28 | "AngularJS" 29 | ], 30 | "license": "MIT", 31 | "ignore": [ 32 | "*", 33 | "!dist/", 34 | "!dist/*", 35 | "!dist/themes/", 36 | "!dist/themes/*" 37 | ], 38 | "dependencies": { 39 | "tinycolor": "^1.3.0", 40 | "angular": "^1.3.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /dist/angularjs-color-picker.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * angularjs-color-picker v3.4.8 3 | * https://github.com/ruhley/angular-color-picker/ 4 | * 5 | * Copyright 2017 ruhley 6 | * 7 | * 2017-10-06 09:52:03 8 | * 9 | */.color-picker-wrapper{position:relative}.color-picker-wrapper .color-picker-input-wrapper{display:table;position:relative}.color-picker-wrapper .input-group{position:relative;border-collapse:separate}.color-picker-wrapper .input-group .color-picker-input,.color-picker-wrapper .input-group .input-group-addon{display:table-cell}.color-picker-wrapper .input-group .color-picker-input{position:relative;z-index:2;float:left;margin-bottom:0}.color-picker-wrapper .input-group .input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc}.color-picker-wrapper .input-group .input-group-addon:first-child{border-right-width:0}.color-picker-wrapper .input-group .input-group-addon:last-child{border-left-width:0}.color-picker-wrapper .input-group .color-picker-input-swatch{padding-left:12px}.color-picker-wrapper .color-picker-input-swatch{padding-left:36px}.color-picker-wrapper .color-picker-swatch{cursor:pointer;z-index:3}.color-picker-wrapper .color-picker-swatch:not(.input-group-addon){position:absolute;top:3px;width:28px;height:70%;box-sizing:border-box;border-radius:3px;vertical-align:middle;background-position:-80px 0;border:solid 1px #ccc;padding:0;margin:0;display:inline-block}.color-picker-wrapper .color-picker-swatch:not(.input-group-addon).color-picker-swatch-left{left:3px}.color-picker-wrapper .color-picker-swatch:not(.input-group-addon).color-picker-swatch-right{right:3px}.color-picker-wrapper .color-picker-panel{position:absolute;background:#fff;border:solid 1px #ccc;box-shadow:0 0 20px rgba(0,0,0,.5);z-index:99999;width:150px;table-layout:fixed;border:1px solid #fff;padding-right:1px;box-sizing:content-box}.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper{display:table;width:100%}.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row{display:table-row}.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-overlay{position:absolute;width:100%;height:150px;top:0;left:0;z-index:2}.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-grid,.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-hue,.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-lightness,.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-opacity,.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-saturation{background-image:linear-gradient(45deg,grey 25%,transparent 25%),linear-gradient(-45deg,grey 25%,transparent 25%),linear-gradient(45deg,transparent 75%,grey 75%),linear-gradient(-45deg,transparent 75%,grey 75%);background-size:10px 10px;background-position:0 0,0 5px,5px -5px,-5px 0}.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-hue,.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-lightness,.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-opacity,.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-saturation{display:table-cell;position:relative;left:1px;width:20px;background-color:#fff;cursor:row-resize}.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-slider{position:absolute;top:0;left:0;width:18px;height:2px;background:#fff;border:solid 1px #000;box-sizing:content-box;margin-top:-1px;z-index:3}.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-grid{display:table-cell;position:relative;width:150px;height:150px;cursor:crosshair}.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-grid .color-picker-grid-inner{width:150px;height:150px;z-index:9}.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-grid .color-picker-overlay{background-image:url(data:image/png;base64,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);pointer-events:none}.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-grid .color-picker-picker{position:absolute;top:70px;left:70px;width:12px;height:12px;border:solid 1px #000;border-radius:10px;margin-top:-6px;margin-left:-6px;background:0 0;box-sizing:content-box;z-index:99}.color-picker-wrapper .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-grid .color-picker-picker>div{position:absolute;top:0;left:0;width:8px;height:8px;border-radius:8px;border:solid 2px #fff;box-sizing:content-box}.color-picker-wrapper .color-picker-panel .color-picker-actions .color-picker-action{width:calc(33.3333% - 6px);margin:3px}.color-picker-wrapper .color-picker-panel.color-picker-show-inline{position:relative}.color-picker-wrapper .color-picker-panel.color-picker-show-hue.color-picker-show-saturation.color-picker-show-lightness.color-picker-show-alpha{width:230px}.color-picker-wrapper .color-picker-panel.color-picker-show-hue.color-picker-show-saturation.color-picker-show-lightness{width:210px}.color-picker-wrapper .color-picker-panel.color-picker-show-hue.color-picker-show-saturation.color-picker-show-alpha{width:210px}.color-picker-wrapper .color-picker-panel.color-picker-show-hue.color-picker-show-lightness.color-picker-show-alpha{width:210px}.color-picker-wrapper .color-picker-panel.color-picker-show-hue.color-picker-show-saturation{width:190px}.color-picker-wrapper .color-picker-panel.color-picker-show-hue.color-picker-show-lightness{width:190px}.color-picker-wrapper .color-picker-panel.color-picker-show-hue.color-picker-show-alpha{width:190px}.color-picker-wrapper .color-picker-panel.color-picker-show-saturation.color-picker-show-alpha{width:190px}.color-picker-wrapper .color-picker-panel.color-picker-show-saturation.color-picker-show-lightness{width:190px}.color-picker-wrapper .color-picker-panel.color-picker-show-saturation.color-picker-show-lightness.color-picker-show-alpha{width:210px}.color-picker-wrapper .color-picker-panel.color-picker-show-lightness.color-picker-show-alpha{width:190px}.color-picker-wrapper .color-picker-panel.color-picker-show-hue{width:170px}.color-picker-wrapper .color-picker-panel.color-picker-show-saturation{width:170px}.color-picker-wrapper .color-picker-panel.color-picker-show-lightness{width:170px}.color-picker-wrapper .color-picker-panel.color-picker-show-alpha{width:170px}.color-picker-wrapper .color-picker-panel.color-picker-panel-bottom{top:auto}.color-picker-wrapper .color-picker-panel.color-picker-panel-top{bottom:100%}.color-picker-wrapper .color-picker-panel.color-picker-panel-left{left:0}.color-picker-wrapper .color-picker-panel.color-picker-panel-right{right:0}.color-picker-wrapper .color-picker-panel.color-picker-panel-round .color-picker-grid-wrapper .color-picker-row .color-picker-grid .color-picker-overlay{background-image:url(data:image/png;base64,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);border-radius:50%}.color-picker-wrapper .color-picker-panel.color-picker-panel-round .color-picker-grid-wrapper .color-picker-row .color-picker-grid .color-picker-grid-inner{background-color:#fff}.color-picker-wrapper .color-picker-hidden{display:none}.color-picker-wrapper.color-picker-disabled .color-picker-grid,.color-picker-wrapper.color-picker-disabled .color-picker-hue,.color-picker-wrapper.color-picker-disabled .color-picker-input,.color-picker-wrapper.color-picker-disabled .color-picker-opacity,.color-picker-wrapper.color-picker-disabled .color-picker-swatch{cursor:not-allowed!important}.color-picker-wrapper.color-picker-swatch-only .color-picker-input{padding-left:33px;padding-right:0;width:35px}.color-picker-wrapper.color-picker-swatch-only .input-group .input-group-addon{width:35px;height:100%;border-right:1px solid #ccc}.color-picker-wrapper.color-picker-swatch-only .input-group .input-group-addon:first-child{border-right-width:1px}.color-picker-wrapper.color-picker-swatch-only .input-group .input-group-addon:last-child{border-left-width:1px}.color-picker-wrapper.color-picker-swatch-only .input-group .color-picker-input{padding:0;width:1px;opacity:0;cursor:pointer}.color-picker-wrapper.color-picker-swatch-only .input-group .color-picker-input:focus{outline:0}.color-picker-wrapper.color-picker-closed .color-picker-panel{display:none}.color-picker-wrapper.color-picker-horizontal .color-picker-panel{width:150px!important}.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row{display:block}.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-grid{display:block}.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-hue,.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-lightness,.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-opacity,.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-saturation{cursor:col-resize;display:block;left:0;width:150px;height:20px}.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-hue .color-picker-overlay,.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-lightness .color-picker-overlay,.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-opacity .color-picker-overlay,.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-saturation .color-picker-overlay{height:20px}.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-hue .color-picker-slider,.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-lightness .color-picker-slider,.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-opacity .color-picker-slider,.color-picker-wrapper.color-picker-horizontal .color-picker-panel .color-picker-grid-wrapper .color-picker-row .color-picker-saturation .color-picker-slider{width:2px;height:18px;margin-top:0} -------------------------------------------------------------------------------- /dist/angularjs-color-picker.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * angularjs-color-picker v3.4.8 3 | * https://github.com/ruhley/angular-color-picker/ 4 | * 5 | * Copyright 2017 ruhley 6 | * 7 | * 2017-10-06 09:51:57 8 | * 9 | */ 10 | !function(o,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("tinycolor2")):"function"==typeof define&&define.amd?define(["tinycolor2"],t):o.AngularjsColorPicker=t(o.tinycolor)}(this,function(o){"use strict";function t(o){o.put("template/color-picker/directive.html",'
')}o=o&&o.hasOwnProperty("default")?o.default:o;var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(o){return typeof o}:function(o){return o&&"function"==typeof Symbol&&o.constructor===Symbol&&o!==Symbol.prototype?"symbol":typeof o},i=(function(){function o(o){this.value=o}function t(t){function e(n,r){try{var s=t[n](r),l=s.value;l instanceof o?Promise.resolve(l.value).then(function(o){e("next",o)},function(o){e("throw",o)}):i(s.done?"return":"normal",s.value)}catch(o){i("throw",o)}}function i(o,t){switch(o){case"return":n.resolve({value:t,done:!0});break;case"throw":n.reject(t);break;default:n.resolve({value:t,done:!1})}(n=n.next)?e(n.key,n.arg):r=null}var n,r;this._invoke=function(o,t){return new Promise(function(i,s){var l={key:o,arg:t,resolve:i,reject:s,next:null};r?r=r.next=l:(n=r=l,e(o,t))})},"function"!=typeof t.return&&(this.return=void 0)}"function"==typeof Symbol&&Symbol.asyncIterator&&(t.prototype[Symbol.asyncIterator]=function(){return this}),t.prototype.next=function(o){return this._invoke("next",o)},t.prototype.throw=function(o){return this._invoke("throw",o)},t.prototype.return=function(o){return this._invoke("return",o)}}(),function(o,t){if(!(o instanceof t))throw new TypeError("Cannot call a class as a function")}),n=function(){function o(o,t){for(var e=0;e1?parseFloat(o[1]):NaN,this.updateModel=!0,this.initWatchers(),this.initConfig(),this.initMouseEvents()}},{key:"initConfig",value:function(){this.options||(this.options={}),this.mergeOptions(this.options,this.ColorPickerOptions),this.is_open=this.options.inline,this.options.inline&&(this.options.close.show=!1),this.pickerDimensions={width:150,height:150},this.sliderDimensions={width:this.options.horizontal?this.pickerDimensions.width:20,height:this.options.horizontal?20:this.pickerDimensions.height}}},{key:"mergeOptions",value:function(o,t){for(var i in t)t.hasOwnProperty(i)&&(o&&o.hasOwnProperty(i)?"object"===e(t[i])&&this.mergeOptions(o[i],t[i]):o[i]=t[i])}},{key:"initWatchers",value:function(){var o=this;this.$scope.$watch("AngularColorPickerController.internalNgModel",this.watchInternalNgModel.bind(this)),this.$scope.$watch("AngularColorPickerController.ngModel",this.watchNgModel.bind(this)),this.$scope.$watch("AngularColorPickerController.options.swatchPos",function(t){void 0!==t&&(o.initConfig(),o.$timeout(function(){o.updateSwatchBackground()}))}),this.$scope.$watchGroup(["AngularColorPickerController.options.format","AngularColorPickerController.options.alpha","AngularColorPickerController.options.case","AngularColorPickerController.options.round","AngularColorPickerController.options.restrictToFormat","AngularColorPickerController.options.preserveInputFormat","AngularColorPickerController.options.allowEmpty","AngularColorPickerController.options.horizontal","AngularColorPickerController.options.dynamicHue","AngularColorPickerController.options.dynamicSaturation","AngularColorPickerController.options.dynamicLightness","AngularColorPickerController.options.dynamicAlpha"],function(t){void 0!==t&&(o.initConfig(),o.update())}),this.$scope.$watchGroup(["AngularColorPickerController.options.disabled","AngularColorPickerController.options.swatchBootstrap","AngularColorPickerController.options.swatchOnly","AngularColorPickerController.options.swatch","AngularColorPickerController.options.pos","AngularColorPickerController.options.inline","AngularColorPickerController.options.placeholder"],function(t){void 0!==t&&o.initConfig()}),this.$scope.$watch("AngularColorPickerController.api",this.setupApi.bind(this)),this.$scope.$watch("AngularColorPickerController.swatchColor",this.updateSwatchBackground.bind(this)),this.$scope.$watch("AngularColorPickerController.hue",function(){o.valueUpdate("hue")}),this.$scope.$watch("AngularColorPickerController.saturation",function(){o.valueUpdate("saturation")}),this.$scope.$watch("AngularColorPickerController.lightness",function(){o.valueUpdate("lightness")}),this.$scope.$watch("AngularColorPickerController.opacity",function(){o.valueUpdate("opacity")})}},{key:"watchInternalNgModel",value:function(o,t){this.colorMouse||this.watchNgModelSet(o)}},{key:"watchNgModel",value:function(o,t){void 0===o||this.hasOwnProperty("initialNgModel")||(this.initialNgModel=o),this.checkDirty(o),this.internalNgModel=this.ngModelOptions.getterSetter?this.ngModel():this.ngModel,this.colorMouse||this.watchNgModelSet(o)}},{key:"watchNgModelSet",value:function(t){var e=this;if(void 0!==t&&null!==t){var i=o(t),n=this.isColorValid(i);n&&(this.setColorValue(i),this.updateModel=!1,this.$timeout(function(){e.updateModel=!0})),this.$scope.control[0].$setValidity("color",n)}else null!==t&&""!==t||(this.hue=0,this.saturation=void 0,this.lightness=void 0,this.opacity=void 0),this.swatchColor=""}},{key:"initMouseEvents",value:function(){var o=this,t={mouseDown:this.onMouseDown.bind(this),mouseUp:this.onMouseUp.bind(this),mouseMove:this.onMouseMove.bind(this),keyUp:this.onKeyUp.bind(this)};this.$document.on("mousedown",t.mouseDown),this.$document.on("mouseup",t.mouseUp),this.$document.on("mousemove",t.mouseMove),this.$document.on("touchstart",t.mouseDown),this.$document.on("touchend",t.mouseUp),this.$document.on("touchmove",t.mouseMove),this.$document.on("keyup",t.keyUp),this.find(".color-picker-grid").on("click",function(t){o.onClick("color",t)}),this.find(".color-picker-grid").on("touchend",function(t){o.onClick("color",t)}),this.find(".color-picker-hue").on("click",function(t){o.onClick("hue",t)}),this.find(".color-picker-hue").on("touchend",function(t){o.onClick("hue",t)}),this.find(".color-picker-saturation").on("click",function(t){o.onClick("saturation",t)}),this.find(".color-picker-saturation").on("touchend",function(t){o.onClick("saturation",t)}),this.find(".color-picker-lightness").on("click",function(t){o.onClick("lightness",t)}),this.find(".color-picker-lightness").on("touchend",function(t){o.onClick("lightness",t)}),this.find(".color-picker-opacity").on("click",function(t){o.onClick("opacity",t)}),this.find(".color-picker-opacity").on("touchend",function(t){o.onClick("opacity",t)}),this.find(".color-picker-input").on("focusin",this.onFocus.bind(this)),this.find(".color-picker-input").on("focusout",this.onBlur.bind(this)),this.$scope.$on("$destroy",function(){o.$document.off("mousedown",t.mouseDown),o.$document.off("mouseup",t.mouseUp),o.$document.off("mousemove",t.mouseMove),o.$document.off("touchstart",t.mouseDown),o.$document.off("touchend",t.mouseUp),o.$document.off("touchmove",t.mouseMove),o.$document.off("keyup",t.keyUp),o.eventApiDispatch("onDestroy")})}},{key:"onMouseDown",value:function(o){if(this.has_moused_moved=!1,this.options.disabled||0===this.find(o.target).length)return!0;for(var t=0;tn?this[o]=n:this[o]<0&&(this[o]=0)}},{key:"valueUpdate",value:function(o){if(void 0!==this[o]){if("saturation"===o)this[o+"Pos"]=this[o];else{var t=this.getMaxFromType(o);this[o+"Pos"]=100*(1-this[o]/t)}this[o+"Pos"]<0?this[o+"Pos"]=0:this[o+"Pos"]>100&&(this[o+"Pos"]=100),this.options.round&&(this.getRoundPos(),this.updateRoundPos()),this[o+"PosUpdate"](),this.update()}}},{key:"huePosUpdate",value:function(){var o=angular.element(this.$element[0].querySelector(".color-picker-hue .color-picker-slider"));this.options.horizontal?o.css({left:this.sliderDimensions.width*this.huePos/100+"px",top:0}):o.css({left:0,top:this.sliderDimensions.height*this.huePos/100+"px"})}},{key:"updateHueBackground",value:function(t){var e=this.find(".color-picker-hue .color-picker-overlay"),i=this.options.horizontal?"left":"top",n=this.getColorValue(this.options.dynamicHue),r=this.getColorValue(this.options.dynamicHue),s=this.getColorValue(this.options.dynamicHue),l=this.getColorValue(this.options.dynamicHue),a=this.getColorValue(this.options.dynamicHue),c=this.getColorValue(this.options.dynamicHue),h=this.getColorValue(this.options.dynamicHue);n.h=0,r.h=60,s.h=120,l.h=180,a.h=240,c.h=300,h.h=359,e.css({background:"linear-gradient(to "+i+", "+o(n).toRgbString()+" 0%, "+o(r).toRgbString()+" 17%, "+o(s).toRgbString()+" 33%, "+o(l).toRgbString()+" 50%, "+o(a).toRgbString()+" 67%, "+o(c).toRgbString()+" 83%, "+o(h).toRgbString()+" 100%)"})}},{key:"saturationPosUpdate",value:function(){var o;this.options.round||(o=angular.element(this.$element[0].querySelector(".color-picker-grid .color-picker-picker"))).css({left:this.pickerDimensions.height*this.saturationPos/100+"px"}),o=angular.element(this.$element[0].querySelector(".color-picker-saturation .color-picker-slider")),this.options.horizontal?o.css({left:this.sliderDimensions.width*(100-this.saturationPos)/100+"px",top:0}):o.css({left:0,top:this.sliderDimensions.height*(100-this.saturationPos)/100+"px"})}},{key:"updateSaturationBackground",value:function(t){var e=this.find(".color-picker-saturation .color-picker-overlay"),i=this.options.horizontal?"right":"bottom",n=this.getColorValue(this.options.dynamicSaturation),r=this.getColorValue(this.options.dynamicSaturation);n.s="100%",r.s="0%",e.css({background:"linear-gradient(to "+i+", "+o(n).toRgbString()+" 0%, "+o(r).toRgbString()+" 100%)"})}},{key:"lightnessPosUpdate",value:function(){var o;this.options.round||(o=angular.element(this.$element[0].querySelector(".color-picker-grid .color-picker-picker"))).css({top:this.pickerDimensions.width*this.lightnessPos/100+"px"}),o=angular.element(this.$element[0].querySelector(".color-picker-lightness .color-picker-slider")),this.options.horizontal?o.css({left:this.sliderDimensions.width*this.lightnessPos/100+"px",top:0}):o.css({left:0,top:this.sliderDimensions.height*this.lightnessPos/100+"px"})}},{key:"updateLightnessBackground",value:function(t){var e=this.find(".color-picker-lightness .color-picker-overlay"),i=this.options.horizontal?"right":"bottom",n=this.getColorValue(this.options.dynamicLightness),r=this.getColorValue(this.options.dynamicLightness),s=this.getColorValue(this.options.dynamicLightness);this.options.round?(n.l=100,r.l=50,s.l=0):(n.v=100,r.v=50,s.v=0),e.css({background:"linear-gradient(to "+i+", "+o(n).toRgbString()+" 0%, "+o(r).toRgbString()+" 50%, "+o(s).toRgbString()+" 100%)"})}},{key:"opacityPosUpdate",value:function(){var o=angular.element(this.$element[0].querySelector(".color-picker-opacity .color-picker-slider"));this.options.horizontal?o.css({left:this.sliderDimensions.width*this.opacityPos/100+"px",top:0}):o.css({left:0,top:this.sliderDimensions.height*this.opacityPos/100+"px"})}},{key:"updateOpacityBackground",value:function(t){var e=this.find(".color-picker-opacity .color-picker-overlay"),i=this.options.horizontal?"right":"bottom",n=this.getColorValue(this.options.dynamicAlpha),r=this.getColorValue(this.options.dynamicAlpha);n.a=1,r.a=0,e.css({background:"linear-gradient(to "+i+", "+o(n).toRgbString()+" 0%, "+o(r).toRgbString()+" 100%)"})}},{key:"colorChange",value:function(o){this.stopEvent(o);var t=this.find(".color-picker-grid-inner"),e=this.getEventPos(o),i=this.offset(t);this.options.round?this.colorChangeRound(t,i,e):this.colorChangeSquare(t,i,e)}},{key:"colorChangeRound",value:function(o,t,e){var i=2*(e.pageX-t.left)/o.prop("offsetWidth")-1,n=-2*(e.pageY-t.top)/o.prop("offsetHeight")+1,r=Math.atan2(n,i),s=Math.round(57.29577951308233*r);s<0&&(s+=360),this.hue=s;var l=Math.sqrt(i*i+n*n);l>1?l=1:l<0&&(l=0),this.saturation=100*l,void 0===this.lightness&&(this.lightness=50)}},{key:"colorChangeSquare",value:function(o,t,e){this.saturation=(e.pageX-t.left)/o.prop("offsetWidth")*100,this.lightness=100*(1-(e.pageY-t.top)/o.prop("offsetHeight")),this.saturation>100?this.saturation=100:this.saturation<0&&(this.saturation=0),this.lightness>100?this.lightness=100:this.lightness<0&&(this.lightness=0)}},{key:"updateGridBackground",value:function(t){var e=this.find(".color-picker-grid .color-picker-overlay"),i=this.getColorValue();this.options.round?i.s="0%":(i.s="100%",i.v="100%",i.a=1),e.css({"background-color":o(i).toRgbString(),opacity:t.getAlpha()}),this.find(".color-picker-grid .color-picker-grid-inner").css({opacity:t.getAlpha()})}},{key:"updateSwatchBackground",value:function(){angular.element(this.$element[0].querySelector(".color-picker-swatch")).css({"background-color":this.swatchColor})}},{key:"isColorValid",value:function(o){var t=o.isValid();if(t&&this.options.restrictToFormat&&(t=o.getFormat()===this.getTinyColorFormat()),!t&&this.options.allowEmpty){var e=o.getOriginalInput();void 0!==e&&null!==e&&""!==e||(t=!0)}return t}},{key:"getTinyColorFormat",value:function(){return"hexString"===this.options.format?"hex":"hex8String"===this.options.format?"hex8":this.options.format}},{key:"areAllValuesSet",value:function(){return void 0!==this.hue&&void 0!==this.saturation&&void 0!==this.lightness}},{key:"getColorValue",value:function(){var o=!(arguments.length>0&&void 0!==arguments[0])||arguments[0],t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],e={h:this.hue,s:o?this.saturation+"%":"100%",v:o?this.lightness+"%":"100%"};return this.options.round&&(e={h:this.hue,s:o?this.saturation+"%":"100%",l:o?this.lightness+"%":"50%"}),t&&(e.a=o?this.opacity/100:1),e}},{key:"setColorValue",value:function(o){var t=!this.anyMouseEvents(),e=this.options.round?o.toHsl():o.toHsv();(t||this.hueMouse)&&(this.hue=e.h),(t||this.saturationMouse)&&(this.saturation=100*e.s),(t||this.lightnessMouse)&&(this.lightness=100*(this.options.round?e.l:e.v)),this.options.alpha&&(t||this.opacityMouse)&&(this.opacity=100*e.a)}},{key:"checkDirty",value:function(o){this.hasOwnProperty("initialNgModel")&&(o===this.initialNgModel?"function"==typeof this.$scope.control[0].$setPristine&&this.$scope.control[0].$setPristine():"function"==typeof this.$scope.control[0].$setDirty&&this.$scope.control[0].$setDirty())}},{key:"stopEvent",value:function(o){o.stopPropagation(),o.preventDefault()}},{key:"getRoundPos",value:function(){var o=.01745329251994*this.hue,t=Math.cos(o)*this.saturation,e=-Math.sin(o)*this.saturation;this.xPos=.5*(t+100),this.yPos=.5*(e+100);if(Math.pow(50-this.xPos,2)+Math.pow(50-this.yPos,2)>Math.pow(50,2)){var i=Math.atan2(this.yPos-50,this.xPos-50);this.xPos=50*Math.cos(i)+50,this.yPos=50*Math.sin(i)+50}}},{key:"updateRoundPos",value:function(){angular.element(this.$element[0].querySelector(".color-picker-grid .color-picker-picker")).css({left:this.pickerDimensions.width*this.xPos/100+"px",top:this.pickerDimensions.height*this.yPos/100+"px"})}},{key:"getEventPos",value:function(o){if(0===o.type.search("touch")){if(o.originalEvent&&o.originalEvent.changedTouches)return o.originalEvent.changedTouches[0];if(o.changedTouches)return o.changedTouches[0]}return o}},{key:"calculateSliderPos",value:function(o,t,e){return this.options.horizontal?Math.round((1-(t.pageX-this.offset(o).left)/o.prop("offsetWidth"))*e):Math.round((1-(t.pageY-this.offset(o).top)/o.prop("offsetHeight"))*e)}},{key:"eventApiDispatch",value:function(o,t){this.eventApi&&"function"==typeof this.eventApi[o]&&(t||(t=[]),t.unshift(this.internalNgModel),t.unshift(this.api),this.eventApi[o].apply(this,t))}},{key:"find",value:function(o){var t,e=this.wrapper?this.wrapper[0]:this.$element[0],i=[];if(!o)return i;if("string"==typeof o){if(1!==(t=e.nodeType)&&9!==t)return[];i=e.querySelectorAll(o)}else e.contains(o)&&i.push(o);return angular.element(i)}},{key:"offset",value:function(o){var t,e,i,n,r=o[0];if(r)return r.getClientRects().length?(i=r.getBoundingClientRect()).width||i.height?(n=r.ownerDocument,e=this.getWindowElements(n),t=n.documentElement,this.chrome&&this.android_version<6&&screen.width<=768?{top:i.top-t.clientTop,left:i.left-t.clientLeft}:{top:i.top+e.pageYOffset-t.clientTop,left:i.left+e.pageXOffset-t.clientLeft}):i:{top:0,left:0}}},{key:"getWindowElements",value:function(o){return null!==o&&o===o.window?o:9===o.nodeType&&o.defaultView}},{key:"anyMouseEvents",value:function(){return this.colorMouse||this.hueMouse||this.saturationMouse||this.lightnessMouse||this.opacityMouse}},{key:"getMaxFromType",value:function(o){return"hue"===o?360:100}}]),t}();r.$inject=["$scope","$element","$document","$timeout","ColorPickerOptions"],t.$inject=["$templateCache"];return angular.module("color.picker",[]).service("ColorPickerOptions",function o(){return i(this,o),{id:void 0,name:void 0,required:!1,disabled:!1,placeholder:"",inputClass:"",restrictToFormat:!1,preserveInputFormat:!1,allowEmpty:!1,format:"hsl",case:"upper",hue:!0,saturation:!1,lightness:!1,alpha:!0,dynamicHue:!0,dynamicSaturation:!0,dynamicLightness:!0,dynamicAlpha:!0,round:!1,pos:"bottom left",inline:!1,horizontal:!1,swatch:!0,swatchOnly:!1,swatchPos:"left",swatchBootstrap:!0,show:{swatch:!0,focus:!0},hide:{blur:!0,escape:!0,click:!0},close:{show:!1,label:"Close",class:""},clear:{show:!1,label:"Clear",class:""},reset:{show:!1,label:"Reset",class:""}}}).directive("colorPicker",function(){return{restrict:"E",require:["^ngModel"],scope:{ngModel:"=",options:"=?",api:"=?",eventApi:"=?"},bindToController:!0,templateUrl:"template/color-picker/directive.html",controller:r,controllerAs:"AngularColorPickerController",link:function(o,t,e,i){o.control=i,o.init()}}}).run(t)}); 11 | -------------------------------------------------------------------------------- /dist/themes/angularjs-color-picker-bootstrap.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * angularjs-color-picker v3.4.8 3 | * https://github.com/ruhley/angular-color-picker/ 4 | * 5 | * Copyright 2017 ruhley 6 | * 7 | * 2017-10-06 09:52:03 8 | * 9 | */ 10 | .color-picker-wrapper .color-picker-input-wrapper { 11 | width: 100%; 12 | } 13 | .color-picker-wrapper .color-picker-swatch:not(.input-group-addon) { 14 | height: 28px; 15 | } 16 | .color-picker-wrapper.color-picker-swatch-only .input-group .input-group-addon { 17 | border-radius: 4px; 18 | } 19 | -------------------------------------------------------------------------------- /dist/themes/angularjs-color-picker-bootstrap.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * angularjs-color-picker v3.4.8 3 | * https://github.com/ruhley/angular-color-picker/ 4 | * 5 | * Copyright 2017 ruhley 6 | * 7 | * 2017-10-06 09:52:03 8 | * 9 | */.color-picker-wrapper .color-picker-input-wrapper{width:100%}.color-picker-wrapper .color-picker-swatch:not(.input-group-addon){height:28px}.color-picker-wrapper.color-picker-swatch-only .input-group .input-group-addon{border-radius:4px} -------------------------------------------------------------------------------- /examples/01-simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example 1 - Simple 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

AngularJS Color Picker

22 |

An AngularJS directive for a color picker. No requirement on jQuery.

23 |
24 | 25 |

Color

26 | 27 |
28 | 29 | 30 |
31 | 32 |
33 | 34 | 35 |
36 | 37 |

Sliders

38 | 39 |
40 | 41 | 42 |
43 | 44 |
45 | 46 | 47 |
48 | 49 |
50 | 51 | 52 |
53 | 54 |
55 | 56 | 57 |
58 | 59 |
60 | 61 | 62 |
63 | 64 |
65 | 66 | 67 |
68 | 69 |
70 | 71 | 72 |
73 | 74 |
75 | 76 | 77 |
78 | 79 |

Swatch

80 | 81 |
82 | 83 | 84 |
85 | 86 |
87 | 88 | 89 |
90 | 91 |
92 | 93 | 94 |
95 | 96 |
97 | 98 | 99 |
100 | 101 |

Popup

102 | 103 |
104 | 105 | 106 |
107 | 108 |
109 | 110 | 111 |
112 | 113 |
114 | 115 | 116 |
117 | 118 |
119 | 120 | 121 |
122 | 123 |

Attributes

124 | 125 |
126 | 127 | 128 |
129 | 130 |
131 | 132 | 133 |
134 | 135 |
136 | 137 | 138 |
139 | 140 |
141 | 142 | 143 |
144 | 145 |
146 | 147 | 148 |
149 | 150 |
151 | 152 | 153 |
154 | 155 |

Show/Hide

156 | 157 |
158 | 159 | 160 |
161 | 162 |
163 | 164 | 165 |
166 | 167 |
168 | 169 | 170 |
171 | 172 |
173 | 174 | 175 |
176 | 177 |
178 | 179 | 180 |
181 | 182 |

Buttons

183 | 184 |
185 | 186 | 187 |
188 | 189 |
190 | 191 | 192 |
193 | 194 |
195 | 196 | 197 |
198 | 199 |
200 | 201 | 202 |
203 | 204 |
205 | 206 | 207 |
208 | 209 |
210 | 211 | 212 |
213 | 214 |
215 | 216 | 217 |
218 | 219 |
220 | 221 | 222 |
223 | 224 |
225 | 226 | 227 |
228 | 229 |

Validation

230 | 231 |
232 | 233 | 234 |
235 | 236 |
237 | 238 | 239 |
240 | 241 |
242 | 243 | 244 |
245 | 246 |

Examples

247 | 248 |
249 | 250 | 251 | 252 | 253 | 259 |
260 | 261 |
262 | Two Way Binding 263 | 264 | {{color}} 265 |
266 | 267 |
268 |

HTML Options

269 | 270 | 271 |
272 | 273 |
274 | Two Way Binding 275 | {{color2}} 276 |
277 | 278 |
279 |

No Options

280 | 281 | 282 |
283 | 284 |
285 | Two Way Binding 286 | {{color3}} 287 |
288 |
289 |
290 | 291 | 292 | -------------------------------------------------------------------------------- /examples/02-app.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('app', ['color.picker']) 3 | .config(function($provide) { 4 | $provide.decorator('ColorPickerOptions', function($delegate) { 5 | var options = angular.copy($delegate); 6 | options.inputClass = 'form-control'; 7 | return options; 8 | }); 9 | }) 10 | .controller('AppCtrl', function($scope) { 11 | $scope.eventApi = { 12 | onChange: function() { 13 | console.log($scope.color); 14 | }, 15 | onBlur: function() { 16 | console.log($scope.color); 17 | }, 18 | onOpen: function() { 19 | console.log($scope.color); 20 | }, 21 | onClose: function() { 22 | console.log($scope.color); 23 | }, 24 | }; 25 | 26 | var _color = 'hsl(0, 100%, 50%)'; 27 | $scope.color = function(newColor) { 28 | return angular.isDefined(newColor) ? (_color = newColor) : _color; 29 | }; 30 | }); 31 | -------------------------------------------------------------------------------- /examples/02-getterSetter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example 2 - Getter Setter 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |

AngularJS Color Picker

21 |

An AngularJS directive for a color picker. No requirement on jQuery.

22 | {{color}} 23 | {{color()}} 24 | 29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/03-angular-1.5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example 1 - Simple 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |

AngularJS Color Picker

21 |

An AngularJS directive for a color picker. No requirement on jQuery.

22 |
23 | 24 |

Color

25 | 26 |
27 | 28 | 29 |
30 | 31 |
32 | 33 | 34 |
35 | 36 |
37 | 38 | 39 |
40 | 41 |
42 | 43 | 44 |
45 | 46 |
47 | 48 | 49 |
50 | 51 |
52 | 53 | 54 |
55 | 56 |

Swatch

57 | 58 |
59 | 60 | 61 |
62 | 63 |
64 | 65 | 66 |
67 | 68 |
69 | 70 | 71 |
72 | 73 |
74 | 75 | 76 |
77 | 78 |

Popup

79 | 80 |
81 | 82 | 83 |
84 | 85 |
86 | 87 | 88 |
89 | 90 |
91 | 92 | 93 |
94 | 95 |
96 | 97 | 98 |
99 | 100 |

Attributes

101 | 102 |
103 | 104 | 105 |
106 | 107 |
108 | 109 | 110 |
111 | 112 |
113 | 114 | 115 |
116 | 117 |
118 | 119 | 120 |
121 | 122 |
123 | 124 | 125 |
126 | 127 |
128 | 129 | 130 |
131 | 132 |

Show/Hide

133 | 134 |
135 | 136 | 137 |
138 | 139 |
140 | 141 | 142 |
143 | 144 |
145 | 146 | 147 |
148 | 149 |
150 | 151 | 152 |
153 | 154 |
155 | 156 | 157 |
158 | 159 |

Buttons

160 | 161 |
162 | 163 | 164 |
165 | 166 |
167 | 168 | 169 |
170 | 171 |
172 | 173 | 174 |
175 | 176 |
177 | 178 | 179 |
180 | 181 |
182 | 183 | 184 |
185 | 186 |
187 | 188 | 189 |
190 | 191 |
192 | 193 | 194 |
195 | 196 |
197 | 198 | 199 |
200 | 201 |
202 | 203 | 204 |
205 | 206 |

Validation

207 | 208 |
209 | 210 | 211 |
212 | 213 |
214 | 215 | 216 |
217 | 218 |
219 | 220 | 221 |
222 | 223 |

Examples

224 | 225 |
226 | 227 | 228 | 229 | 235 |
236 | 237 |
238 | Two Way Binding 239 | 240 | {{color}} 241 |
242 | 243 |
244 |

HTML Options

245 | 246 | 247 |
248 | 249 |
250 | Two Way Binding 251 | {{color2}} 252 |
253 | 254 |
255 |

No Options

256 | 257 | 258 |
259 | 260 |
261 | Two Way Binding 262 | {{color3}} 263 |
264 |
265 |
266 | 267 | 268 | -------------------------------------------------------------------------------- /examples/04-app.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('app', ['color.picker']) 3 | .controller('AppCtrl', function($scope, $timeout) { 4 | $timeout(() => { 5 | $scope.color = 'hsl(180, 100%, 50%)'; 6 | }); 7 | $scope.options = { 8 | close: {show: true}, 9 | clear: {show: true}, 10 | reset: {show: true}, 11 | placeholder: $scope.color 12 | }; 13 | $scope.api = {}; 14 | 15 | $scope.setValue = function(value) { 16 | $scope.color = value; 17 | }; 18 | }); 19 | -------------------------------------------------------------------------------- /examples/04-delayed-initial-value.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example 4 - Delayed Initial Value 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |

AngularJS Color Picker

21 |

An AngularJS directive for a color picker. No requirement on jQuery.

22 |
23 | 24 |

Examples

25 | 26 |
27 | 28 | 29 | 35 |
36 | 37 |
38 | Two Way Binding 39 | {{color}} 40 |
41 |
42 |
43 | 44 | 45 | -------------------------------------------------------------------------------- /examples/app.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('app', ['color.picker']) 3 | .config(function($provide) { 4 | $provide.decorator('ColorPickerOptions', function($delegate) { 5 | var options = angular.copy($delegate); 6 | // options.round = true; 7 | options.hue = true; 8 | options.saturation = true; 9 | options.lightness = true; 10 | options.alpha = true; 11 | options.inline = true; 12 | options.format = 'hsl'; 13 | options.inputClass = 'form-control'; 14 | 15 | options.dynamicHue = false; 16 | options.dynamicLightness = false; 17 | options.dynamicSaturation = false; 18 | options.dynamicAlpha = false; 19 | return options; 20 | }); 21 | }) 22 | .controller('AppCtrl', function($scope) { 23 | $scope.formatOptions = [{label: 'HSL', value: 'hsl'}, {label: 'HSV', value: 'hsv'}, {label: 'RGB', value: 'rgb'}, {label: 'HEX', value: 'hex'}, {label: 'HEX8', value: 'hex8'}, {label: 'Raw', value: 'raw'}]; 24 | $scope.boolOptions = [{label: 'Yes', value: true}, {label: 'No', value: false}]; 25 | $scope.swatchPosOptions = [{label: 'Left', value: 'left'}, {label: 'Right', value: 'right'}]; 26 | $scope.posOptions = [{label: 'Bottom Left', value: 'bottom left'}, {label: 'Top Left', value: 'top left'}, {label: 'Bottom Right', value: 'bottom right'}, {label: 'Top Right', value: 'top right'}]; 27 | $scope.caseOptions = [{label: 'Upper Case', value: 'upper'}, {label: 'Lower Case', value: 'lower'}]; 28 | 29 | $scope.color = 'hsl(0, 100%, 50%)'; 30 | $scope.options = { 31 | close: {show: true}, 32 | clear: {show: true}, 33 | reset: {show: true}, 34 | placeholder: $scope.color 35 | }; 36 | $scope.api = {}; 37 | $scope.eventApi = { 38 | onChange: function() { 39 | console.log('change', arguments); 40 | }, 41 | onBlur: function() { 42 | console.log('blur', arguments); 43 | }, 44 | onOpen: function() { 45 | console.info('open', arguments); 46 | }, 47 | onClose: function() { 48 | console.info('close', arguments); 49 | }, 50 | onClear: function() { 51 | console.info('clear', arguments); 52 | }, 53 | onReset: function() { 54 | console.info('reset', arguments); 55 | }, 56 | onDestroy: function() { 57 | console.info('destroy', arguments); 58 | } 59 | }; 60 | 61 | $scope.open = function() { 62 | $scope.api.open(); 63 | }; 64 | 65 | $scope.close = function() { 66 | $scope.api.close(); 67 | }; 68 | 69 | $scope.setValue = function(value) { 70 | $scope.color = value; 71 | }; 72 | }); 73 | -------------------------------------------------------------------------------- /grunt/build.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.registerTask('build', [ 3 | 'notify:build', 4 | 'jshint:src', 5 | 'jshint:grunt', 6 | 'clean:build', 7 | 'run:rollup', 8 | 'less:build', 9 | 'cssmin:build', 10 | 'notify:buildComplete' 11 | ]); 12 | }; 13 | -------------------------------------------------------------------------------- /grunt/options/clean.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | build: { 3 | files: [{ 4 | dot: true, 5 | src: [ 6 | '.tmp', 7 | 'dist' 8 | ] 9 | }] 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /grunt/options/connect.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | test: { 3 | hostname: '*', 4 | keepalive: true 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /grunt/options/cssmin.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | options: { 3 | keepSpecialComments: 1 4 | }, 5 | build: { 6 | files: [{ 7 | expand: true, 8 | cwd: '<%= config.dist %>', 9 | src: ['**/*.css'], 10 | dest: '<%= config.dist %>', 11 | ext: '.min.css' 12 | }] 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /grunt/options/jshint.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | options: { 3 | esversion: 6, 4 | globals: { 5 | // js globals 6 | angular: true, 7 | _: true, 8 | console: true, 9 | // grunt globals 10 | module: true, 11 | require: true, 12 | process: true 13 | } 14 | }, 15 | src: ['<%= config.src %>/**/*.js'], 16 | grunt: ['Gruntfile.js', '<%= config.grunt %>/**/*.js'] 17 | }; 18 | -------------------------------------------------------------------------------- /grunt/options/less.js: -------------------------------------------------------------------------------- 1 | module.exports = function() { 2 | return { 3 | options: { 4 | ieCompat: false, 5 | strictMath: true, 6 | sourceMap: false, 7 | banner: '/*!\n * <%= config.pkg.name %> v<%= config.pkg.version %>\n * https://github.com/ruhley/angular-color-picker/\n *\n * Copyright <%= grunt.template.today("yyyy") %> ruhley\n *\n * <%= grunt.template.today("yyyy-mm-dd HH:MM:ss") %>\n *\n */\n' 8 | }, 9 | build: { 10 | files: [{ 11 | expand: true, 12 | cwd: '<%= config.src %>/<%= config.styles %>', 13 | src: ['**/*.less'], 14 | dest: '<%= config.dist %>', 15 | ext: '.css' 16 | }] 17 | } 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /grunt/options/notify.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | build: { 3 | options: { 4 | title: 'Grunt Build Task', 5 | message: 'Started' 6 | } 7 | }, 8 | buildComplete: { 9 | options: { 10 | title: 'Grunt Build Task', 11 | message: 'Task completed successfully' 12 | } 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /grunt/options/rollup.js: -------------------------------------------------------------------------------- 1 | var babel = require('rollup-plugin-babel'); 2 | var uglify = require('rollup-plugin-uglify'); 3 | var es2015Rollup = require('babel-preset-es2015-rollup'); 4 | var moment = require('moment'); 5 | 6 | var pjson = require('../../package.json'); 7 | 8 | var today = moment(); 9 | 10 | module.exports = { 11 | options: { 12 | input: 'src/scripts/module.js', 13 | plugins: [ 14 | babel({ 15 | exclude: 'node_modules/**', 16 | presets: [ es2015Rollup ] 17 | }) 18 | ] 19 | }, 20 | options_min: { 21 | input: 'src/scripts/module.js', 22 | plugins: [ 23 | babel({ 24 | exclude: 'node_modules/**', 25 | presets: [ es2015Rollup ] 26 | }), 27 | uglify({ 28 | output: { 29 | comments: function(node, comment) { 30 | var text = comment.value; 31 | var type = comment.type; 32 | if (type === 'comment2') { 33 | // multiline comment 34 | return /!/i.test(text); 35 | } 36 | } 37 | } 38 | }) 39 | ] 40 | }, 41 | writeOptions: { 42 | file: 'dist/angularjs-color-picker.js', 43 | format: 'umd', 44 | name: 'AngularjsColorPicker', 45 | sourcemap: false, 46 | banner: '/*!\n * ' + pjson.name + ' v' + pjson.version + '\n * https://github.com/ruhley/angular-color-picker/\n *\n * Copyright ' + today.format('YYYY') + ' ruhley\n *\n * ' + today.format('YYYY-MM-DD HH:mm:ss') + '\n *\n */\n', 47 | globals: { 48 | tinycolor2: 'tinycolor', 49 | }, 50 | }, 51 | writeFile: function(writer, writeOptions) { 52 | try { 53 | writer.write(writeOptions).then(function() { 54 | console.log('File created'); 55 | }, function() { 56 | console.log(arguments); 57 | }); 58 | } catch (e) { 59 | console.log(e); 60 | } 61 | }, 62 | reject: function(response) { 63 | console.log(response); 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /grunt/options/run.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rollup: { 3 | cmd: 'node', 4 | args: ['grunt/rollup.js'] 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /grunt/rollup.js: -------------------------------------------------------------------------------- 1 | var rollup = require('rollup'); 2 | 3 | var rollup_options = require('./options/rollup'); 4 | 5 | 6 | 7 | rollup.rollup(rollup_options.options).then(function(writer) { 8 | rollup_options.writeFile(writer, rollup_options.writeOptions); 9 | 10 | rollup.rollup(rollup_options.options_min).then(function(writer) { 11 | rollup_options.writeOptions.file = rollup_options.writeOptions.file.replace('.js', '.min.js'); 12 | rollup_options.writeFile(writer, rollup_options.writeOptions); 13 | }, rollup_options.reject); 14 | }, rollup_options.reject); 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angularjs-color-picker", 3 | "description": "Color Picker Directive For AngularJS", 4 | "version": "3.4.8", 5 | "license": "MIT", 6 | "main": "dist/angularjs-color-picker.min.js", 7 | "dependencies": { 8 | "angular": "^1.4.0", 9 | "tinycolor2": "^1.3.0" 10 | }, 11 | "repository": "git://github.com/ruhley/angular-color-picker.git", 12 | "author": "Timothy Ruhle ", 13 | "contributors": [ 14 | "Benjamin Orozco " 15 | ], 16 | "devDependencies": { 17 | "babel-core": "^6.25.0", 18 | "babel-preset-es2015-rollup": "^3.0.0", 19 | "glob": "^7.0.0", 20 | "grunt": "^1.0.0", 21 | "grunt-contrib-clean": "^1.0.0", 22 | "grunt-contrib-connect": "^1.0.2", 23 | "grunt-contrib-cssmin": "^2.0.0", 24 | "grunt-contrib-jshint": "^1.1.0", 25 | "grunt-contrib-less": "^1.3.0", 26 | "grunt-notify": "^0.4.1", 27 | "grunt-run": "^0.8.0", 28 | "load-grunt-tasks": "^3.5.0", 29 | "moment": "^2.14.1", 30 | "protractor": "^5.0.0", 31 | "rollup": "^0.50.0", 32 | "rollup-plugin-babel": "^3.0.0", 33 | "rollup-plugin-uglify": "^2.0.0", 34 | "time-grunt": "^1.3.0" 35 | }, 36 | "engines": { 37 | "node": ">=4.4.0" 38 | }, 39 | "scripts": { 40 | "pretest": "./node_modules/.bin/webdriver-manager update --standalone", 41 | "test": "./node_modules/.bin/protractor ./test/protractor-config.js" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/scripts/directive.js: -------------------------------------------------------------------------------- 1 | import controller from './controller'; 2 | 3 | export default function colorPickerDirective () { 4 | return { 5 | restrict: 'E', 6 | require: ['^ngModel'], 7 | scope: { 8 | ngModel: '=', 9 | options: '=?', 10 | api: '=?', 11 | eventApi: '=?' 12 | }, 13 | bindToController: true, 14 | templateUrl: 'template/color-picker/directive.html', 15 | controller: controller, 16 | controllerAs: 'AngularColorPickerController', 17 | link: function ($scope, element, attrs, control) { 18 | $scope.control = control; 19 | $scope.init(); 20 | } 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/scripts/module.js: -------------------------------------------------------------------------------- 1 | import directive from './directive'; 2 | import template from './template'; 3 | import optionsService from './options-service'; 4 | 5 | var colorPicker = angular 6 | .module('color.picker', []) 7 | .service('ColorPickerOptions', optionsService) 8 | .directive('colorPicker', directive) 9 | .run(template); 10 | 11 | 12 | export default colorPicker; 13 | -------------------------------------------------------------------------------- /src/scripts/options-service.js: -------------------------------------------------------------------------------- 1 | export default class AngularColorPickerOptions { 2 | constructor() { 3 | return { 4 | // input attributes 5 | id: undefined, 6 | name: undefined, 7 | required: false, 8 | disabled: false, 9 | placeholder: '', 10 | inputClass: '', 11 | // validation 12 | restrictToFormat: false, 13 | preserveInputFormat: false, 14 | allowEmpty: false, 15 | // color 16 | format: 'hsl', 17 | case: 'upper', 18 | // sliders 19 | hue: true, 20 | saturation: false, 21 | lightness: false, 22 | alpha: true, 23 | dynamicHue: true, 24 | dynamicSaturation: true, 25 | dynamicLightness: true, 26 | dynamicAlpha: true, 27 | // picker 28 | round: false, 29 | pos: 'bottom left', 30 | inline: false, 31 | horizontal: false, 32 | // swatch 33 | swatch: true, 34 | swatchOnly: false, 35 | swatchPos: 'left', 36 | swatchBootstrap: true, 37 | // show/hide events 38 | show: { 39 | swatch: true, 40 | focus: true 41 | }, 42 | hide: { 43 | blur: true, 44 | escape: true, 45 | click: true 46 | }, 47 | // buttons 48 | close: { 49 | show: false, 50 | label: 'Close', 51 | class: '' 52 | }, 53 | clear: { 54 | show: false, 55 | label: 'Clear', 56 | class: '' 57 | }, 58 | reset: { 59 | show: false, 60 | label: 'Reset', 61 | class: '' 62 | } 63 | }; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/scripts/template.js: -------------------------------------------------------------------------------- 1 | export default function template($templateCache) { 2 | $templateCache.put('template/color-picker/directive.html', 3 | '
' + 10 | '
' + 11 | '' + 12 | '' + 13 | '' + 14 | '
' + 15 | '
' + 27 | '
' + 28 | '
' + 29 | '
' + 30 | '
' + 31 | '
' + 32 | '
' + 33 | '
' + 34 | '
' + 35 | '
' + 36 | '
' + 37 | '
' + 38 | '
' + 39 | '
' + 40 | '
' + 41 | '
' + 42 | '
' + 43 | '
' + 44 | '
' + 45 | '
' + 46 | '
' + 47 | '
' + 48 | '
' + 49 | '
' + 50 | '
' + 51 | '
' + 52 | '
' + 53 | '
' + 54 | '
' + 55 | '' + 65 | '' + 75 | '' + 85 | '
' + 86 | '
' + 87 | '
' 88 | ); 89 | } 90 | 91 | template.$inject = ['$templateCache']; 92 | -------------------------------------------------------------------------------- /src/styles/themes/angularjs-color-picker-bootstrap.less: -------------------------------------------------------------------------------- 1 | .color-picker-wrapper { 2 | .color-picker-input-wrapper { 3 | width: 100%; 4 | } 5 | 6 | .color-picker-swatch { 7 | &:not(.input-group-addon) { 8 | height: 28px; 9 | } 10 | } 11 | 12 | &.color-picker-swatch-only { 13 | .input-group { 14 | .input-group-addon { 15 | border-radius: 4px; 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/e2e/allow-empty.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Allow Empty: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should not allow empty by default', () => { 11 | Page.blurColorPicker(); 12 | Page.openColorPicker(); 13 | Page.input_field.sendKeys('#FF0000').clear(); 14 | 15 | expect(Page.color_picker.getAttribute('class')).toMatch('ng-invalid'); 16 | }); 17 | 18 | it('Should allow empty', () => { 19 | Page.allow_empty_field.$('[label="Yes"]').click(); 20 | 21 | Page.blurColorPicker(); 22 | Page.openColorPicker(); 23 | Page.input_field.sendKeys('#FF0000').clear(); 24 | 25 | expect(Page.color_picker.getAttribute('class')).toMatch('ng-valid'); 26 | }); 27 | 28 | it('Should not allow empty again', () => { 29 | Page.allow_empty_field.$('[label="No"]').click(); 30 | 31 | Page.blurColorPicker(); 32 | Page.openColorPicker(); 33 | Page.input_field.sendKeys('#FF0000').clear(); 34 | 35 | expect(Page.color_picker.getAttribute('class')).toMatch('ng-invalid'); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/e2e/alpha.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Alpha: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should show alpha by default', () => { 11 | Page.openColorPicker(); 12 | expect(Page.alpha.isDisplayed()).toEqual(true); 13 | }); 14 | 15 | it('Should hide alpha', () => { 16 | Page.alpha_field.$('[label="No"]').click(); 17 | Page.openColorPicker(); 18 | expect(Page.alpha.isDisplayed()).toEqual(false); 19 | }); 20 | 21 | it('Should show alpha again', () => { 22 | Page.alpha_field.$('[label="Yes"]').click(); 23 | Page.openColorPicker(); 24 | expect(Page.alpha.isDisplayed()).toEqual(true); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/e2e/button-clear.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Button Clear: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should not be visible by default', () => { 11 | Page.openColorPicker(); 12 | expect(Page.button_clear.isDisplayed()).toEqual(false); 13 | }); 14 | 15 | it('Should update to be visible', () => { 16 | Page.button_clear_show_field.$('[label="Yes"]').click(); 17 | Page.openColorPicker(); 18 | expect(Page.button_clear.isDisplayed()).toEqual(true); 19 | }); 20 | 21 | it('Should set back to invisible', () => { 22 | Page.button_clear_show_field.$('[label="No"]').click(); 23 | Page.openColorPicker(); 24 | expect(Page.button_clear.isDisplayed()).toEqual(false); 25 | }); 26 | }); 27 | 28 | describe('Button Class: ', () => { 29 | beforeAll(() => { 30 | Page.openPage(); 31 | Page.waitTillPageLoaded(); 32 | }); 33 | 34 | it('Should not have an button class by default', () => { 35 | expect(Page.button_clear.getAttribute('class')).toMatch(''); 36 | }); 37 | 38 | it('Should update the button class', () => { 39 | let button_class = 'qwerty'; 40 | Page.button_clear_show_class.clear().sendKeys(button_class); 41 | expect(Page.button_clear.getAttribute('class')).toMatch(button_class); 42 | }); 43 | 44 | it('Should not have an button class', () => { 45 | Page.button_clear_show_class.clear(); 46 | expect(Page.button_clear.getAttribute('class')).toMatch(''); 47 | }); 48 | 49 | it('Should update the button class again', () => { 50 | let button_class = 'asdf'; 51 | Page.button_clear_show_class.clear().sendKeys(button_class); 52 | expect(Page.button_clear.getAttribute('class')).toMatch(button_class); 53 | }); 54 | 55 | it('Should update the button class again', () => { 56 | let button_class = 'zxcv'; 57 | Page.button_clear_show_class.clear().sendKeys(button_class); 58 | expect(Page.button_clear.getAttribute('class')).toMatch(button_class); 59 | }); 60 | }); 61 | 62 | describe('Button Label: ', () => { 63 | beforeAll(() => { 64 | Page.openPage(); 65 | Page.waitTillPageLoaded(); 66 | // show the button 67 | Page.button_clear_show_field.$('[label="Yes"]').click(); 68 | }); 69 | 70 | it('Should have an button label by default', () => { 71 | expect(Page.button_clear.getAttribute('innerHTML')).toEqual('Clear'); 72 | }); 73 | 74 | it('Should update the button label', () => { 75 | let button_label = 'qwerty'; 76 | Page.button_clear_show_label.clear().sendKeys(button_label); 77 | expect(Page.button_clear.getAttribute('innerHTML')).toEqual(button_label); 78 | }); 79 | 80 | it('Should not have an button label', () => { 81 | Page.button_clear_show_label.clear(); 82 | 83 | expect(Page.button_clear.getAttribute('innerHTML')).toEqual(''); 84 | }); 85 | 86 | it('Should update the button label again', () => { 87 | let button_label = 'asdf'; 88 | Page.button_clear_show_label.clear().sendKeys(button_label); 89 | expect(Page.button_clear.getAttribute('innerHTML')).toEqual(button_label); 90 | }); 91 | 92 | it('Should update the button label a third time', () => { 93 | let button_label = 'zxcv'; 94 | Page.button_clear_show_label.clear().sendKeys(button_label); 95 | expect(Page.button_clear.getAttribute('innerHTML')).toEqual(button_label); 96 | }); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /test/e2e/button-close.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Button Close: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should not be visible by default', () => { 11 | Page.openColorPicker(); 12 | expect(Page.button_close.isDisplayed()).toEqual(false); 13 | }); 14 | 15 | it('Should update to be visible', () => { 16 | Page.button_close_show_field.$('[label="Yes"]').click(); 17 | Page.openColorPicker(); 18 | expect(Page.button_close.isDisplayed()).toEqual(true); 19 | }); 20 | 21 | it('Should set back to invisible', () => { 22 | Page.button_close_show_field.$('[label="No"]').click(); 23 | Page.openColorPicker(); 24 | expect(Page.button_close.isDisplayed()).toEqual(false); 25 | }); 26 | }); 27 | 28 | describe('Button Class: ', () => { 29 | beforeAll(() => { 30 | Page.openPage(); 31 | Page.waitTillPageLoaded(); 32 | }); 33 | 34 | it('Should not have an button class by default', () => { 35 | expect(Page.button_close.getAttribute('class')).toMatch(''); 36 | }); 37 | 38 | it('Should update the button class', () => { 39 | let button_class = 'qwerty'; 40 | Page.button_close_show_class.clear().sendKeys(button_class); 41 | expect(Page.button_close.getAttribute('class')).toMatch(button_class); 42 | }); 43 | 44 | it('Should not have an button class', () => { 45 | Page.button_close_show_class.clear(); 46 | expect(Page.button_close.getAttribute('class')).toMatch(''); 47 | }); 48 | 49 | it('Should update the button class again', () => { 50 | let button_class = 'asdf'; 51 | Page.button_close_show_class.clear().sendKeys(button_class); 52 | expect(Page.button_close.getAttribute('class')).toMatch(button_class); 53 | }); 54 | 55 | it('Should update the button class again', () => { 56 | let button_class = 'zxcv'; 57 | Page.button_close_show_class.clear().sendKeys(button_class); 58 | expect(Page.button_close.getAttribute('class')).toMatch(button_class); 59 | }); 60 | }); 61 | 62 | describe('Button Label: ', () => { 63 | beforeAll(() => { 64 | Page.openPage(); 65 | Page.waitTillPageLoaded(); 66 | // show the button 67 | Page.button_close_show_field.$('[label="Yes"]').click(); 68 | }); 69 | 70 | it('Should have an button label by default', () => { 71 | expect(Page.button_close.getAttribute('innerHTML')).toEqual('Close'); 72 | }); 73 | 74 | it('Should update the button label', () => { 75 | let button_label = 'qwerty'; 76 | Page.button_close_show_label.clear().sendKeys(button_label); 77 | expect(Page.button_close.getAttribute('innerHTML')).toEqual(button_label); 78 | }); 79 | 80 | it('Should not have an button label', () => { 81 | Page.button_close_show_label.clear(); 82 | 83 | expect(Page.button_close.getAttribute('innerHTML')).toEqual(''); 84 | }); 85 | 86 | it('Should update the button label again', () => { 87 | let button_label = 'asdf'; 88 | Page.button_close_show_label.clear().sendKeys(button_label); 89 | expect(Page.button_close.getAttribute('innerHTML')).toEqual(button_label); 90 | }); 91 | 92 | it('Should update the button label a third time', () => { 93 | let button_label = 'zxcv'; 94 | Page.button_close_show_label.clear().sendKeys(button_label); 95 | expect(Page.button_close.getAttribute('innerHTML')).toEqual(button_label); 96 | }); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /test/e2e/button-reset.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Button Reset: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should not be visible by default', () => { 11 | Page.openColorPicker(); 12 | expect(Page.button_reset.isDisplayed()).toEqual(false); 13 | }); 14 | 15 | it('Should update to be visible', () => { 16 | Page.button_reset_show_field.$('[label="Yes"]').click(); 17 | Page.openColorPicker(); 18 | expect(Page.button_reset.isDisplayed()).toEqual(true); 19 | }); 20 | 21 | it('Should set back to invisible', () => { 22 | Page.button_reset_show_field.$('[label="No"]').click(); 23 | Page.openColorPicker(); 24 | expect(Page.button_reset.isDisplayed()).toEqual(false); 25 | }); 26 | }); 27 | 28 | describe('Button Class: ', () => { 29 | beforeAll(() => { 30 | Page.openPage(); 31 | Page.waitTillPageLoaded(); 32 | }); 33 | 34 | it('Should not have an button class by default', () => { 35 | expect(Page.button_reset.getAttribute('class')).toMatch(''); 36 | }); 37 | 38 | it('Should update the button class', () => { 39 | let button_class = 'qwerty'; 40 | Page.button_reset_show_class.clear().sendKeys(button_class); 41 | expect(Page.button_reset.getAttribute('class')).toMatch(button_class); 42 | }); 43 | 44 | it('Should not have an button class', () => { 45 | Page.button_reset_show_class.clear(); 46 | expect(Page.button_reset.getAttribute('class')).toMatch(''); 47 | }); 48 | 49 | it('Should update the button class again', () => { 50 | let button_class = 'asdf'; 51 | Page.button_reset_show_class.clear().sendKeys(button_class); 52 | expect(Page.button_reset.getAttribute('class')).toMatch(button_class); 53 | }); 54 | 55 | it('Should update the button class again', () => { 56 | let button_class = 'zxcv'; 57 | Page.button_reset_show_class.clear().sendKeys(button_class); 58 | expect(Page.button_reset.getAttribute('class')).toMatch(button_class); 59 | }); 60 | }); 61 | 62 | describe('Button Label: ', () => { 63 | beforeAll(() => { 64 | Page.openPage(); 65 | Page.waitTillPageLoaded(); 66 | // show the button 67 | Page.button_reset_show_field.$('[label="Yes"]').click(); 68 | }); 69 | 70 | it('Should have an button label by default', () => { 71 | expect(Page.button_reset.getAttribute('innerHTML')).toEqual('Reset'); 72 | }); 73 | 74 | it('Should update the button label', () => { 75 | let button_label = 'qwerty'; 76 | Page.button_reset_show_label.clear().sendKeys(button_label); 77 | expect(Page.button_reset.getAttribute('innerHTML')).toEqual(button_label); 78 | }); 79 | 80 | it('Should not have an button label', () => { 81 | Page.button_reset_show_label.clear(); 82 | 83 | expect(Page.button_reset.getAttribute('innerHTML')).toEqual(''); 84 | }); 85 | 86 | it('Should update the button label again', () => { 87 | let button_label = 'asdf'; 88 | Page.button_reset_show_label.clear().sendKeys(button_label); 89 | expect(Page.button_reset.getAttribute('innerHTML')).toEqual(button_label); 90 | }); 91 | 92 | it('Should update the button label a third time', () => { 93 | let button_label = 'zxcv'; 94 | Page.button_reset_show_label.clear().sendKeys(button_label); 95 | expect(Page.button_reset.getAttribute('innerHTML')).toEqual(button_label); 96 | }); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /test/e2e/dynamic-alpha.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('DynamicAlpha: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should enable dynamic alpha by default', () => { 11 | Page.openColorPicker(); 12 | expect(Page.dynamicAlpha_field.getAttribute('value').toEqual(true)); 13 | }); 14 | 15 | it('Should allow dynamic alpha to be turned off', () => { 16 | Page.dynamicAlpha_field.$('[label="No"]').click(); 17 | Page.openColorPicker(); 18 | expect(Page.dynamicAlpha_field.getAttribute('value').toEqual(false)); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/e2e/dynamic-hue.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('DynamicHue: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should enable dynamic hue by default', () => { 11 | Page.openColorPicker(); 12 | expect(Page.dynamicHue_field.getAttribute('value').toEqual(true)); 13 | }); 14 | 15 | it('Should allow dynamic hue to be turned off', () => { 16 | Page.dynamicHue_field.$('[label="No"]').click(); 17 | Page.openColorPicker(); 18 | expect(Page.dynamicHue_field.getAttribute('value').toEqual(false)); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/e2e/dynamic-lightness.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('DynamicLightness: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should enable dynamic lightness by default', () => { 11 | Page.openColorPicker(); 12 | expect(Page.dynamicLightness_field.getAttribute('value').toEqual(true)); 13 | }); 14 | 15 | it('Should allow dynamic lightness to be turned off', () => { 16 | Page.dynamicLightness_field.$('[label="No"]').click(); 17 | Page.openColorPicker(); 18 | expect(Page.dynamicLightness_field.getAttribute('value').toEqual(false)); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/e2e/dynamic-saturation.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('DynamicSaturation: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should enable dynamic saturation by default', () => { 11 | Page.openColorPicker(); 12 | expect(Page.dynamicSaturation_field.getAttribute('value').toEqual(true)); 13 | }); 14 | 15 | it('Should allow dynamic saturation to be turned off', () => { 16 | Page.dynamicSaturation_field.$('[label="No"]').click(); 17 | Page.openColorPicker(); 18 | expect(Page.dynamicSaturation_field.getAttribute('value').toEqual(false)); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/e2e/hide.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Hide Blur: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should hide when clicking the swatch by default', () => { 11 | Page.input_field.click(); 12 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 13 | Page.blurColorPicker(); 14 | expect(Page.color_picker_panel.isDisplayed()).toEqual(false); 15 | }); 16 | 17 | it('Should not hide when option is changed', () => { 18 | Page.hide_blur_field.$('[label="No"]').click(); 19 | Page.input_field.click(); 20 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 21 | Page.blurColorPicker(); 22 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 23 | }); 24 | 25 | it('Should hide again', () => { 26 | Page.hide_blur_field.$('[label="Yes"]').click(); 27 | Page.input_field.click(); 28 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 29 | Page.blurColorPicker(); 30 | expect(Page.color_picker_panel.isDisplayed()).toEqual(false); 31 | }); 32 | }); 33 | 34 | describe('Hide Escape: ', () => { 35 | beforeAll(() => { 36 | Page.openPage(); 37 | Page.waitTillPageLoaded(); 38 | }); 39 | 40 | it('Should hide when pressing escape by default', () => { 41 | Page.input_field.click(); 42 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 43 | Page.input_field.sendKeys(protractor.Key.ESCAPE); 44 | expect(Page.color_picker_panel.isDisplayed()).toEqual(false); 45 | }); 46 | 47 | it('Should not hide when option is changed', () => { 48 | Page.hide_escape_field.$('[label="No"]').click(); 49 | Page.input_field.click(); 50 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 51 | Page.input_field.sendKeys(protractor.Key.ESCAPE); 52 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 53 | }); 54 | 55 | it('Should hide again', () => { 56 | Page.hide_escape_field.$('[label="Yes"]').click(); 57 | Page.input_field.click(); 58 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 59 | Page.input_field.sendKeys(protractor.Key.ESCAPE); 60 | expect(Page.color_picker_panel.isDisplayed()).toEqual(false); 61 | }); 62 | }); 63 | 64 | describe('Hide Click: ', () => { 65 | beforeAll(() => { 66 | Page.openPage(); 67 | Page.waitTillPageLoaded(); 68 | // This can only truely be tested when blur is disabled 69 | Page.hide_blur_field.$('[label="No"]').click(); 70 | }); 71 | 72 | it('Should hide when clicking the swatch by default', () => { 73 | Page.input_field.click(); 74 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 75 | Page.body.click(); 76 | expect(Page.color_picker_panel.isDisplayed()).toEqual(false); 77 | }); 78 | 79 | it('Should not hide when option is changed', () => { 80 | Page.hide_click_field.$('[label="No"]').click(); 81 | Page.input_field.click(); 82 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 83 | Page.body.click(); 84 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 85 | }); 86 | 87 | it('Should hide again', () => { 88 | Page.hide_click_field.$('[label="Yes"]').click(); 89 | Page.input_field.click(); 90 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 91 | Page.body.click(); 92 | expect(Page.color_picker_panel.isDisplayed()).toEqual(false); 93 | }); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /test/e2e/hue.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Hue: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should show hue by default', () => { 11 | Page.openColorPicker(); 12 | expect(Page.hue.isDisplayed()).toEqual(true); 13 | }); 14 | 15 | it('Should hide hue', () => { 16 | Page.hue_field.$('[label="No"]').click(); 17 | Page.openColorPicker(); 18 | expect(Page.hue.isDisplayed()).toEqual(false); 19 | }); 20 | 21 | it('Should show hue again', () => { 22 | Page.hue_field.$('[label="Yes"]').click(); 23 | Page.openColorPicker(); 24 | expect(Page.hue.isDisplayed()).toEqual(true); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/e2e/id.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('ID: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should not have an id by default', () => { 11 | expect(Page.input_field.getAttribute('id')).toEqual(''); 12 | }); 13 | 14 | it('Should update the id', () => { 15 | let id = 'qwerty'; 16 | Page.id_field.clear().sendKeys(id); 17 | expect(Page.input_field.getAttribute('id')).toEqual(id); 18 | }); 19 | 20 | it('Should not have an id', () => { 21 | Page.id_field.clear(); 22 | expect(Page.input_field.getAttribute('id')).toEqual(''); 23 | }); 24 | 25 | it('Should update the id again', () => { 26 | let id = 'asdf'; 27 | Page.id_field.clear().sendKeys(id); 28 | expect(Page.input_field.getAttribute('id')).toEqual(id); 29 | }); 30 | 31 | it('Should update the id again', () => { 32 | let id = 'zxcv'; 33 | Page.id_field.clear().sendKeys(id); 34 | expect(Page.input_field.getAttribute('id')).toEqual(id); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/e2e/input-class.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Input Class: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should not have an inputClass by default', () => { 11 | expect(Page.input_field.getAttribute('class')).toMatch(''); 12 | }); 13 | 14 | it('Should update the inputClass', () => { 15 | let inputClass = 'qwerty'; 16 | Page.inputClass_field.clear().sendKeys(inputClass); 17 | expect(Page.input_field.getAttribute('class')).toMatch(inputClass); 18 | }); 19 | 20 | it('Should not have an inputClass', () => { 21 | Page.inputClass_field.clear(); 22 | expect(Page.input_field.getAttribute('class')).toMatch(''); 23 | }); 24 | 25 | it('Should update the inputClass again', () => { 26 | let inputClass = 'asdf'; 27 | Page.inputClass_field.clear().sendKeys(inputClass); 28 | expect(Page.input_field.getAttribute('class')).toMatch(inputClass); 29 | }); 30 | 31 | it('Should update the inputClass again', () => { 32 | let inputClass = 'zxcv'; 33 | Page.inputClass_field.clear().sendKeys(inputClass); 34 | expect(Page.input_field.getAttribute('class')).toMatch(inputClass); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/e2e/lightness.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Lightness: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should show lightness by default', () => { 11 | Page.openColorPicker(); 12 | expect(Page.lightness.isDisplayed()).toEqual(false); 13 | }); 14 | 15 | it('Should hide lightness', () => { 16 | Page.lightness_field.$('[label="Yes"]').click(); 17 | Page.openColorPicker(); 18 | expect(Page.lightness.isDisplayed()).toEqual(true); 19 | }); 20 | 21 | it('Should show lightness again', () => { 22 | Page.lightness_field.$('[label="No"]').click(); 23 | Page.openColorPicker(); 24 | expect(Page.lightness.isDisplayed()).toEqual(false); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/e2e/name.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Name: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should not have an name by default', () => { 11 | expect(Page.input_field.getAttribute('name')).toEqual(''); 12 | }); 13 | 14 | it('Should update the name', () => { 15 | let name = 'qwerty'; 16 | Page.name_field.clear().sendKeys(name); 17 | expect(Page.input_field.getAttribute('name')).toEqual(name); 18 | }); 19 | 20 | it('Should not have an name', () => { 21 | Page.name_field.clear(); 22 | expect(Page.input_field.getAttribute('name')).toEqual(''); 23 | }); 24 | 25 | it('Should update the name again', () => { 26 | let name = 'asdf'; 27 | Page.name_field.clear().sendKeys(name); 28 | expect(Page.input_field.getAttribute('name')).toEqual(name); 29 | }); 30 | 31 | it('Should update the name again', () => { 32 | let name = 'zxcv'; 33 | Page.name_field.clear().sendKeys(name); 34 | expect(Page.input_field.getAttribute('name')).toEqual(name); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/e2e/placeholder.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Placeholder: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should not have an placeholder by default', () => { 11 | expect(Page.input_field.getAttribute('placeholder')).toEqual(''); 12 | }); 13 | 14 | it('Should update the placeholder', () => { 15 | let placeholder = 'qwerty'; 16 | Page.placeholder_field.clear().sendKeys(placeholder); 17 | expect(Page.input_field.getAttribute('placeholder')).toEqual(placeholder); 18 | }); 19 | 20 | it('Should not have an placeholder', () => { 21 | Page.placeholder_field.clear(); 22 | expect(Page.input_field.getAttribute('placeholder')).toEqual(''); 23 | }); 24 | 25 | it('Should update the placeholder again', () => { 26 | let placeholder = 'asdf'; 27 | Page.placeholder_field.clear().sendKeys(placeholder); 28 | expect(Page.input_field.getAttribute('placeholder')).toEqual(placeholder); 29 | }); 30 | 31 | it('Should update the placeholder again', () => { 32 | let placeholder = 'zxcv'; 33 | Page.placeholder_field.clear().sendKeys(placeholder); 34 | expect(Page.input_field.getAttribute('placeholder')).toEqual(placeholder); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/e2e/preserve-input-format.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Preserve Input Format: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should not preserve input format by default', () => { 11 | Page.format_field.$('[label="HEXString"]').click(); 12 | Page.input_field.clear().sendKeys('red'); 13 | Page.blurColorPicker(); 14 | expect(Page.input_field.getAttribute('value')).toEqual('#FF0000'); 15 | }); 16 | 17 | it('Should preserve input format', () => { 18 | Page.format_field.$('[label="HEXString"]').click(); 19 | Page.preserve_input_format_field.$('[label="Yes"]').click(); 20 | Page.input_field.clear().sendKeys('red'); 21 | Page.blurColorPicker(); 22 | expect(Page.input_field.getAttribute('value')).toEqual('red'); 23 | }); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/e2e/restrict-to-format.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Restrict To Format: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should allow any format by default', () => { 11 | Page.format_field.$('[label="HEXString"]').click(); 12 | Page.input_field.clear().sendKeys('red'); 13 | Page.blurColorPicker(); 14 | Page.openColorPicker(); 15 | expect(Page.input_field.getAttribute('value')).toEqual('#FF0000'); 16 | }); 17 | 18 | it('Should only allow selected format', () => { 19 | Page.restrict_to_format_field.$('[label="Yes"]').click(); 20 | 21 | Page.format_field.$('[label="HEXString"]').click(); 22 | Page.input_field.clear().sendKeys('green'); 23 | Page.blurColorPicker(); 24 | Page.openColorPicker(); 25 | // even though we changed from red to green it should stay as red 26 | expect(Page.input_field.getAttribute('value')).toEqual('#FF0000'); 27 | }); 28 | 29 | it('Should allow any format again', () => { 30 | Page.restrict_to_format_field.$('[label="No"]').click(); 31 | 32 | Page.format_field.$('[label="HEXString"]').click(); 33 | Page.input_field.clear().sendKeys('blue'); 34 | Page.blurColorPicker(); 35 | Page.openColorPicker(); 36 | expect(Page.input_field.getAttribute('value')).toEqual('#0000FF'); 37 | }); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /test/e2e/saturation.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Saturation: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should show saturation by default', () => { 11 | Page.openColorPicker(); 12 | expect(Page.saturation.isDisplayed()).toEqual(false); 13 | }); 14 | 15 | it('Should hide saturation', () => { 16 | Page.saturation_field.$('[label="Yes"]').click(); 17 | Page.openColorPicker(); 18 | expect(Page.saturation.isDisplayed()).toEqual(true); 19 | }); 20 | 21 | it('Should show saturation again', () => { 22 | Page.saturation_field.$('[label="No"]').click(); 23 | Page.openColorPicker(); 24 | expect(Page.saturation.isDisplayed()).toEqual(false); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/e2e/show.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Show Swatch: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should show when clicking the swatch by default', () => { 11 | Page.swatch.click(); 12 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 13 | }); 14 | 15 | it('Should not show when option is changed', () => { 16 | Page.show_swatch_field.$('[label="No"]').click(); 17 | Page.swatch.click(); 18 | expect(Page.color_picker_panel.isDisplayed()).toEqual(false); 19 | }); 20 | 21 | it('Should show again', () => { 22 | Page.show_swatch_field.$('[label="Yes"]').click(); 23 | Page.swatch.click(); 24 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 25 | }); 26 | }); 27 | 28 | describe('Show Focus: ', () => { 29 | beforeAll(() => { 30 | Page.openPage(); 31 | Page.waitTillPageLoaded(); 32 | }); 33 | 34 | it('Should show when focusing by default', () => { 35 | Page.input_field.click(); 36 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 37 | }); 38 | 39 | it('Should not show when option is changed', () => { 40 | Page.show_focus_field.$('[label="No"]').click(); 41 | Page.input_field.click(); 42 | expect(Page.color_picker_panel.isDisplayed()).toEqual(false); 43 | }); 44 | 45 | it('Should show again', () => { 46 | Page.show_focus_field.$('[label="Yes"]').click(); 47 | Page.input_field.click(); 48 | expect(Page.color_picker_panel.isDisplayed()).toEqual(true); 49 | }); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /test/e2e/swatch-only.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Swatch Only: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should show the field by default', () => { 11 | expect(Page.input_field.isDisplayed()).toEqual(true); 12 | }); 13 | 14 | it('Should hide the field', () => { 15 | Page.swatch_only_field.$('[label="Yes"]').click(); 16 | expect(Page.input_field.isDisplayed()).toEqual(false); 17 | }); 18 | 19 | it('Should show the field again', () => { 20 | Page.swatch_only_field.$('[label="No"]').click(); 21 | expect(Page.input_field.isDisplayed()).toEqual(true); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /test/e2e/swatch-pos.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Swatch Pos: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should show the swatch on the left by default', () => { 11 | expect(Page.swatch_left.isPresent()).toEqual(true); 12 | expect(Page.swatch_right.isPresent()).toEqual(false); 13 | }); 14 | 15 | it('Should show the swatch on the right', () => { 16 | Page.swatch_pos_field.$('[label="Right"]').click(); 17 | expect(Page.swatch_left.isPresent()).toEqual(false); 18 | expect(Page.swatch_right.isPresent()).toEqual(true); 19 | }); 20 | 21 | it('Should show the swatch on the left again', () => { 22 | Page.swatch_pos_field.$('[label="Left"]').click(); 23 | expect(Page.swatch_left.isPresent()).toEqual(true); 24 | expect(Page.swatch_right.isPresent()).toEqual(false); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/e2e/swatch.protractor.js: -------------------------------------------------------------------------------- 1 | var Page = require('../page-object.js'); 2 | 3 | describe('Options: ', () => { 4 | describe('Swatch: ', () => { 5 | beforeAll(() => { 6 | Page.openPage(); 7 | Page.waitTillPageLoaded(); 8 | }); 9 | 10 | it('Should show the swatch by default', () => { 11 | expect(Page.swatch.isDisplayed()).toEqual(true); 12 | }); 13 | 14 | it('Should hide the swatch', () => { 15 | Page.swatch_field.$('[label="No"]').click(); 16 | expect(Page.swatch.isDisplayed()).toEqual(false); 17 | }); 18 | 19 | it('Should show the swatch again', () => { 20 | Page.swatch_field.$('[label="Yes"]').click(); 21 | expect(Page.swatch.isDisplayed()).toEqual(true); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /test/page-object.js: -------------------------------------------------------------------------------- 1 | 2 | class Page { 3 | constructor() { 4 | this.url = 'http://localhost:8000/test/test.html'; 5 | this.body = element(by.css('body')); 6 | 7 | // attribute fields 8 | this.id_field = element(by.model('options.id')); 9 | this.inputClass_field = element(by.model('options.inputClass')); 10 | this.name_field = element(by.model('options.name')); 11 | this.placeholder_field = element(by.model('options.placeholder')); 12 | 13 | // validation fields 14 | this.restrict_to_format_field = element(by.model('options.restrictToFormat')); 15 | this.preserve_input_format_field = element(by.model('options.preserveInputFormat')); 16 | this.allow_empty_field = element(by.model('options.allowEmpty')); 17 | 18 | // color fields 19 | this.format_field = element(by.model('options.format')); 20 | this.hue_field = element(by.model('options.hue')); 21 | this.saturation_field = element(by.model('options.saturation')); 22 | this.lightness_field = element(by.model('options.lightness')); 23 | this.alpha_field = element(by.model('options.alpha')); 24 | this.dynamicHue_field = element(by.model('options.dynamicHue')); 25 | 26 | // swatch fields 27 | this.swatch_field = element(by.model('options.swatch')); 28 | this.swatch_only_field = element(by.model('options.swatchOnly')); 29 | this.swatch_pos_field = element(by.model('options.swatchPos')); 30 | 31 | // show/hide fields 32 | this.show_swatch_field = element(by.model('options.show.swatch')); 33 | this.show_focus_field = element(by.model('options.show.focus')); 34 | this.hide_blur_field = element(by.model('options.hide.blur')); 35 | this.hide_escape_field = element(by.model('options.hide.escape')); 36 | this.hide_click_field = element(by.model('options.hide.click')); 37 | 38 | // button fields 39 | this.button_close_show_field = element(by.model('options.close.show')); 40 | this.button_close_show_class = element(by.model('options.close.class')); 41 | this.button_close_show_label = element(by.model('options.close.label')); 42 | 43 | this.button_clear_show_field = element(by.model('options.clear.show')); 44 | this.button_clear_show_class = element(by.model('options.clear.class')); 45 | this.button_clear_show_label = element(by.model('options.clear.label')); 46 | 47 | this.button_reset_show_field = element(by.model('options.reset.show')); 48 | this.button_reset_show_class = element(by.model('options.reset.class')); 49 | this.button_reset_show_label = element(by.model('options.reset.label')); 50 | 51 | // color picker elements 52 | this.color_picker = element(by.model('color')); 53 | this.input_field = element(by.model('AngularColorPickerController.internalNgModel')); 54 | this.color_picker_panel = element(by.css('.color-picker-panel')); 55 | this.swatch = element(by.css('.color-picker-swatch')); 56 | this.swatch_left = element(by.css('.color-picker-swatch-left')); 57 | this.swatch_right = element(by.css('.color-picker-swatch-right')); 58 | 59 | this.hue = element(by.css('.color-picker-hue')); 60 | this.saturation = element(by.css('.color-picker-saturation')); 61 | this.lightness = element(by.css('.color-picker-lightness')); 62 | this.alpha = element(by.css('.color-picker-opacity')); 63 | 64 | this.button_close = element(by.css('.color-picker-action-close')); 65 | this.button_clear = element(by.css('.color-picker-action-clear')); 66 | this.button_reset = element(by.css('.color-picker-action-reset')); 67 | } 68 | 69 | openPage() { 70 | // connect to the page 71 | browser.get(this.url); 72 | } 73 | 74 | // wait for the page to load 75 | waitTillPageLoaded() { 76 | browser.wait(() => { 77 | return this.input_field.isPresent(); 78 | }, 10000, 'Page not loaded'); 79 | } 80 | 81 | openColorPicker() { 82 | this.input_field.click(); 83 | } 84 | 85 | closeColorPicker() { 86 | this.input_field.sendKeys(protractor.Key.ESCAPE); 87 | } 88 | 89 | blurColorPicker() { 90 | browser.driver.executeScript('document.activeElement.blur()'); 91 | } 92 | 93 | getNgModel() { 94 | return this.color_picker.evaluate('color'); 95 | } 96 | 97 | setNgModel(value) { 98 | return this.color_picker.evaluate(`color = '${value}'`); 99 | } 100 | } 101 | 102 | module.exports = new Page(); 103 | -------------------------------------------------------------------------------- /test/protractor-config.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | 3 | //------------------------- 4 | // get selenium executables 5 | //------------------------- 6 | 7 | var selenium_dir = "./node_modules/protractor/node_modules/webdriver-manager/selenium/"; 8 | var files = fs.readdirSync(selenium_dir); 9 | var selenium_server_jar = null; 10 | var chrome_driver = null; 11 | 12 | for (var i = 0; i < files.length; i++) { 13 | if (/^selenium-server-standalone-[\d\.]+\.jar$/i.test(files[i])) { 14 | selenium_server_jar = files[i]; 15 | } else if (/^chromedriver_[\d\.]+$/i.test(files[i])) { // linux 16 | chrome_driver = files[i]; 17 | } else if (/^chromedriver_[\d\.]+.exe$/i.test(files[i])) { // windows 18 | chrome_driver = files[i]; 19 | } 20 | } 21 | 22 | //------------------------- 23 | // protractor config 24 | //------------------------- 25 | 26 | var _config = { 27 | seleniumServerJar: "." + selenium_dir + selenium_server_jar, 28 | chromeDriver: "." + selenium_dir + chrome_driver, 29 | specs: ["**/*.protractor.js"], 30 | directConnect: true, 31 | 32 | // options to be passed to jasmine 33 | jasmineNodeOpts: { 34 | showColors: true, 35 | defaultTimeoutInterval: 80000, 36 | isVerbose: true, 37 | includeStackTrace: true 38 | }, 39 | onPrepare: function() { 40 | // allow new javascript features to work 41 | require( "babel-core/register" )( { presets: [ "es2015" ] } ); 42 | 43 | // set the position and size of the browser 44 | browser.driver.manage().window().setSize( 1600, 800 ); 45 | browser.driver.manage().window().setPosition( 50, 100 ); 46 | }, 47 | }; 48 | 49 | module.exports.config = _config; 50 | -------------------------------------------------------------------------------- /test/test-app.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('app', ['color.picker']) 3 | .controller('AppCtrl', function($scope) { 4 | $scope.formatOptions = [{label: 'HSL', value: 'hsl'}, {label: 'HSV', value: 'hsv'}, {label: 'RGB', value: 'rgb'}, {label: 'HEX', value: 'hex'}, {label: 'HEXString', value: 'hexstring'}, {label: 'HEX8', value: 'hex8'}, {label: 'Raw', value: 'raw'}]; 5 | $scope.boolOptions = [{label: 'Yes', value: true}, {label: 'No', value: false}]; 6 | $scope.swatchPosOptions = [{label: 'Left', value: 'left'}, {label: 'Right', value: 'right'}]; 7 | $scope.posOptions = [{label: 'Bottom Left', value: 'bottom left'}, {label: 'Top Left', value: 'top left'}, {label: 'Bottom Right', value: 'bottom right'}, {label: 'Top Right', value: 'top right'}]; 8 | $scope.caseOptions = [{label: 'Upper Case', value: 'upper'}, {label: 'Lower Case', value: 'lower'}]; 9 | 10 | $scope.api = {}; 11 | $scope.eventApi = { 12 | onChange: function() { 13 | console.log('change', arguments); 14 | }, 15 | onBlur: function() { 16 | console.log('blur', arguments); 17 | }, 18 | onOpen: function() { 19 | console.info('open', arguments); 20 | }, 21 | onClose: function() { 22 | console.info('close', arguments); 23 | }, 24 | onClear: function() { 25 | console.info('clear', arguments); 26 | }, 27 | onReset: function() { 28 | console.info('reset', arguments); 29 | }, 30 | onDestroy: function() { 31 | console.info('destroy', arguments); 32 | } 33 | }; 34 | 35 | $scope.open = function() { 36 | $scope.api.open(); 37 | }; 38 | 39 | $scope.close = function() { 40 | $scope.api.close(); 41 | }; 42 | }); 43 | -------------------------------------------------------------------------------- /test/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Test 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

AngularJS Color Picker

17 |

An AngularJS directive for a color picker. No requirement on jQuery.

18 |
19 |
20 | 21 | 22 | 23 | 29 |
30 | 31 |

Color

32 | 33 |
34 | 35 | 36 |
37 | 38 |
39 | 40 | 41 |
42 | 43 |

Sliders

44 | 45 |
46 | 47 | 48 |
49 | 50 |
51 | 52 | 53 |
54 | 55 |
56 | 57 | 58 |
59 | 60 |
61 | 62 | 63 |
64 | 65 |
66 | 67 | 68 |
69 | 70 |
71 | 72 | 73 |
74 | 75 |
76 | 77 | 78 |
79 | 80 |
81 | 82 | 83 |
84 | 85 |

Swatch

86 | 87 |
88 | 89 | 90 |
91 | 92 |
93 | 94 | 95 |
96 | 97 |
98 | 99 | 100 |
101 | 102 |
103 | 104 | 105 |
106 | 107 |

Popup

108 | 109 |
110 | 111 | 112 |
113 | 114 |
115 | 116 | 117 |
118 | 119 |
120 | 121 | 122 |
123 | 124 |

Validation

125 | 126 |
127 | 128 | 129 |
130 | 131 |
132 | 133 | 134 |
135 | 136 |
137 | 138 | 139 |
140 | 141 |

Attributes

142 | 143 |
144 | 145 | 146 |
147 | 148 |
149 | 150 | 151 |
152 | 153 |
154 | 155 | 156 |
157 | 158 |
159 | 160 | 161 |
162 | 163 |
164 | 165 | 166 |
167 | 168 |
169 | 170 | 171 |
172 | 173 |

Show/Hide

174 | 175 |
176 | 177 | 178 |
179 | 180 |
181 | 182 | 183 |
184 | 185 |
186 | 187 | 188 |
189 | 190 |
191 | 192 | 193 |
194 | 195 |
196 | 197 | 198 |
199 | 200 |

Buttons

201 | 202 |
203 | 204 | 205 |
206 | 207 |
208 | 209 | 210 |
211 | 212 |
213 | 214 | 215 |
216 | 217 |
218 | 219 | 220 |
221 | 222 |
223 | 224 | 225 |
226 | 227 |
228 | 229 | 230 |
231 | 232 |
233 | 234 | 235 |
236 | 237 |
238 | 239 | 240 |
241 | 242 |
243 | 244 | 245 |
246 |
247 |
248 | 249 | 250 | --------------------------------------------------------------------------------