From 3e268805610ad6df0a804415d86754b5b45c1aa9 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 29 Apr 2014 23:46:40 +0300 Subject: [PATCH] Adding custom invoice colors --- Gruntfile.js | 4 +- README.md | 3 +- app/controllers/AccountController.php | 16 +- ...014_04_29_174315_add_advanced_settings.php | 36 + app/lang/en/texts.php | 14 +- app/libraries/utils.php | 2 +- app/routes.php | 2 +- ....blade.php => advanced_settings.blade.php} | 20 +- app/views/accounts/nav.blade.php | 2 +- app/views/header.blade.php | 12 +- app/views/invoices/view.blade.php | 5 + bower.json | 5 +- public/built.css | 520 ++++ public/built.js | 2347 ++++++++++++++++- public/js/script.js | 266 +- public/vendor/spectrum/.bower.json | 35 + public/vendor/spectrum/bower.json | 22 + .../spectrum/i18n/jquery.spectrum-de.js | 14 + .../spectrum/i18n/jquery.spectrum-dk.js | 14 + .../spectrum/i18n/jquery.spectrum-es.js | 14 + .../spectrum/i18n/jquery.spectrum-fi.js | 14 + .../spectrum/i18n/jquery.spectrum-fr.js | 14 + .../spectrum/i18n/jquery.spectrum-it.js | 14 + .../spectrum/i18n/jquery.spectrum-ja.js | 14 + .../spectrum/i18n/jquery.spectrum-nl.js | 15 + .../spectrum/i18n/jquery.spectrum-pt-br.js | 14 + .../spectrum/i18n/jquery.spectrum-ru.js | 14 + .../spectrum/i18n/jquery.spectrum-sv.js | 14 + .../spectrum/i18n/jquery.spectrum-tr.js | 14 + public/vendor/spectrum/index.html | 1084 ++++++++ public/vendor/spectrum/package.json | 14 + public/vendor/spectrum/spectrum.css | 519 ++++ public/vendor/spectrum/spectrum.jquery.json | 28 + public/vendor/spectrum/spectrum.js | 2080 +++++++++++++++ public/vendor/spectrum/themes/index.html | 113 + public/vendor/spectrum/themes/sp-dark.css | 128 + 36 files changed, 7183 insertions(+), 263 deletions(-) create mode 100644 app/database/migrations/2014_04_29_174315_add_advanced_settings.php rename app/views/accounts/{custom_fields.blade.php => advanced_settings.blade.php} (65%) create mode 100644 public/vendor/spectrum/.bower.json create mode 100644 public/vendor/spectrum/bower.json create mode 100644 public/vendor/spectrum/i18n/jquery.spectrum-de.js create mode 100644 public/vendor/spectrum/i18n/jquery.spectrum-dk.js create mode 100644 public/vendor/spectrum/i18n/jquery.spectrum-es.js create mode 100644 public/vendor/spectrum/i18n/jquery.spectrum-fi.js create mode 100644 public/vendor/spectrum/i18n/jquery.spectrum-fr.js create mode 100644 public/vendor/spectrum/i18n/jquery.spectrum-it.js create mode 100644 public/vendor/spectrum/i18n/jquery.spectrum-ja.js create mode 100644 public/vendor/spectrum/i18n/jquery.spectrum-nl.js create mode 100644 public/vendor/spectrum/i18n/jquery.spectrum-pt-br.js create mode 100644 public/vendor/spectrum/i18n/jquery.spectrum-ru.js create mode 100644 public/vendor/spectrum/i18n/jquery.spectrum-sv.js create mode 100644 public/vendor/spectrum/i18n/jquery.spectrum-tr.js create mode 100644 public/vendor/spectrum/index.html create mode 100644 public/vendor/spectrum/package.json create mode 100644 public/vendor/spectrum/spectrum.css create mode 100644 public/vendor/spectrum/spectrum.jquery.json create mode 100644 public/vendor/spectrum/spectrum.js create mode 100644 public/vendor/spectrum/themes/index.html create mode 100644 public/vendor/spectrum/themes/sp-dark.css diff --git a/Gruntfile.js b/Gruntfile.js index 4963af3142ed..c2fba67f89fc 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -17,6 +17,7 @@ module.exports = function(grunt) { 'public/vendor/bootstrap-datepicker/js/bootstrap-datepicker.js', 'public/vendor/typeahead.js/dist/typeahead.min.js', 'public/vendor/accounting/accounting.min.js', + 'public/vendor/spectrum/spectrum.js', 'public/js/bootstrap-combobox.js', 'public/js/jspdf.source.js', 'public/js/jspdf.plugin.split_text_to_size.js', @@ -31,13 +32,13 @@ module.exports = function(grunt) { 'public/vendor/datatables-bootstrap3/BS3/assets/css/datatables.css', 'public/vendor/font-awesome/css/font-awesome.min.css', 'public/vendor/bootstrap-datepicker/css/datepicker.css', + 'public/vendor/spectrum/spectrum.css', 'public/css/bootstrap-combobox.css', 'public/css/typeahead.js-bootstrap.css', 'public/css/style.css', ], dest: 'public/built.css' }, - /* css_public: { src: [ 'public/vendor/bootstrap/dist/css/bootstrap.min.css', @@ -46,7 +47,6 @@ module.exports = function(grunt) { ], dest: 'public/built.public.css' } - */ } }); diff --git a/README.md b/README.md index da06d990b5ea..5f58ffeedf68 100644 --- a/README.md +++ b/README.md @@ -68,4 +68,5 @@ Configure config/database.php and config/mail.php and initialize the database. * [josscrowcroft/accounting.js](https://github.com/josscrowcroft/accounting.js) - A lightweight JavaScript library for number, money and currency formatting * [jashkenas/underscore](https://github.com/jashkenas/underscore) - JavaScript's utility _ belt * [caouecs/Laravel4-long](https://github.com/caouecs/Laravel4-lang) - List of languages ​​for Laravel4 -* [calvinfroedge/PHP-Payments](https://github.com/calvinfroedge/PHP-Payments) - A uniform payments interface for PHP \ No newline at end of file +* [calvinfroedge/PHP-Payments](https://github.com/calvinfroedge/PHP-Payments) - A uniform payments interface for PHP +* [bgrins/spectrum](https://github.com/bgrins/spectrum) - The No Hassle JavaScript Colorpicker \ No newline at end of file diff --git a/app/controllers/AccountController.php b/app/controllers/AccountController.php index 4614c4bf5da3..00f57f65a819 100755 --- a/app/controllers/AccountController.php +++ b/app/controllers/AccountController.php @@ -181,13 +181,13 @@ class AccountController extends \BaseController { { return View::make('accounts.import_export'); } - else if ($section == ACCOUNT_CUSTOM_FIELDS) + else if ($section == ACCOUNT_ADVANCED_SETTINGS) { $data = [ 'account' => Auth::user()->account ]; - return View::make('accounts.custom_fields', $data); + return View::make('accounts.advanced_settings', $data); } else if ($section == ACCOUNT_PRODUCTS) { @@ -225,9 +225,9 @@ class AccountController extends \BaseController { { return AccountController::export(); } - else if ($section == ACCOUNT_CUSTOM_FIELDS) + else if ($section == ACCOUNT_ADVANCED_SETTINGS) { - return AccountController::saveCustomFields(); + return AccountController::saveAdvancedSettings(); } else if ($section == ACCOUNT_PRODUCTS) { @@ -247,7 +247,7 @@ class AccountController extends \BaseController { return Redirect::to('company/products'); } - private function saveCustomFields() + private function saveAdvancedSettings() { $account = Auth::user()->account; @@ -257,10 +257,14 @@ class AccountController extends \BaseController { $account->custom_value2 = Input::get('custom_value2'); $account->custom_client_label1 = Input::get('custom_client_label1'); $account->custom_client_label2 = Input::get('custom_client_label2'); + + $account->primary_color = Input::get('primary_color');// ? Input::get('primary_color') : null; + $account->secondary_color = Input::get('secondary_color');// ? Input::get('secondary_color') : null; + $account->save(); Session::flash('message', trans('texts.updated_settings')); - return Redirect::to('company/custom_fields'); + return Redirect::to('company/advanced_settings'); } private function export() diff --git a/app/database/migrations/2014_04_29_174315_add_advanced_settings.php b/app/database/migrations/2014_04_29_174315_add_advanced_settings.php new file mode 100644 index 000000000000..370cacfb1ee2 --- /dev/null +++ b/app/database/migrations/2014_04_29_174315_add_advanced_settings.php @@ -0,0 +1,36 @@ +string('primary_color'); + $table->string('secondary_color'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('primary_color'); + $table->dropColumn('secondary_color'); + }); + } + +} diff --git a/app/lang/en/texts.php b/app/lang/en/texts.php index 9fc4a67358f3..896c155262d0 100644 --- a/app/lang/en/texts.php +++ b/app/lang/en/texts.php @@ -339,7 +339,15 @@ return array( 'archive_product' => 'Archive Product', 'updated_product' => 'Successfully updated product', 'created_product' => 'Successfully created product', - 'archived_product' => 'Successfully archived product', - - 'pro_plan_custom_fields' => ':link to enable custom fields by joining the Pro Plan' + 'archived_product' => 'Successfully archived product', + 'pro_plan_custom_fields' => ':link to enable custom fields by joining the Pro Plan', + + 'advanced_settings' => 'Advanced Settings', + 'pro_plan_advanced_settings' => ':link to enable the advanced settings by joining the Pro Plan', + 'invoice_design' => 'Invoice Design', + 'specify_colors' => 'Specify colors', + 'specify_colors_label' => 'Select the colors used in the invoice', + + + ); diff --git a/app/libraries/utils.php b/app/libraries/utils.php index b6749b39b636..42c2e9c897d9 100755 --- a/app/libraries/utils.php +++ b/app/libraries/utils.php @@ -36,7 +36,7 @@ class Utils { if (Auth::check() && !Auth::user()->isPro() - && $feature == 'custom_fields') + && $feature == ACCOUNT_ADVANCED_SETTINGS) { return ' PRO'; } diff --git a/app/routes.php b/app/routes.php index 676444845b70..d938f6d7f72c 100755 --- a/app/routes.php +++ b/app/routes.php @@ -136,7 +136,7 @@ define('ACCOUNT_IMPORT_EXPORT', 'import_export'); define('ACCOUNT_PAYMENTS', 'payments'); define('ACCOUNT_MAP', 'import_map'); define('ACCOUNT_EXPORT', 'export'); -define('ACCOUNT_CUSTOM_FIELDS', 'custom_fields'); +define('ACCOUNT_ADVANCED_SETTINGS', 'advanced_settings'); define('ACCOUNT_PRODUCTS', 'products'); define('DEFAULT_INVOICE_NUMBER', '0001'); diff --git a/app/views/accounts/custom_fields.blade.php b/app/views/accounts/advanced_settings.blade.php similarity index 65% rename from app/views/accounts/custom_fields.blade.php rename to app/views/accounts/advanced_settings.blade.php index b79de815c8d2..e44aab85f5c2 100644 --- a/app/views/accounts/custom_fields.blade.php +++ b/app/views/accounts/advanced_settings.blade.php @@ -6,7 +6,7 @@ @if (!Auth::user()->account->isPro())
-
{{ trans('texts.pro_plan_custom_fields', ['link'=>''.trans('texts.pro_plan.remove_logo_link').'']) }}
+
{{ trans('texts.pro_plan_advanced_settings', ['link'=>''.trans('texts.pro_plan.remove_logo_link').'']) }}
 

 

@@ -27,6 +27,10 @@ {{ Former::text('custom_client_label1')->label(trans('texts.field_label')) }} {{ Former::text('custom_client_label2')->label(trans('texts.field_label')) }} + {{ Former::legend('invoice_design') }} + {{ Former::text('primary_color') }} + {{ Former::text('secondary_color') }} + @if (Auth::user()->isPro()) {{ Former::actions( Button::lg_success_submit(trans('texts.save'))->append_with_icon('floppy-disk') ) }} @else @@ -39,5 +43,19 @@ {{ Former::close() }} + + @stop \ No newline at end of file diff --git a/app/views/accounts/nav.blade.php b/app/views/accounts/nav.blade.php index db3b1940b704..c10e0153eb3d 100755 --- a/app/views/accounts/nav.blade.php +++ b/app/views/accounts/nav.blade.php @@ -8,7 +8,7 @@ {{ HTML::nav_link('company/products', 'product_library') }} {{ HTML::nav_link('company/notifications', 'notifications') }} {{ HTML::nav_link('company/import_export', 'import_export', 'company/import_map') }} - {{ HTML::nav_link('company/custom_fields', 'custom_fields') }} + {{ HTML::nav_link('company/advanced_settings', 'advanced_settings') }}

 

diff --git a/app/views/header.blade.php b/app/views/header.blade.php index f85835f4260b..5cd52f7c0485 100755 --- a/app/views/header.blade.php +++ b/app/views/header.blade.php @@ -17,7 +17,8 @@ - + + @@ -29,7 +30,8 @@ - + + @@ -53,6 +55,10 @@ currencyMap[currency.id] = currency; } var NINJA = NINJA || {}; + @if (Auth::check()) + NINJA.primaryColor = "{{ Auth::user()->account->primary_color }}"; + NINJA.secondaryColor = "{{ Auth::user()->account->secondary_color }}"; + @endif NINJA.parseFloat = function(str) { if (!str) return ''; str = (str+'').replace(/[^0-9\.\-]/g, ''); @@ -146,7 +152,7 @@
  • {{ link_to('company/products', uctrans('texts.product_library')) }}
  • {{ link_to('company/notifications', uctrans('texts.notifications')) }}
  • {{ link_to('company/import_export', uctrans('texts.import_export')) }}
  • -
  • {{ uctrans('texts.custom_fields') . Utils::getProLabel(ACCOUNT_CUSTOM_FIELDS) }}
  • +
  • {{ uctrans('texts.advanced_settings') . Utils::getProLabel(ACCOUNT_ADVANCED_SETTINGS) }}
  • {{ link_to('#', trans('texts.logout'), array('onclick'=>'logout()')) }}
  • diff --git a/app/views/invoices/view.blade.php b/app/views/invoices/view.blade.php index 969558993bba..a9ff416d43c9 100755 --- a/app/views/invoices/view.blade.php +++ b/app/views/invoices/view.blade.php @@ -48,6 +48,11 @@ invoice.imageWidth = {{ $invoice->client->account->getLogoWidth() }}; invoice.imageHeight = {{ $invoice->client->account->getLogoHeight() }}; @endif + + var NINJA = NINJA || {}; + NINJA.primaryColor = "{{ $invoice->client->account->primary_color }}"; + NINJA.secondaryColor = "{{ $invoice->client->account->secondary_color }}"; + var doc = generatePDF(invoice); if (!doc) return; var string = doc.output('datauristring'); diff --git a/bower.json b/bower.json index 0bb6f03a0329..177e7cf36aaf 100644 --- a/bower.json +++ b/bower.json @@ -16,6 +16,7 @@ "bootstrap-datepicker": "~1.*", "typeahead.js": "~0.9.3", "accounting": "~0.*", - "pdfjs": "*" + "pdfjs": "*", + "spectrum": "~1.3.4" } -} \ No newline at end of file +} diff --git a/public/built.css b/public/built.css index 9acb58dcd2e0..0f2c8dace270 100644 --- a/public/built.css +++ b/public/built.css @@ -921,6 +921,526 @@ div.DTFC_LeftFootWrapper table { padding: 4px 5px; } +/*** +Spectrum Colorpicker v1.3.4 +https://github.com/bgrins/spectrum +Author: Brian Grinstead +License: MIT +***/ + +.sp-container { + position:absolute; + top:0; + left:0; + display:inline-block; + *display: inline; + *zoom: 1; + /* https://github.com/bgrins/spectrum/issues/40 */ + z-index: 9999994; + overflow: hidden; +} +.sp-container.sp-flat { + position: relative; +} + +/* Fix for * { box-sizing: border-box; } */ +.sp-container, +.sp-container * { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +/* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */ +.sp-top { + position:relative; + width: 100%; + display:inline-block; +} +.sp-top-inner { + position:absolute; + top:0; + left:0; + bottom:0; + right:0; +} +.sp-color { + position: absolute; + top:0; + left:0; + bottom:0; + right:20%; +} +.sp-hue { + position: absolute; + top:0; + right:0; + bottom:0; + left:84%; + height: 100%; +} + +.sp-clear-enabled .sp-hue { + top:33px; + height: 77.5%; +} + +.sp-fill { + padding-top: 80%; +} +.sp-sat, .sp-val { + position: absolute; + top:0; + left:0; + right:0; + bottom:0; +} + +.sp-alpha-enabled .sp-top { + margin-bottom: 18px; +} +.sp-alpha-enabled .sp-alpha { + display: block; +} +.sp-alpha-handle { + position:absolute; + top:-4px; + bottom: -4px; + width: 6px; + left: 50%; + cursor: pointer; + border: 1px solid black; + background: white; + opacity: .8; +} +.sp-alpha { + display: none; + position: absolute; + bottom: -14px; + right: 0; + left: 0; + height: 8px; +} +.sp-alpha-inner { + border: solid 1px #333; +} + +.sp-clear { + display: none; +} + +.sp-clear.sp-clear-display { + background-position: center; +} + +.sp-clear-enabled .sp-clear { + display: block; + position:absolute; + top:0px; + right:0; + bottom:0; + left:84%; + height: 28px; +} + +/* Don't allow text selection */ +.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-clear, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button { + -webkit-user-select:none; + -moz-user-select: -moz-none; + -o-user-select:none; + user-select: none; +} + +.sp-container.sp-input-disabled .sp-input-container { + display: none; +} +.sp-container.sp-buttons-disabled .sp-button-container { + display: none; +} +.sp-palette-only .sp-picker-container { + display: none; +} +.sp-palette-disabled .sp-palette-container { + display: none; +} + +.sp-initial-disabled .sp-initial { + display: none; +} + + +/* Gradients for hue, saturation and value instead of images. Not pretty... but it works */ +.sp-sat { + background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0))); + background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0)); + background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); + background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); + background-image: -ms-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); + background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0)); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)"; + filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81'); +} +.sp-val { + background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0))); + background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); + background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); + background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); + background-image: -ms-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); + background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0)); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)"; + filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000'); +} + +.sp-hue { + background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); + background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); + background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); + background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000)); + background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); +} + +/* IE filters do not support multiple color stops. + Generate 6 divs, line them up, and do two color gradients for each. + Yes, really. + */ +.sp-1 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00'); +} +.sp-2 { + height:16%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00'); +} +.sp-3 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff'); +} +.sp-4 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff'); +} +.sp-5 { + height:16%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff'); +} +.sp-6 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000'); +} + +.sp-hidden { + display: none !important; +} + +/* Clearfix hack */ +.sp-cf:before, .sp-cf:after { content: ""; display: table; } +.sp-cf:after { clear: both; } +.sp-cf { *zoom: 1; } + +/* Mobile devices, make hue slider bigger so it is easier to slide */ +@media (max-device-width: 480px) { + .sp-color { right: 40%; } + .sp-hue { left: 63%; } + .sp-fill { padding-top: 60%; } +} +.sp-dragger { + border-radius: 5px; + height: 5px; + width: 5px; + border: 1px solid #fff; + background: #000; + cursor: pointer; + position:absolute; + top:0; + left: 0; +} +.sp-slider { + position: absolute; + top:0; + cursor:pointer; + height: 3px; + left: -1px; + right: -1px; + border: 1px solid #000; + background: white; + opacity: .8; +} + +/* +Theme authors: +Here are the basic themeable display options (colors, fonts, global widths). +See http://bgrins.github.io/spectrum/themes/ for instructions. +*/ + +.sp-container { + border-radius: 0; + background-color: #ECECEC; + border: solid 1px #f0c49B; + padding: 0; +} +.sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue, .sp-clear +{ + font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} +.sp-top +{ + margin-bottom: 3px; +} +.sp-color, .sp-hue, .sp-clear +{ + border: solid 1px #666; +} + +/* Input */ +.sp-input-container { + float:right; + width: 100px; + margin-bottom: 4px; +} +.sp-initial-disabled .sp-input-container { + width: 100%; +} +.sp-input { + font-size: 12px !important; + border: 1px inset; + padding: 4px 5px; + margin: 0; + width: 100%; + background:transparent; + border-radius: 3px; + color: #222; +} +.sp-input:focus { + border: 1px solid orange; +} +.sp-input.sp-validation-error +{ + border: 1px solid red; + background: #fdd; +} +.sp-picker-container , .sp-palette-container +{ + float:left; + position: relative; + padding: 10px; + padding-bottom: 300px; + margin-bottom: -290px; +} +.sp-picker-container +{ + width: 172px; + border-left: solid 1px #fff; +} + +/* Palettes */ +.sp-palette-container +{ + border-right: solid 1px #ccc; +} + +.sp-palette .sp-thumb-el { + display: block; + position:relative; + float:left; + width: 24px; + height: 15px; + margin: 3px; + cursor: pointer; + border:solid 2px transparent; +} +.sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active { + border-color: orange; +} +.sp-thumb-el +{ + position:relative; +} + +/* Initial */ +.sp-initial +{ + float: left; + border: solid 1px #333; +} +.sp-initial span { + width: 30px; + height: 25px; + border:none; + display:block; + float:left; + margin:0; +} + +.sp-initial .sp-clear-display { + background-position: center; +} + +/* Buttons */ +.sp-button-container { + float: right; +} + +/* Replacer (the little preview div that shows up instead of the ) */ +.sp-replacer { + margin:0; + overflow:hidden; + cursor:pointer; + padding: 4px; + display:inline-block; + *zoom: 1; + *display: inline; + border: solid 1px #91765d; + background: #eee; + color: #333; + vertical-align: middle; +} +.sp-replacer:hover, .sp-replacer.sp-active { + border-color: #F0C49B; + color: #111; +} +.sp-replacer.sp-disabled { + cursor:default; + border-color: silver; + color: silver; +} +.sp-dd { + padding: 2px 0; + height: 16px; + line-height: 16px; + float:left; + font-size:10px; +} +.sp-preview +{ + position:relative; + width:25px; + height: 20px; + border: solid 1px #222; + margin-right: 5px; + float:left; + z-index: 0; +} + +.sp-palette +{ + *width: 220px; + max-width: 220px; +} +.sp-palette .sp-thumb-el +{ + width:16px; + height: 16px; + margin:2px 1px; + border: solid 1px #d0d0d0; +} + +.sp-container +{ + padding-bottom:0; +} + + +/* Buttons: http://hellohappy.org/css3-buttons/ */ +.sp-container button { + background-color: #eeeeee; + background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc); + background-image: -moz-linear-gradient(top, #eeeeee, #cccccc); + background-image: -ms-linear-gradient(top, #eeeeee, #cccccc); + background-image: -o-linear-gradient(top, #eeeeee, #cccccc); + background-image: linear-gradient(to bottom, #eeeeee, #cccccc); + border: 1px solid #ccc; + border-bottom: 1px solid #bbb; + border-radius: 3px; + color: #333; + font-size: 14px; + line-height: 1; + padding: 5px 4px; + text-align: center; + text-shadow: 0 1px 0 #eee; + vertical-align: middle; +} +.sp-container button:hover { + background-color: #dddddd; + background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb); + background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb); + background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb); + background-image: -o-linear-gradient(top, #dddddd, #bbbbbb); + background-image: linear-gradient(to bottom, #dddddd, #bbbbbb); + border: 1px solid #bbb; + border-bottom: 1px solid #999; + cursor: pointer; + text-shadow: 0 1px 0 #ddd; +} +.sp-container button:active { + border: 1px solid #aaa; + border-bottom: 1px solid #888; + -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + -ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + -o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; +} +.sp-cancel +{ + font-size: 11px; + color: #d93f3f !important; + margin:0; + padding:2px; + margin-right: 5px; + vertical-align: middle; + text-decoration:none; + +} +.sp-cancel:hover +{ + color: #d93f3f !important; + text-decoration: underline; +} + + +.sp-palette span:hover, .sp-palette span.sp-thumb-active +{ + border-color: #000; +} + +.sp-preview, .sp-alpha, .sp-thumb-el +{ + position:relative; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); +} +.sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner +{ + display:block; + position:absolute; + top:0;left:0;bottom:0;right:0; +} + +.sp-palette .sp-thumb-inner +{ + background-position: 50% 50%; + background-repeat: no-repeat; +} + +.sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner +{ + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=); +} + +.sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner +{ + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=); +} + +.sp-clear-display { + background-repeat:no-repeat; + background-position: center; + background-image: url(data:image/gif;base64,R0lGODlhFAAUAPcAAAAAAJmZmZ2dnZ6enqKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq/Hx8fLy8vT09PX19ff39/j4+Pn5+fr6+vv7+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAAUABQAAAihAP9FoPCvoMGDBy08+EdhQAIJCCMybCDAAYUEARBAlFiQQoMABQhKUJBxY0SPICEYHBnggEmDKAuoPMjS5cGYMxHW3IiT478JJA8M/CjTZ0GgLRekNGpwAsYABHIypcAgQMsITDtWJYBR6NSqMico9cqR6tKfY7GeBCuVwlipDNmefAtTrkSzB1RaIAoXodsABiZAEFB06gIBWC1mLVgBa0AAOw==); +} + .combobox-container { margin-bottom: 5px; *zoom: 1; diff --git a/public/built.js b/public/built.js index 052f9bdebf09..216c06fd24e1 100644 --- a/public/built.js +++ b/public/built.js @@ -26002,6 +26002,2087 @@ d[b]="undefined"!==f.getType(g)?g:f.visitModel(j,c,a);break;default:d[b]=c(j,a.p * accounting.js v0.3.2, copyright 2011 Joss Crowcroft, MIT license, http://josscrowcroft.github.com/accounting.js */ (function(p,z){function q(a){return!!(""===a||a&&a.charCodeAt&&a.substr)}function m(a){return u?u(a):"[object Array]"===v.call(a)}function r(a){return"[object Object]"===v.call(a)}function s(a,b){var d,a=a||{},b=b||{};for(d in b)b.hasOwnProperty(d)&&null==a[d]&&(a[d]=b[d]);return a}function j(a,b,d){var c=[],e,h;if(!a)return c;if(w&&a.map===w)return a.map(b,d);for(e=0,h=a.length;ea?"-":"",g=parseInt(y(Math.abs(a||0),h),10)+"",l=3a?g.neg:g.zero).replace("%s",f.symbol).replace("%v",t(Math.abs(a),n(f.precision),f.thousand,f.decimal))};c.formatColumn=function(a,b,d,i,e,h){if(!a)return[];var f=s(r(b)?b:{symbol:b,precision:d,thousand:i,decimal:e,format:h},c.settings.currency),g=x(f.format),l=g.pos.indexOf("%s")a?g.neg:g.zero).replace("%s",f.symbol).replace("%v",t(Math.abs(a),n(f.precision),f.thousand,f.decimal));if(a.length>k)k=a.length;return a});return j(a,function(a){return q(a)&&a.length")[0]; + return colorInput.type === "color" && colorInput.value !== "!"; + })(), + replaceInput = [ + "
    ", + "
    ", + "
    ", + "
    " + ].join(''), + markup = (function () { + + // IE does not support gradients with multiple stops, so we need to simulate + // that for the rainbow slider with 8 divs that each have a single gradient + var gradientFix = ""; + if (IE) { + for (var i = 1; i <= 6; i++) { + gradientFix += "
    "; + } + } + + return [ + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + gradientFix, + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "", + "
    ", + "
    ", + "
    ", + "", + "", + "
    ", + "
    ", + "
    " + ].join(""); + })(); + + function paletteTemplate (p, color, className, tooltipFormat) { + var html = []; + for (var i = 0; i < p.length; i++) { + var current = p[i]; + if(current) { + var tiny = tinycolor(current); + var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light"; + c += (tinycolor.equals(color, current)) ? " sp-thumb-active" : ""; + + var formattedString = tiny.toString(tooltipFormat || "rgb"); + var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter(); + html.push(''); + } else { + var cls = 'sp-clear-display'; + html.push(''); + } + } + return "
    " + html.join('') + "
    "; + } + + function hideAll() { + for (var i = 0; i < spectrums.length; i++) { + if (spectrums[i]) { + spectrums[i].hide(); + } + } + } + + function instanceOptions(o, callbackContext) { + var opts = $.extend({}, defaultOpts, o); + opts.callbacks = { + 'move': bind(opts.move, callbackContext), + 'change': bind(opts.change, callbackContext), + 'show': bind(opts.show, callbackContext), + 'hide': bind(opts.hide, callbackContext), + 'beforeShow': bind(opts.beforeShow, callbackContext) + }; + + return opts; + } + + function spectrum(element, o) { + + var opts = instanceOptions(o, element), + flat = opts.flat, + showSelectionPalette = opts.showSelectionPalette, + localStorageKey = opts.localStorageKey, + theme = opts.theme, + callbacks = opts.callbacks, + resize = throttle(reflow, 10), + visible = false, + dragWidth = 0, + dragHeight = 0, + dragHelperHeight = 0, + slideHeight = 0, + slideWidth = 0, + alphaWidth = 0, + alphaSlideHelperWidth = 0, + slideHelperHeight = 0, + currentHue = 0, + currentSaturation = 0, + currentValue = 0, + currentAlpha = 1, + palette = [], + paletteArray = [], + paletteLookup = {}, + selectionPalette = opts.selectionPalette.slice(0), + maxSelectionSize = opts.maxSelectionSize, + draggingClass = "sp-dragging", + shiftMovementDirection = null; + + var doc = element.ownerDocument, + body = doc.body, + boundElement = $(element), + disabled = false, + container = $(markup, doc).addClass(theme), + dragger = container.find(".sp-color"), + dragHelper = container.find(".sp-dragger"), + slider = container.find(".sp-hue"), + slideHelper = container.find(".sp-slider"), + alphaSliderInner = container.find(".sp-alpha-inner"), + alphaSlider = container.find(".sp-alpha"), + alphaSlideHelper = container.find(".sp-alpha-handle"), + textInput = container.find(".sp-input"), + paletteContainer = container.find(".sp-palette"), + initialColorContainer = container.find(".sp-initial"), + cancelButton = container.find(".sp-cancel"), + clearButton = container.find(".sp-clear"), + chooseButton = container.find(".sp-choose"), + isInput = boundElement.is("input"), + isInputTypeColor = isInput && inputTypeColorSupport && boundElement.attr("type") === "color", + shouldReplace = isInput && !flat, + replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className).addClass(opts.replacerClassName) : $([]), + offsetElement = (shouldReplace) ? replacer : boundElement, + previewElement = replacer.find(".sp-preview-inner"), + initialColor = opts.color || (isInput && boundElement.val()), + colorOnShow = false, + preferredFormat = opts.preferredFormat, + currentPreferredFormat = preferredFormat, + clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange, + isEmpty = !initialColor, + allowEmpty = opts.allowEmpty && !isInputTypeColor; + + function applyOptions() { + + if (opts.showPaletteOnly) { + opts.showPalette = true; + } + + if (opts.palette) { + palette = opts.palette.slice(0); + paletteArray = $.isArray(palette[0]) ? palette : [palette]; + paletteLookup = {}; + for (var i = 0; i < paletteArray.length; i++) { + for (var j = 0; j < paletteArray[i].length; j++) { + var rgb = tinycolor(paletteArray[i][j]).toRgbString(); + paletteLookup[rgb] = true; + } + } + } + + container.toggleClass("sp-flat", flat); + container.toggleClass("sp-input-disabled", !opts.showInput); + container.toggleClass("sp-alpha-enabled", opts.showAlpha); + container.toggleClass("sp-clear-enabled", allowEmpty); + container.toggleClass("sp-buttons-disabled", !opts.showButtons); + container.toggleClass("sp-palette-disabled", !opts.showPalette); + container.toggleClass("sp-palette-only", opts.showPaletteOnly); + container.toggleClass("sp-initial-disabled", !opts.showInitial); + container.addClass(opts.className).addClass(opts.containerClassName); + + reflow(); + } + + function initialize() { + + if (IE) { + container.find("*:not(input)").attr("unselectable", "on"); + } + + applyOptions(); + + if (shouldReplace) { + boundElement.after(replacer).hide(); + } + + if (!allowEmpty) { + clearButton.hide(); + } + + if (flat) { + boundElement.after(container).hide(); + } + else { + + var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo); + if (appendTo.length !== 1) { + appendTo = $("body"); + } + + appendTo.append(container); + } + + updateSelectionPaletteFromStorage(); + + offsetElement.bind("click.spectrum touchstart.spectrum", function (e) { + if (!disabled) { + toggle(); + } + + e.stopPropagation(); + + if (!$(e.target).is("input")) { + e.preventDefault(); + } + }); + + if(boundElement.is(":disabled") || (opts.disabled === true)) { + disable(); + } + + // Prevent clicks from bubbling up to document. This would cause it to be hidden. + container.click(stopPropagation); + + // Handle user typed input + textInput.change(setFromTextInput); + textInput.bind("paste", function () { + setTimeout(setFromTextInput, 1); + }); + textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } }); + + cancelButton.text(opts.cancelText); + cancelButton.bind("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + hide("cancel"); + }); + + clearButton.attr("title", opts.clearText); + clearButton.bind("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + isEmpty = true; + move(); + + if(flat) { + //for the flat style, this is a change event + updateOriginalInput(true); + } + }); + + chooseButton.text(opts.chooseText); + chooseButton.bind("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + + if (isValid()) { + updateOriginalInput(true); + hide(); + } + }); + + draggable(alphaSlider, function (dragX, dragY, e) { + currentAlpha = (dragX / alphaWidth); + isEmpty = false; + if (e.shiftKey) { + currentAlpha = Math.round(currentAlpha * 10) / 10; + } + + move(); + }, dragStart, dragStop); + + draggable(slider, function (dragX, dragY) { + currentHue = parseFloat(dragY / slideHeight); + isEmpty = false; + if (!opts.showAlpha) { + currentAlpha = 1; + } + move(); + }, dragStart, dragStop); + + draggable(dragger, function (dragX, dragY, e) { + + // shift+drag should snap the movement to either the x or y axis. + if (!e.shiftKey) { + shiftMovementDirection = null; + } + else if (!shiftMovementDirection) { + var oldDragX = currentSaturation * dragWidth; + var oldDragY = dragHeight - (currentValue * dragHeight); + var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY); + + shiftMovementDirection = furtherFromX ? "x" : "y"; + } + + var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x"; + var setValue = !shiftMovementDirection || shiftMovementDirection === "y"; + + if (setSaturation) { + currentSaturation = parseFloat(dragX / dragWidth); + } + if (setValue) { + currentValue = parseFloat((dragHeight - dragY) / dragHeight); + } + + isEmpty = false; + if (!opts.showAlpha) { + currentAlpha = 1; + } + + move(); + + }, dragStart, dragStop); + + if (!!initialColor) { + set(initialColor); + + // In case color was black - update the preview UI and set the format + // since the set function will not run (default color is black). + updateUI(); + currentPreferredFormat = preferredFormat || tinycolor(initialColor).format; + + addColorToSelectionPalette(initialColor); + } + else { + updateUI(); + } + + if (flat) { + show(); + } + + function palletElementClick(e) { + if (e.data && e.data.ignore) { + set($(this).data("color")); + move(); + } + else { + set($(this).data("color")); + move(); + updateOriginalInput(true); + hide(); + } + + return false; + } + + var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum"; + paletteContainer.delegate(".sp-thumb-el", paletteEvent, palletElementClick); + initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, palletElementClick); + } + + function updateSelectionPaletteFromStorage() { + + if (localStorageKey && window.localStorage) { + + // Migrate old palettes over to new format. May want to remove this eventually. + try { + var oldPalette = window.localStorage[localStorageKey].split(",#"); + if (oldPalette.length > 1) { + delete window.localStorage[localStorageKey]; + $.each(oldPalette, function(i, c) { + addColorToSelectionPalette(c); + }); + } + } + catch(e) { } + + try { + selectionPalette = window.localStorage[localStorageKey].split(";"); + } + catch (e) { } + } + } + + function addColorToSelectionPalette(color) { + if (showSelectionPalette) { + var rgb = tinycolor(color).toRgbString(); + if (!paletteLookup[rgb] && $.inArray(rgb, selectionPalette) === -1) { + selectionPalette.push(rgb); + while(selectionPalette.length > maxSelectionSize) { + selectionPalette.shift(); + } + } + + if (localStorageKey && window.localStorage) { + try { + window.localStorage[localStorageKey] = selectionPalette.join(";"); + } + catch(e) { } + } + } + } + + function getUniqueSelectionPalette() { + var unique = []; + if (opts.showPalette) { + for (i = 0; i < selectionPalette.length; i++) { + var rgb = tinycolor(selectionPalette[i]).toRgbString(); + + if (!paletteLookup[rgb]) { + unique.push(selectionPalette[i]); + } + } + } + + return unique.reverse().slice(0, opts.maxSelectionSize); + } + + function drawPalette() { + + var currentColor = get(); + + var html = $.map(paletteArray, function (palette, i) { + return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i, opts.preferredFormat); + }); + + updateSelectionPaletteFromStorage(); + + if (selectionPalette) { + html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection", opts.preferredFormat)); + } + + paletteContainer.html(html.join("")); + } + + function drawInitial() { + if (opts.showInitial) { + var initial = colorOnShow; + var current = get(); + initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial", opts.preferredFormat)); + } + } + + function dragStart() { + if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) { + reflow(); + } + container.addClass(draggingClass); + shiftMovementDirection = null; + boundElement.trigger('dragstart.spectrum', [ get() ]); + } + + function dragStop() { + container.removeClass(draggingClass); + boundElement.trigger('dragstop.spectrum', [ get() ]); + } + + function setFromTextInput() { + + var value = textInput.val(); + + if ((value === null || value === "") && allowEmpty) { + set(null); + updateOriginalInput(true); + } + else { + var tiny = tinycolor(value); + if (tiny.ok) { + set(tiny); + updateOriginalInput(true); + } + else { + textInput.addClass("sp-validation-error"); + } + } + } + + function toggle() { + if (visible) { + hide(); + } + else { + show(); + } + } + + function show() { + var event = $.Event('beforeShow.spectrum'); + + if (visible) { + reflow(); + return; + } + + boundElement.trigger(event, [ get() ]); + + if (callbacks.beforeShow(get()) === false || event.isDefaultPrevented()) { + return; + } + + hideAll(); + visible = true; + + $(doc).bind("click.spectrum", hide); + $(window).bind("resize.spectrum", resize); + replacer.addClass("sp-active"); + container.removeClass("sp-hidden"); + + reflow(); + updateUI(); + + colorOnShow = get(); + + drawInitial(); + callbacks.show(colorOnShow); + boundElement.trigger('show.spectrum', [ colorOnShow ]); + } + + function hide(e) { + + // Return on right click + if (e && e.type == "click" && e.button == 2) { return; } + + // Return if hiding is unnecessary + if (!visible || flat) { return; } + visible = false; + + $(doc).unbind("click.spectrum", hide); + $(window).unbind("resize.spectrum", resize); + + replacer.removeClass("sp-active"); + container.addClass("sp-hidden"); + + var colorHasChanged = !tinycolor.equals(get(), colorOnShow); + + if (colorHasChanged) { + if (clickoutFiresChange && e !== "cancel") { + updateOriginalInput(true); + } + else { + revert(); + } + } + + callbacks.hide(get()); + boundElement.trigger('hide.spectrum', [ get() ]); + } + + function revert() { + set(colorOnShow, true); + } + + function set(color, ignoreFormatChange) { + if (tinycolor.equals(color, get())) { + // Update UI just in case a validation error needs + // to be cleared. + updateUI(); + return; + } + + var newColor, newHsv; + if (!color && allowEmpty) { + isEmpty = true; + } else { + isEmpty = false; + newColor = tinycolor(color); + newHsv = newColor.toHsv(); + + currentHue = (newHsv.h % 360) / 360; + currentSaturation = newHsv.s; + currentValue = newHsv.v; + currentAlpha = newHsv.a; + } + updateUI(); + + if (newColor && newColor.ok && !ignoreFormatChange) { + currentPreferredFormat = preferredFormat || newColor.format; + } + } + + function get(opts) { + opts = opts || { }; + + if (allowEmpty && isEmpty) { + return null; + } + + return tinycolor.fromRatio({ + h: currentHue, + s: currentSaturation, + v: currentValue, + a: Math.round(currentAlpha * 100) / 100 + }, { format: opts.format || currentPreferredFormat }); + } + + function isValid() { + return !textInput.hasClass("sp-validation-error"); + } + + function move() { + updateUI(); + + callbacks.move(get()); + boundElement.trigger('move.spectrum', [ get() ]); + } + + function updateUI() { + + textInput.removeClass("sp-validation-error"); + + updateHelperLocations(); + + // Update dragger background color (gradients take care of saturation and value). + var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 }); + dragger.css("background-color", flatColor.toHexString()); + + // Get a format that alpha will be included in (hex and names ignore alpha) + var format = currentPreferredFormat; + if (currentAlpha < 1 && !(currentAlpha === 0 && format === "name")) { + if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") { + format = "rgb"; + } + } + + var realColor = get({ format: format }), + displayColor = ''; + + //reset background info for preview element + previewElement.removeClass("sp-clear-display"); + previewElement.css('background-color', 'transparent'); + + if (!realColor && allowEmpty) { + // Update the replaced elements background with icon indicating no color selection + previewElement.addClass("sp-clear-display"); + } + else { + var realHex = realColor.toHexString(), + realRgb = realColor.toRgbString(); + + // Update the replaced elements background color (with actual selected color) + if (rgbaSupport || realColor.alpha === 1) { + previewElement.css("background-color", realRgb); + } + else { + previewElement.css("background-color", "transparent"); + previewElement.css("filter", realColor.toFilter()); + } + + if (opts.showAlpha) { + var rgb = realColor.toRgb(); + rgb.a = 0; + var realAlpha = tinycolor(rgb).toRgbString(); + var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")"; + + if (IE) { + alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex)); + } + else { + alphaSliderInner.css("background", "-webkit-" + gradient); + alphaSliderInner.css("background", "-moz-" + gradient); + alphaSliderInner.css("background", "-ms-" + gradient); + // Use current syntax gradient on unprefixed property. + alphaSliderInner.css("background", + "linear-gradient(to right, " + realAlpha + ", " + realHex + ")"); + } + } + + displayColor = realColor.toString(format); + } + + // Update the text entry input as it changes happen + if (opts.showInput) { + textInput.val(displayColor); + } + + if (opts.showPalette) { + drawPalette(); + } + + drawInitial(); + } + + function updateHelperLocations() { + var s = currentSaturation; + var v = currentValue; + + if(allowEmpty && isEmpty) { + //if selected color is empty, hide the helpers + alphaSlideHelper.hide(); + slideHelper.hide(); + dragHelper.hide(); + } + else { + //make sure helpers are visible + alphaSlideHelper.show(); + slideHelper.show(); + dragHelper.show(); + + // Where to show the little circle in that displays your current selected color + var dragX = s * dragWidth; + var dragY = dragHeight - (v * dragHeight); + dragX = Math.max( + -dragHelperHeight, + Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight) + ); + dragY = Math.max( + -dragHelperHeight, + Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight) + ); + dragHelper.css({ + "top": dragY + "px", + "left": dragX + "px" + }); + + var alphaX = currentAlpha * alphaWidth; + alphaSlideHelper.css({ + "left": (alphaX - (alphaSlideHelperWidth / 2)) + "px" + }); + + // Where to show the bar that displays your current selected hue + var slideY = (currentHue) * slideHeight; + slideHelper.css({ + "top": (slideY - slideHelperHeight) + "px" + }); + } + } + + function updateOriginalInput(fireCallback) { + var color = get(), + displayColor = '', + hasChanged = !tinycolor.equals(color, colorOnShow); + + if (color) { + displayColor = color.toString(currentPreferredFormat); + // Update the selection palette with the current color + addColorToSelectionPalette(color); + } + + if (isInput) { + boundElement.val(displayColor); + } + + colorOnShow = color; + + if (fireCallback && hasChanged) { + callbacks.change(color); + boundElement.trigger('change', [ color ]); + } + } + + function reflow() { + dragWidth = dragger.width(); + dragHeight = dragger.height(); + dragHelperHeight = dragHelper.height(); + slideWidth = slider.width(); + slideHeight = slider.height(); + slideHelperHeight = slideHelper.height(); + alphaWidth = alphaSlider.width(); + alphaSlideHelperWidth = alphaSlideHelper.width(); + + if (!flat) { + container.css("position", "absolute"); + container.offset(getOffset(container, offsetElement)); + } + + updateHelperLocations(); + + if (opts.showPalette) { + drawPalette(); + } + + boundElement.trigger('reflow.spectrum'); + } + + function destroy() { + boundElement.show(); + offsetElement.unbind("click.spectrum touchstart.spectrum"); + container.remove(); + replacer.remove(); + spectrums[spect.id] = null; + } + + function option(optionName, optionValue) { + if (optionName === undefined) { + return $.extend({}, opts); + } + if (optionValue === undefined) { + return opts[optionName]; + } + + opts[optionName] = optionValue; + applyOptions(); + } + + function enable() { + disabled = false; + boundElement.attr("disabled", false); + offsetElement.removeClass("sp-disabled"); + } + + function disable() { + hide(); + disabled = true; + boundElement.attr("disabled", true); + offsetElement.addClass("sp-disabled"); + } + + initialize(); + + var spect = { + show: show, + hide: hide, + toggle: toggle, + reflow: reflow, + option: option, + enable: enable, + disable: disable, + set: function (c) { + set(c); + updateOriginalInput(); + }, + get: get, + destroy: destroy, + container: container + }; + + spect.id = spectrums.push(spect) - 1; + + return spect; + } + + /** + * checkOffset - get the offset below/above and left/right element depending on screen position + * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js + */ + function getOffset(picker, input) { + var extraY = 0; + var dpWidth = picker.outerWidth(); + var dpHeight = picker.outerHeight(); + var inputHeight = input.outerHeight(); + var doc = picker[0].ownerDocument; + var docElem = doc.documentElement; + var viewWidth = docElem.clientWidth + $(doc).scrollLeft(); + var viewHeight = docElem.clientHeight + $(doc).scrollTop(); + var offset = input.offset(); + offset.top += inputHeight; + + offset.left -= + Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? + Math.abs(offset.left + dpWidth - viewWidth) : 0); + + offset.top -= + Math.min(offset.top, ((offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? + Math.abs(dpHeight + inputHeight - extraY) : extraY)); + + return offset; + } + + /** + * noop - do nothing + */ + function noop() { + + } + + /** + * stopPropagation - makes the code only doing this a little easier to read in line + */ + function stopPropagation(e) { + e.stopPropagation(); + } + + /** + * Create a function bound to a given object + * Thanks to underscore.js + */ + function bind(func, obj) { + var slice = Array.prototype.slice; + var args = slice.call(arguments, 2); + return function () { + return func.apply(obj, args.concat(slice.call(arguments))); + }; + } + + /** + * Lightweight drag helper. Handles containment within the element, so that + * when dragging, the x is within [0,element.width] and y is within [0,element.height] + */ + function draggable(element, onmove, onstart, onstop) { + onmove = onmove || function () { }; + onstart = onstart || function () { }; + onstop = onstop || function () { }; + var doc = element.ownerDocument || document; + var dragging = false; + var offset = {}; + var maxHeight = 0; + var maxWidth = 0; + var hasTouch = ('ontouchstart' in window); + + var duringDragEvents = {}; + duringDragEvents["selectstart"] = prevent; + duringDragEvents["dragstart"] = prevent; + duringDragEvents["touchmove mousemove"] = move; + duringDragEvents["touchend mouseup"] = stop; + + function prevent(e) { + if (e.stopPropagation) { + e.stopPropagation(); + } + if (e.preventDefault) { + e.preventDefault(); + } + e.returnValue = false; + } + + function move(e) { + if (dragging) { + // Mouseup happened outside of window + if (IE && document.documentMode < 9 && !e.button) { + return stop(); + } + + var touches = e.originalEvent.touches; + var pageX = touches ? touches[0].pageX : e.pageX; + var pageY = touches ? touches[0].pageY : e.pageY; + + var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); + var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); + + if (hasTouch) { + // Stop scrolling in iOS + prevent(e); + } + + onmove.apply(element, [dragX, dragY, e]); + } + } + + function start(e) { + var rightclick = (e.which) ? (e.which == 3) : (e.button == 2); + var touches = e.originalEvent.touches; + + if (!rightclick && !dragging) { + if (onstart.apply(element, arguments) !== false) { + dragging = true; + maxHeight = $(element).height(); + maxWidth = $(element).width(); + offset = $(element).offset(); + + $(doc).bind(duringDragEvents); + $(doc.body).addClass("sp-dragging"); + + if (!hasTouch) { + move(e); + } + + prevent(e); + } + } + } + + function stop() { + if (dragging) { + $(doc).unbind(duringDragEvents); + $(doc.body).removeClass("sp-dragging"); + onstop.apply(element, arguments); + } + dragging = false; + } + + $(element).bind("touchstart mousedown", start); + } + + function throttle(func, wait, debounce) { + var timeout; + return function () { + var context = this, args = arguments; + var throttler = function () { + timeout = null; + func.apply(context, args); + }; + if (debounce) clearTimeout(timeout); + if (debounce || !timeout) timeout = setTimeout(throttler, wait); + }; + } + + function log(){/* jshint -W021 */if(window.console){if(Function.prototype.bind)log=Function.prototype.bind.call(console.log,console);else log=function(){Function.prototype.apply.call(console.log,console,arguments);};log.apply(this,arguments);}} + + /** + * Define a jQuery plugin + */ + var dataID = "spectrum.id"; + $.fn.spectrum = function (opts, extra) { + + if (typeof opts == "string") { + + var returnValue = this; + var args = Array.prototype.slice.call( arguments, 1 ); + + this.each(function () { + var spect = spectrums[$(this).data(dataID)]; + if (spect) { + var method = spect[opts]; + if (!method) { + throw new Error( "Spectrum: no such method: '" + opts + "'" ); + } + + if (opts == "get") { + returnValue = spect.get(); + } + else if (opts == "container") { + returnValue = spect.container; + } + else if (opts == "option") { + returnValue = spect.option.apply(spect, args); + } + else if (opts == "destroy") { + spect.destroy(); + $(this).removeData(dataID); + } + else { + method.apply(spect, args); + } + } + }); + + return returnValue; + } + + // Initializing a new instance of spectrum + return this.spectrum("destroy").each(function () { + var options = $.extend({}, opts, $(this).data()); + var spect = spectrum(this, options); + $(this).data(dataID, spect.id); + }); + }; + + $.fn.spectrum.load = true; + $.fn.spectrum.loadOpts = {}; + $.fn.spectrum.draggable = draggable; + $.fn.spectrum.defaults = defaultOpts; + + $.spectrum = { }; + $.spectrum.localization = { }; + $.spectrum.palettes = { }; + + $.fn.spectrum.processNativeColorInputs = function () { + if (!inputTypeColorSupport) { + $("input[type=color]").spectrum({ + preferredFormat: "hex6" + }); + } + }; + + // TinyColor v0.9.17 + // https://github.com/bgrins/TinyColor + // 2013-08-10, Brian Grinstead, MIT License + + (function() { + + var trimLeft = /^[\s,#]+/, + trimRight = /\s+$/, + tinyCounter = 0, + math = Math, + mathRound = math.round, + mathMin = math.min, + mathMax = math.max, + mathRandom = math.random; + + function tinycolor (color, opts) { + + color = (color) ? color : ''; + opts = opts || { }; + + // If input is already a tinycolor, return itself + if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { + return color; + } + + var rgb = inputToRGB(color); + var r = rgb.r, + g = rgb.g, + b = rgb.b, + a = rgb.a, + roundA = mathRound(100*a) / 100, + format = opts.format || rgb.format; + + // Don't let the range of [0,255] come back in [0,1]. + // Potentially lose a little bit of precision here, but will fix issues where + // .5 gets interpreted as half of the total, instead of half of 1 + // If it was supposed to be 128, this was already taken care of by `inputToRgb` + if (r < 1) { r = mathRound(r); } + if (g < 1) { g = mathRound(g); } + if (b < 1) { b = mathRound(b); } + + return { + ok: rgb.ok, + format: format, + _tc_id: tinyCounter++, + alpha: a, + getAlpha: function() { + return a; + }, + setAlpha: function(value) { + a = boundAlpha(value); + roundA = mathRound(100*a) / 100; + }, + toHsv: function() { + var hsv = rgbToHsv(r, g, b); + return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a }; + }, + toHsvString: function() { + var hsv = rgbToHsv(r, g, b); + var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); + return (a == 1) ? + "hsv(" + h + ", " + s + "%, " + v + "%)" : + "hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")"; + }, + toHsl: function() { + var hsl = rgbToHsl(r, g, b); + return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a }; + }, + toHslString: function() { + var hsl = rgbToHsl(r, g, b); + var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); + return (a == 1) ? + "hsl(" + h + ", " + s + "%, " + l + "%)" : + "hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")"; + }, + toHex: function(allow3Char) { + return rgbToHex(r, g, b, allow3Char); + }, + toHexString: function(allow3Char) { + return '#' + this.toHex(allow3Char); + }, + toHex8: function() { + return rgbaToHex(r, g, b, a); + }, + toHex8String: function() { + return '#' + this.toHex8(); + }, + toRgb: function() { + return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a }; + }, + toRgbString: function() { + return (a == 1) ? + "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" : + "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")"; + }, + toPercentageRgb: function() { + return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a }; + }, + toPercentageRgbString: function() { + return (a == 1) ? + "rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" : + "rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")"; + }, + toName: function() { + if (a === 0) { + return "transparent"; + } + + return hexNames[rgbToHex(r, g, b, true)] || false; + }, + toFilter: function(secondColor) { + var hex8String = '#' + rgbaToHex(r, g, b, a); + var secondHex8String = hex8String; + var gradientType = opts && opts.gradientType ? "GradientType = 1, " : ""; + + if (secondColor) { + var s = tinycolor(secondColor); + secondHex8String = s.toHex8String(); + } + + return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")"; + }, + toString: function(format) { + var formatSet = !!format; + format = format || this.format; + + var formattedString = false; + var hasAlphaAndFormatNotSet = !formatSet && a < 1 && a > 0; + var formatWithAlpha = hasAlphaAndFormatNotSet && (format === "hex" || format === "hex6" || format === "hex3" || format === "name"); + + if (format === "rgb") { + formattedString = this.toRgbString(); + } + if (format === "prgb") { + formattedString = this.toPercentageRgbString(); + } + if (format === "hex" || format === "hex6") { + formattedString = this.toHexString(); + } + if (format === "hex3") { + formattedString = this.toHexString(true); + } + if (format === "hex8") { + formattedString = this.toHex8String(); + } + if (format === "name") { + formattedString = this.toName(); + } + if (format === "hsl") { + formattedString = this.toHslString(); + } + if (format === "hsv") { + formattedString = this.toHsvString(); + } + + if (formatWithAlpha) { + return this.toRgbString(); + } + + return formattedString || this.toHexString(); + } + }; + } + + // If input is an object, force 1 into "1.0" to handle ratios properly + // String input requires "1.0" as input, so 1 will be treated as 1 + tinycolor.fromRatio = function(color, opts) { + if (typeof color == "object") { + var newColor = {}; + for (var i in color) { + if (color.hasOwnProperty(i)) { + if (i === "a") { + newColor[i] = color[i]; + } + else { + newColor[i] = convertToPercentage(color[i]); + } + } + } + color = newColor; + } + + return tinycolor(color, opts); + }; + + // Given a string or object, convert that input to RGB + // Possible string inputs: + // + // "red" + // "#f00" or "f00" + // "#ff0000" or "ff0000" + // "#ff000000" or "ff000000" + // "rgb 255 0 0" or "rgb (255, 0, 0)" + // "rgb 1.0 0 0" or "rgb (1, 0, 0)" + // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" + // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" + // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" + // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" + // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" + // + function inputToRGB(color) { + + var rgb = { r: 0, g: 0, b: 0 }; + var a = 1; + var ok = false; + var format = false; + + if (typeof color == "string") { + color = stringInputToObject(color); + } + + if (typeof color == "object") { + if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { + rgb = rgbToRgb(color.r, color.g, color.b); + ok = true; + format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; + } + else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { + color.s = convertToPercentage(color.s); + color.v = convertToPercentage(color.v); + rgb = hsvToRgb(color.h, color.s, color.v); + ok = true; + format = "hsv"; + } + else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { + color.s = convertToPercentage(color.s); + color.l = convertToPercentage(color.l); + rgb = hslToRgb(color.h, color.s, color.l); + ok = true; + format = "hsl"; + } + + if (color.hasOwnProperty("a")) { + a = color.a; + } + } + + a = boundAlpha(a); + + return { + ok: ok, + format: color.format || format, + r: mathMin(255, mathMax(rgb.r, 0)), + g: mathMin(255, mathMax(rgb.g, 0)), + b: mathMin(255, mathMax(rgb.b, 0)), + a: a + }; + } + + + // Conversion Functions + // -------------------- + + // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: + // + + // `rgbToRgb` + // Handle bounds / percentage checking to conform to CSS color spec + // + // *Assumes:* r, g, b in [0, 255] or [0, 1] + // *Returns:* { r, g, b } in [0, 255] + function rgbToRgb(r, g, b){ + return { + r: bound01(r, 255) * 255, + g: bound01(g, 255) * 255, + b: bound01(b, 255) * 255 + }; + } + + // `rgbToHsl` + // Converts an RGB color value to HSL. + // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] + // *Returns:* { h, s, l } in [0,1] + function rgbToHsl(r, g, b) { + + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + + var max = mathMax(r, g, b), min = mathMin(r, g, b); + var h, s, l = (max + min) / 2; + + if(max == min) { + h = s = 0; // achromatic + } + else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch(max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + + h /= 6; + } + + return { h: h, s: s, l: l }; + } + + // `hslToRgb` + // Converts an HSL color value to RGB. + // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] + // *Returns:* { r, g, b } in the set [0, 255] + function hslToRgb(h, s, l) { + var r, g, b; + + h = bound01(h, 360); + s = bound01(s, 100); + l = bound01(l, 100); + + function hue2rgb(p, q, t) { + if(t < 0) t += 1; + if(t > 1) t -= 1; + if(t < 1/6) return p + (q - p) * 6 * t; + if(t < 1/2) return q; + if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; + return p; + } + + if(s === 0) { + r = g = b = l; // achromatic + } + else { + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1/3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1/3); + } + + return { r: r * 255, g: g * 255, b: b * 255 }; + } + + // `rgbToHsv` + // Converts an RGB color value to HSV + // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] + // *Returns:* { h, s, v } in [0,1] + function rgbToHsv(r, g, b) { + + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + + var max = mathMax(r, g, b), min = mathMin(r, g, b); + var h, s, v = max; + + var d = max - min; + s = max === 0 ? 0 : d / max; + + if(max == min) { + h = 0; // achromatic + } + else { + switch(max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + return { h: h, s: s, v: v }; + } + + // `hsvToRgb` + // Converts an HSV color value to RGB. + // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] + // *Returns:* { r, g, b } in the set [0, 255] + function hsvToRgb(h, s, v) { + + h = bound01(h, 360) * 6; + s = bound01(s, 100); + v = bound01(v, 100); + + var i = math.floor(h), + f = h - i, + p = v * (1 - s), + q = v * (1 - f * s), + t = v * (1 - (1 - f) * s), + mod = i % 6, + r = [v, q, p, p, t, v][mod], + g = [t, v, v, q, p, p][mod], + b = [p, p, t, v, v, q][mod]; + + return { r: r * 255, g: g * 255, b: b * 255 }; + } + + // `rgbToHex` + // Converts an RGB color to hex + // Assumes r, g, and b are contained in the set [0, 255] + // Returns a 3 or 6 character hex + function rgbToHex(r, g, b, allow3Char) { + + var hex = [ + pad2(mathRound(r).toString(16)), + pad2(mathRound(g).toString(16)), + pad2(mathRound(b).toString(16)) + ]; + + // Return a 3 character hex if possible + if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { + return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); + } + + return hex.join(""); + } + // `rgbaToHex` + // Converts an RGBA color plus alpha transparency to hex + // Assumes r, g, b and a are contained in the set [0, 255] + // Returns an 8 character hex + function rgbaToHex(r, g, b, a) { + + var hex = [ + pad2(convertDecimalToHex(a)), + pad2(mathRound(r).toString(16)), + pad2(mathRound(g).toString(16)), + pad2(mathRound(b).toString(16)) + ]; + + return hex.join(""); + } + + // `equals` + // Can be called with any tinycolor input + tinycolor.equals = function (color1, color2) { + if (!color1 || !color2) { return false; } + return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); + }; + tinycolor.random = function() { + return tinycolor.fromRatio({ + r: mathRandom(), + g: mathRandom(), + b: mathRandom() + }); + }; + + + // Modification Functions + // ---------------------- + // Thanks to less.js for some of the basics here + // + + tinycolor.desaturate = function (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.s -= amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); + }; + tinycolor.saturate = function (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.s += amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); + }; + tinycolor.greyscale = function(color) { + return tinycolor.desaturate(color, 100); + }; + tinycolor.lighten = function(color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.l += amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); + }; + tinycolor.darken = function (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.l -= amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); + }; + tinycolor.complement = function(color) { + var hsl = tinycolor(color).toHsl(); + hsl.h = (hsl.h + 180) % 360; + return tinycolor(hsl); + }; + + + // Combination Functions + // --------------------- + // Thanks to jQuery xColor for some of the ideas behind these + // + + tinycolor.triad = function(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) + ]; + }; + tinycolor.tetrad = function(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) + ]; + }; + tinycolor.splitcomplement = function(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), + tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) + ]; + }; + tinycolor.analogous = function(color, results, slices) { + results = results || 6; + slices = slices || 30; + + var hsl = tinycolor(color).toHsl(); + var part = 360 / slices; + var ret = [tinycolor(color)]; + + for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { + hsl.h = (hsl.h + part) % 360; + ret.push(tinycolor(hsl)); + } + return ret; + }; + tinycolor.monochromatic = function(color, results) { + results = results || 6; + var hsv = tinycolor(color).toHsv(); + var h = hsv.h, s = hsv.s, v = hsv.v; + var ret = []; + var modification = 1 / results; + + while (results--) { + ret.push(tinycolor({ h: h, s: s, v: v})); + v = (v + modification) % 1; + } + + return ret; + }; + + + // Readability Functions + // --------------------- + // + + // `readability` + // Analyze the 2 colors and returns an object with the following properties: + // `brightness`: difference in brightness between the two colors + // `color`: difference in color/hue between the two colors + tinycolor.readability = function(color1, color2) { + var a = tinycolor(color1).toRgb(); + var b = tinycolor(color2).toRgb(); + var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000; + var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000; + var colorDiff = ( + Math.max(a.r, b.r) - Math.min(a.r, b.r) + + Math.max(a.g, b.g) - Math.min(a.g, b.g) + + Math.max(a.b, b.b) - Math.min(a.b, b.b) + ); + + return { + brightness: Math.abs(brightnessA - brightnessB), + color: colorDiff + }; + }; + + // `readable` + // http://www.w3.org/TR/AERT#color-contrast + // Ensure that foreground and background color combinations provide sufficient contrast. + // *Example* + // tinycolor.readable("#000", "#111") => false + tinycolor.readable = function(color1, color2) { + var readability = tinycolor.readability(color1, color2); + return readability.brightness > 125 && readability.color > 500; + }; + + // `mostReadable` + // Given a base color and a list of possible foreground or background + // colors for that base, returns the most readable color. + // *Example* + // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" + tinycolor.mostReadable = function(baseColor, colorList) { + var bestColor = null; + var bestScore = 0; + var bestIsReadable = false; + for (var i=0; i < colorList.length; i++) { + + // We normalize both around the "acceptable" breaking point, + // but rank brightness constrast higher than hue. + + var readability = tinycolor.readability(baseColor, colorList[i]); + var readable = readability.brightness > 125 && readability.color > 500; + var score = 3 * (readability.brightness / 125) + (readability.color / 500); + + if ((readable && ! bestIsReadable) || + (readable && bestIsReadable && score > bestScore) || + ((! readable) && (! bestIsReadable) && score > bestScore)) { + bestIsReadable = readable; + bestScore = score; + bestColor = tinycolor(colorList[i]); + } + } + return bestColor; + }; + + + // Big List of Colors + // ------------------ + // + var names = tinycolor.names = { + aliceblue: "f0f8ff", + antiquewhite: "faebd7", + aqua: "0ff", + aquamarine: "7fffd4", + azure: "f0ffff", + beige: "f5f5dc", + bisque: "ffe4c4", + black: "000", + blanchedalmond: "ffebcd", + blue: "00f", + blueviolet: "8a2be2", + brown: "a52a2a", + burlywood: "deb887", + burntsienna: "ea7e5d", + cadetblue: "5f9ea0", + chartreuse: "7fff00", + chocolate: "d2691e", + coral: "ff7f50", + cornflowerblue: "6495ed", + cornsilk: "fff8dc", + crimson: "dc143c", + cyan: "0ff", + darkblue: "00008b", + darkcyan: "008b8b", + darkgoldenrod: "b8860b", + darkgray: "a9a9a9", + darkgreen: "006400", + darkgrey: "a9a9a9", + darkkhaki: "bdb76b", + darkmagenta: "8b008b", + darkolivegreen: "556b2f", + darkorange: "ff8c00", + darkorchid: "9932cc", + darkred: "8b0000", + darksalmon: "e9967a", + darkseagreen: "8fbc8f", + darkslateblue: "483d8b", + darkslategray: "2f4f4f", + darkslategrey: "2f4f4f", + darkturquoise: "00ced1", + darkviolet: "9400d3", + deeppink: "ff1493", + deepskyblue: "00bfff", + dimgray: "696969", + dimgrey: "696969", + dodgerblue: "1e90ff", + firebrick: "b22222", + floralwhite: "fffaf0", + forestgreen: "228b22", + fuchsia: "f0f", + gainsboro: "dcdcdc", + ghostwhite: "f8f8ff", + gold: "ffd700", + goldenrod: "daa520", + gray: "808080", + green: "008000", + greenyellow: "adff2f", + grey: "808080", + honeydew: "f0fff0", + hotpink: "ff69b4", + indianred: "cd5c5c", + indigo: "4b0082", + ivory: "fffff0", + khaki: "f0e68c", + lavender: "e6e6fa", + lavenderblush: "fff0f5", + lawngreen: "7cfc00", + lemonchiffon: "fffacd", + lightblue: "add8e6", + lightcoral: "f08080", + lightcyan: "e0ffff", + lightgoldenrodyellow: "fafad2", + lightgray: "d3d3d3", + lightgreen: "90ee90", + lightgrey: "d3d3d3", + lightpink: "ffb6c1", + lightsalmon: "ffa07a", + lightseagreen: "20b2aa", + lightskyblue: "87cefa", + lightslategray: "789", + lightslategrey: "789", + lightsteelblue: "b0c4de", + lightyellow: "ffffe0", + lime: "0f0", + limegreen: "32cd32", + linen: "faf0e6", + magenta: "f0f", + maroon: "800000", + mediumaquamarine: "66cdaa", + mediumblue: "0000cd", + mediumorchid: "ba55d3", + mediumpurple: "9370db", + mediumseagreen: "3cb371", + mediumslateblue: "7b68ee", + mediumspringgreen: "00fa9a", + mediumturquoise: "48d1cc", + mediumvioletred: "c71585", + midnightblue: "191970", + mintcream: "f5fffa", + mistyrose: "ffe4e1", + moccasin: "ffe4b5", + navajowhite: "ffdead", + navy: "000080", + oldlace: "fdf5e6", + olive: "808000", + olivedrab: "6b8e23", + orange: "ffa500", + orangered: "ff4500", + orchid: "da70d6", + palegoldenrod: "eee8aa", + palegreen: "98fb98", + paleturquoise: "afeeee", + palevioletred: "db7093", + papayawhip: "ffefd5", + peachpuff: "ffdab9", + peru: "cd853f", + pink: "ffc0cb", + plum: "dda0dd", + powderblue: "b0e0e6", + purple: "800080", + red: "f00", + rosybrown: "bc8f8f", + royalblue: "4169e1", + saddlebrown: "8b4513", + salmon: "fa8072", + sandybrown: "f4a460", + seagreen: "2e8b57", + seashell: "fff5ee", + sienna: "a0522d", + silver: "c0c0c0", + skyblue: "87ceeb", + slateblue: "6a5acd", + slategray: "708090", + slategrey: "708090", + snow: "fffafa", + springgreen: "00ff7f", + steelblue: "4682b4", + tan: "d2b48c", + teal: "008080", + thistle: "d8bfd8", + tomato: "ff6347", + turquoise: "40e0d0", + violet: "ee82ee", + wheat: "f5deb3", + white: "fff", + whitesmoke: "f5f5f5", + yellow: "ff0", + yellowgreen: "9acd32" + }; + + // Make it easy to access colors via `hexNames[hex]` + var hexNames = tinycolor.hexNames = flip(names); + + + // Utilities + // --------- + + // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` + function flip(o) { + var flipped = { }; + for (var i in o) { + if (o.hasOwnProperty(i)) { + flipped[o[i]] = i; + } + } + return flipped; + } + + // Return a valid alpha value [0,1] with all invalid values being set to 1 + function boundAlpha(a) { + a = parseFloat(a); + + if (isNaN(a) || a < 0 || a > 1) { + a = 1; + } + + return a; + } + + // Take input from [0, n] and return it as [0, 1] + function bound01(n, max) { + if (isOnePointZero(n)) { n = "100%"; } + + var processPercent = isPercentage(n); + n = mathMin(max, mathMax(0, parseFloat(n))); + + // Automatically convert percentage into number + if (processPercent) { + n = parseInt(n * max, 10) / 100; + } + + // Handle floating point rounding errors + if ((math.abs(n - max) < 0.000001)) { + return 1; + } + + // Convert into [0, 1] range if it isn't already + return (n % max) / parseFloat(max); + } + + // Force a number between 0 and 1 + function clamp01(val) { + return mathMin(1, mathMax(0, val)); + } + + // Parse a base-16 hex value into a base-10 integer + function parseIntFromHex(val) { + return parseInt(val, 16); + } + + // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 + // + function isOnePointZero(n) { + return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; + } + + // Check to see if string passed in is a percentage + function isPercentage(n) { + return typeof n === "string" && n.indexOf('%') != -1; + } + + // Force a hex value to have 2 characters + function pad2(c) { + return c.length == 1 ? '0' + c : '' + c; + } + + // Replace a decimal with it's percentage value + function convertToPercentage(n) { + if (n <= 1) { + n = (n * 100) + "%"; + } + + return n; + } + + // Converts a decimal to a hex value + function convertDecimalToHex(d) { + return Math.round(parseFloat(d) * 255).toString(16); + } + // Converts a hex value to a decimal + function convertHexToDecimal(h) { + return (parseIntFromHex(h) / 255); + } + + var matchers = (function() { + + // + var CSS_INTEGER = "[-\\+]?\\d+%?"; + + // + var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; + + // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. + var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; + + // Actual matching. + // Parentheses and commas are optional, but not required. + // Whitespace can take the place of commas or opening paren + var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + + return { + rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), + rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), + hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), + hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), + hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), + hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, + hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, + hex8: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ + }; + })(); + + // `stringInputToObject` + // Permissive string parsing. Take in a number of formats, and output an object + // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` + function stringInputToObject(color) { + + color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); + var named = false; + if (names[color]) { + color = names[color]; + named = true; + } + else if (color == 'transparent') { + return { r: 0, g: 0, b: 0, a: 0, format: "name" }; + } + + // Try to match string input using regular expressions. + // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] + // Just return an object and let the conversion functions handle that. + // This way the result will be the same whether the tinycolor is initialized with string or object. + var match; + if ((match = matchers.rgb.exec(color))) { + return { r: match[1], g: match[2], b: match[3] }; + } + if ((match = matchers.rgba.exec(color))) { + return { r: match[1], g: match[2], b: match[3], a: match[4] }; + } + if ((match = matchers.hsl.exec(color))) { + return { h: match[1], s: match[2], l: match[3] }; + } + if ((match = matchers.hsla.exec(color))) { + return { h: match[1], s: match[2], l: match[3], a: match[4] }; + } + if ((match = matchers.hsv.exec(color))) { + return { h: match[1], s: match[2], v: match[3] }; + } + if ((match = matchers.hex8.exec(color))) { + return { + a: convertHexToDecimal(match[1]), + r: parseIntFromHex(match[2]), + g: parseIntFromHex(match[3]), + b: parseIntFromHex(match[4]), + format: named ? "name" : "hex8" + }; + } + if ((match = matchers.hex6.exec(color))) { + return { + r: parseIntFromHex(match[1]), + g: parseIntFromHex(match[2]), + b: parseIntFromHex(match[3]), + format: named ? "name" : "hex" + }; + } + if ((match = matchers.hex3.exec(color))) { + return { + r: parseIntFromHex(match[1] + '' + match[1]), + g: parseIntFromHex(match[2] + '' + match[2]), + b: parseIntFromHex(match[3] + '' + match[3]), + format: named ? "name" : "hex" + }; + } + + return false; + } + + // Expose tinycolor to window, does not need to run in non-browser context. + window.tinycolor = tinycolor; + + })(); + + + $(function () { + if ($.fn.spectrum.load) { + $.fn.spectrum.processNativeColorInputs(); + } + }); + +})(window, jQuery); + /* ============================================================= * bootstrap-combobox.js v1.1.5 * ============================================================= @@ -34093,10 +36174,10 @@ function GetReportTemplate1(doc, invoice, layout, checkMath) doc.setFontSize(9); - SetPdfColor('LightBlue',doc); + SetPdfColor('LightBlue', doc, 'primary'); displayAccount(doc, invoice, 220, layout.accountTop, layout); - SetPdfColor('LightBlue',doc); + SetPdfColor('LightBlue', doc, 'primary'); doc.setFontSize('11'); doc.text(50, layout.headerTop, invoiceLabels.invoice.toUpperCase()); @@ -34166,7 +36247,7 @@ function GetReportTemplate1(doc, invoice, layout, checkMath) doc.text(TmpMsgX, y, Msg); - SetPdfColor('LightBlue',doc); + SetPdfColor('LightBlue', doc, 'primary'); AmountText = formatMoney(invoice.balance_amount, currencyId); headerLeft=layout.headerRight+400; var AmountX = layout.lineTotalRight - (doc.getStringUnitWidth(AmountText) * doc.internal.getFontSize()); @@ -34192,8 +36273,13 @@ function GetReportTemplate2(doc, invoice, layout, checkMath) layout.tableTop = 300; doc.setLineWidth(0.5); - doc.setFillColor(46,43,43); - doc.setFillColor(46,43,43); + + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setFillColor(46,43,43); + } var x1 =0; var y1 = 0; @@ -34257,7 +36343,12 @@ function GetReportTemplate2(doc, invoice, layout, checkMath) //publish filled box doc.setDrawColor(200,200,200); - doc.setFillColor(54,164,152); + + if (NINJA.secondaryColor) { + setDocHexFill(doc, NINJA.secondaryColor); + } else { + doc.setFillColor(54,164,152); + } GlobalY=190; doc.setLineWidth(0.5); @@ -34271,7 +36362,7 @@ function GetReportTemplate2(doc, invoice, layout, checkMath) doc.rect(x1, y1, w2, h2, 'FD'); - SetPdfColor('SomeGreen',doc); + SetPdfColor('SomeGreen', doc, 'secondary'); doc.setFontSize('14'); doc.setFontType("bold"); doc.text(50, GlobalY, invoiceLabels.your_invoice.toUpperCase()); @@ -34343,11 +36434,9 @@ function GetReportTemplate2(doc, invoice, layout, checkMath) AmountText = formatMoney(invoice.balance_amount , currencyId); headerLeft=layout.headerRight+400; var AmountX = headerLeft - (doc.getStringUnitWidth(AmountText) * doc.internal.getFontSize()); - SetPdfColor('SomeGreen',doc); + SetPdfColor('SomeGreen', doc, 'secondary'); doc.text(AmountX, y, AmountText); - - return doc; } @@ -34357,143 +36446,117 @@ function GetReportTemplate2(doc, invoice, layout, checkMath) -function SetPdfColor(color,doc) +function SetPdfColor(color, doc, role) { + if (role === 'primary' && NINJA.primaryColor) { + return setDocHexColor(doc, NINJA.primaryColor); + } else if (role === 'secondary' && NINJA.secondaryColor) { + return setDocHexColor(doc, NINJA.secondaryColor); + } - if (color=='LightBlue') { - return doc.setTextColor(41,156, 194); - } + if (color=='LightBlue') { + return doc.setTextColor(41,156, 194); + } - if (color=='Black') { - return doc.setTextColor(46,43,43);//select color black - } - if (color=='GrayLogo') { - //return doc.setTextColor(207,209, 210);//select color Custom Report GRAY - return doc.setTextColor(207,241, 241);//select color Custom Report GRAY - } + if (color=='Black') { + return doc.setTextColor(46,43,43);//select color black + } + if (color=='GrayLogo') { + return doc.setTextColor(207,241, 241);//select color Custom Report GRAY + } - if (color=='GrayBackground') { - //return doc.setTextColor(207,209, 210);//select color Custom Report GRAY - return doc.setTextColor(251,251, 251);//select color Custom Report GRAY - } + if (color=='GrayBackground') { + return doc.setTextColor(251,251, 251);//select color Custom Report GRAY + } + if (color=='GrayText') { + return doc.setTextColor(161,160,160);//select color Custom Report GRAY Colour + } + if (color=='White') { + return doc.setTextColor(255,255,255);//select color Custom Report GRAY Colour + } - if (color=='GrayText') { - return doc.setTextColor(161,160,160);//select color Custom Report GRAY Colour - } + if (color=='SomeGreen') { + return doc.setTextColor(54,164,152);//select color Custom Report GRAY Colour + } - if (color=='White') { - return doc.setTextColor(255,255,255);//select color Custom Report GRAY Colour - } + if (color=='LightGrayReport2-gray') { + return doc.setTextColor(240,240,240);//select color Custom Report GRAY Colour + } - - - if (color=='SomeGreen') { - return doc.setTextColor(54,164,152);//select color Custom Report GRAY Colour - } - - - - - if (color=='LightGrayReport2-gray') { - return doc.setTextColor(240,240,240);//select color Custom Report GRAY Colour - } - - if (color=='LightGrayReport2-white') { - return doc.setTextColor(251,251,251);//select color Custom Report GRAY Colour - } - - - - - alert('color is not defined'); - return false; + if (color=='LightGrayReport2-white') { + return doc.setTextColor(251,251,251);//select color Custom Report GRAY Colour + } } - function Report2AddFooter (invoice,doc) { + doc.setLineWidth(0.5); + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setFillColor(46,43,43); + doc.setDrawColor(46,43,43); + } - doc.setLineWidth(0.5); - doc.setDrawColor(41,37,37); - doc.setFillColor(41,37,37); + // return doc.setTextColor(240,240,240);//select color Custom Report GRAY Colour + var x1 = 0;//tableLeft-tablePadding ; + var y1 = 750; + var w2 = 596; + var h2 = 94;//doc.internal.getFontSize()*length+length*1.1;//+h;//+tablePadding; - // return doc.setTextColor(240,240,240);//select color Custom Report GRAY Colour - - - - - var x1 = 0;//tableLeft-tablePadding ; - - var y1 = 750; - - var w2 = 596; - var h2 = 94;//doc.internal.getFontSize()*length+length*1.1;//+h;//+tablePadding; - - - - doc.rect(x1, y1, w2, h2, 'FD'); - - - if (!invoice.is_pro && logoImages.imageLogo2) - { - pageHeight=820; - var left = 250;//headerRight ; - y=pageHeight-logoImages.imageLogoHeight2; - var headerRight=370; - - var left = headerRight - logoImages.imageLogoWidth2; - doc.addImage(logoImages.imageLogo2, 'JPEG', left, y, logoImages.imageLogoWidth2, logoImages.imageLogoHeight2); - - - } - + doc.rect(x1, y1, w2, h2, 'FD'); + if (!invoice.is_pro && logoImages.imageLogo2) + { + pageHeight=820; + var left = 250;//headerRight ; + y=pageHeight-logoImages.imageLogoHeight2; + var headerRight=370; + var left = headerRight - logoImages.imageLogoWidth2; + doc.addImage(logoImages.imageLogo2, 'JPEG', left, y, logoImages.imageLogoWidth2, logoImages.imageLogoHeight2); + } } function Report3AddFooter (invoice, account, doc, layout) { - doc.setLineWidth(0.5); + doc.setLineWidth(0.5); + + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { doc.setDrawColor(242,101,34); doc.setFillColor(242,101,34); + } - // return doc.setTextColor(240,240,240);//select color Custom Report GRAY Colour + var x1 = 0;//tableLeft-tablePadding ; + var y1 = 750; + var w2 = 596; + var h2 = 94;//doc.internal.getFontSize()*length+length*1.1;//+h;//+tablePadding; + doc.rect(x1, y1, w2, h2, 'FD'); + if (!invoice.is_pro && logoImages.imageLogo3) + { + pageHeight=820; + // var left = 25;//250;//headerRight ; + y=pageHeight-logoImages.imageLogoHeight3; + //var headerRight=370; + //var left = headerRight - invoice.imageLogoWidth3; + doc.addImage(logoImages.imageLogo3, 'JPEG', 40, y, logoImages.imageLogoWidth3, logoImages.imageLogoHeight3); + } - var x1 = 0;//tableLeft-tablePadding ; - - var y1 = 750; - - var w2 = 596; - var h2 = 94;//doc.internal.getFontSize()*length+length*1.1;//+h;//+tablePadding; - - - - doc.rect(x1, y1, w2, h2, 'FD'); - - - if (!invoice.is_pro && logoImages.imageLogo3) - { - pageHeight=820; - // var left = 25;//250;//headerRight ; - y=pageHeight-logoImages.imageLogoHeight3; - //var headerRight=370; - - //var left = headerRight - invoice.imageLogoWidth3; - doc.addImage(logoImages.imageLogo3, 'JPEG', 40, y, logoImages.imageLogoWidth3, logoImages.imageLogoHeight3); - } - - - doc.setFontSize(10); - var marginLeft = 340; - displayAccount(doc, invoice, marginLeft, 780, layout); + doc.setFontSize(10); + var marginLeft = 340; + displayAccount(doc, invoice, marginLeft, 780, layout); } @@ -34539,8 +36602,14 @@ function GetReportTemplate3(doc, invoice, layout, checkMath) doc.setFontType('bold'); doc.setLineWidth(0.3); - doc.setDrawColor(63,60,60); - doc.setFillColor(63,60,60); + if (NINJA.secondaryColor) { + setDocHexFill(doc, NINJA.secondaryColor); + setDocHexDraw(doc, NINJA.secondaryColor); + } else { + doc.setDrawColor(63,60,60); + doc.setFillColor(63,60,60); + } + var left = layout.marginLeft - layout.tablePadding; var top = layout.tableTop - layout.tablePadding; var width = layout.marginRight - (2 * layout.tablePadding); @@ -34562,6 +36631,13 @@ function GetReportTemplate3(doc, invoice, layout, checkMath) var top = y - layout.tablePadding; var width = layout.marginRight - (2 * layout.tablePadding); var height = 20; + if (NINJA.secondaryColor) { + setDocHexFill(doc, NINJA.secondaryColor); + setDocHexDraw(doc, NINJA.secondaryColor); + } else { + doc.setDrawColor(63,60,60); + doc.setFillColor(63,60,60); + } doc.rect(left, top, width, height, 'FD'); doc.setFontType('bold'); @@ -34588,8 +36664,14 @@ function GetReportTemplate3(doc, invoice, layout, checkMath) function Report3AddHeader (invoice, layout, doc) { doc.setLineWidth(0.5); - doc.setDrawColor(242,101,34); - doc.setFillColor(242,101,34); + + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setDrawColor(242,101,34); + doc.setFillColor(242,101,34); + } var x1 =0; var y1 = 0; @@ -35086,4 +37168,27 @@ function objectEquals(x, y) { var p = Object.keys(x); return Object.keys(y).every(function (i) { return p.indexOf(i) !== -1; }) ? p.every(function (i) { return objectEquals(x[i], y[i]); }) : false; -} \ No newline at end of file +} + +function hexToR(h) {return parseInt((cutHex(h)).substring(0,2),16)} +function hexToG(h) {return parseInt((cutHex(h)).substring(2,4),16)} +function hexToB(h) {return parseInt((cutHex(h)).substring(4,6),16)} +function cutHex(h) {return (h.charAt(0)=="#") ? h.substring(1,7):h} +function setDocHexColor(doc, hex) { + var r = hexToR(hex); + var g = hexToG(hex); + var b = hexToB(hex); + return doc.setTextColor(r, g, b); +} +function setDocHexFill(doc, hex) { + var r = hexToR(hex); + var g = hexToG(hex); + var b = hexToB(hex); + return doc.setFillColor(r, g, b); +} +function setDocHexDraw(doc, hex) { + var r = hexToR(hex); + var g = hexToG(hex); + var b = hexToB(hex); + return doc.setDrawColor(r, g, b); +} diff --git a/public/js/script.js b/public/js/script.js index b6c53cccb33a..2d38f1a898bc 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -707,10 +707,10 @@ function GetReportTemplate1(doc, invoice, layout, checkMath) doc.setFontSize(9); - SetPdfColor('LightBlue',doc); + SetPdfColor('LightBlue', doc, 'primary'); displayAccount(doc, invoice, 220, layout.accountTop, layout); - SetPdfColor('LightBlue',doc); + SetPdfColor('LightBlue', doc, 'primary'); doc.setFontSize('11'); doc.text(50, layout.headerTop, invoiceLabels.invoice.toUpperCase()); @@ -780,7 +780,7 @@ function GetReportTemplate1(doc, invoice, layout, checkMath) doc.text(TmpMsgX, y, Msg); - SetPdfColor('LightBlue',doc); + SetPdfColor('LightBlue', doc, 'primary'); AmountText = formatMoney(invoice.balance_amount, currencyId); headerLeft=layout.headerRight+400; var AmountX = layout.lineTotalRight - (doc.getStringUnitWidth(AmountText) * doc.internal.getFontSize()); @@ -806,8 +806,13 @@ function GetReportTemplate2(doc, invoice, layout, checkMath) layout.tableTop = 300; doc.setLineWidth(0.5); - doc.setFillColor(46,43,43); - doc.setFillColor(46,43,43); + + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setFillColor(46,43,43); + } var x1 =0; var y1 = 0; @@ -871,7 +876,12 @@ function GetReportTemplate2(doc, invoice, layout, checkMath) //publish filled box doc.setDrawColor(200,200,200); - doc.setFillColor(54,164,152); + + if (NINJA.secondaryColor) { + setDocHexFill(doc, NINJA.secondaryColor); + } else { + doc.setFillColor(54,164,152); + } GlobalY=190; doc.setLineWidth(0.5); @@ -885,7 +895,7 @@ function GetReportTemplate2(doc, invoice, layout, checkMath) doc.rect(x1, y1, w2, h2, 'FD'); - SetPdfColor('SomeGreen',doc); + SetPdfColor('SomeGreen', doc, 'secondary'); doc.setFontSize('14'); doc.setFontType("bold"); doc.text(50, GlobalY, invoiceLabels.your_invoice.toUpperCase()); @@ -957,11 +967,9 @@ function GetReportTemplate2(doc, invoice, layout, checkMath) AmountText = formatMoney(invoice.balance_amount , currencyId); headerLeft=layout.headerRight+400; var AmountX = headerLeft - (doc.getStringUnitWidth(AmountText) * doc.internal.getFontSize()); - SetPdfColor('SomeGreen',doc); + SetPdfColor('SomeGreen', doc, 'secondary'); doc.text(AmountX, y, AmountText); - - return doc; } @@ -971,143 +979,117 @@ function GetReportTemplate2(doc, invoice, layout, checkMath) -function SetPdfColor(color,doc) +function SetPdfColor(color, doc, role) { + if (role === 'primary' && NINJA.primaryColor) { + return setDocHexColor(doc, NINJA.primaryColor); + } else if (role === 'secondary' && NINJA.secondaryColor) { + return setDocHexColor(doc, NINJA.secondaryColor); + } - if (color=='LightBlue') { - return doc.setTextColor(41,156, 194); - } + if (color=='LightBlue') { + return doc.setTextColor(41,156, 194); + } - if (color=='Black') { - return doc.setTextColor(46,43,43);//select color black - } - if (color=='GrayLogo') { - //return doc.setTextColor(207,209, 210);//select color Custom Report GRAY - return doc.setTextColor(207,241, 241);//select color Custom Report GRAY - } + if (color=='Black') { + return doc.setTextColor(46,43,43);//select color black + } + if (color=='GrayLogo') { + return doc.setTextColor(207,241, 241);//select color Custom Report GRAY + } - if (color=='GrayBackground') { - //return doc.setTextColor(207,209, 210);//select color Custom Report GRAY - return doc.setTextColor(251,251, 251);//select color Custom Report GRAY - } + if (color=='GrayBackground') { + return doc.setTextColor(251,251, 251);//select color Custom Report GRAY + } + if (color=='GrayText') { + return doc.setTextColor(161,160,160);//select color Custom Report GRAY Colour + } + if (color=='White') { + return doc.setTextColor(255,255,255);//select color Custom Report GRAY Colour + } - if (color=='GrayText') { - return doc.setTextColor(161,160,160);//select color Custom Report GRAY Colour - } + if (color=='SomeGreen') { + return doc.setTextColor(54,164,152);//select color Custom Report GRAY Colour + } - if (color=='White') { - return doc.setTextColor(255,255,255);//select color Custom Report GRAY Colour - } + if (color=='LightGrayReport2-gray') { + return doc.setTextColor(240,240,240);//select color Custom Report GRAY Colour + } - - - if (color=='SomeGreen') { - return doc.setTextColor(54,164,152);//select color Custom Report GRAY Colour - } - - - - - if (color=='LightGrayReport2-gray') { - return doc.setTextColor(240,240,240);//select color Custom Report GRAY Colour - } - - if (color=='LightGrayReport2-white') { - return doc.setTextColor(251,251,251);//select color Custom Report GRAY Colour - } - - - - - alert('color is not defined'); - return false; + if (color=='LightGrayReport2-white') { + return doc.setTextColor(251,251,251);//select color Custom Report GRAY Colour + } } - function Report2AddFooter (invoice,doc) { + doc.setLineWidth(0.5); + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setFillColor(46,43,43); + doc.setDrawColor(46,43,43); + } - doc.setLineWidth(0.5); - doc.setDrawColor(41,37,37); - doc.setFillColor(41,37,37); + // return doc.setTextColor(240,240,240);//select color Custom Report GRAY Colour + var x1 = 0;//tableLeft-tablePadding ; + var y1 = 750; + var w2 = 596; + var h2 = 94;//doc.internal.getFontSize()*length+length*1.1;//+h;//+tablePadding; - // return doc.setTextColor(240,240,240);//select color Custom Report GRAY Colour - - - - - var x1 = 0;//tableLeft-tablePadding ; - - var y1 = 750; - - var w2 = 596; - var h2 = 94;//doc.internal.getFontSize()*length+length*1.1;//+h;//+tablePadding; - - - - doc.rect(x1, y1, w2, h2, 'FD'); - - - if (!invoice.is_pro && logoImages.imageLogo2) - { - pageHeight=820; - var left = 250;//headerRight ; - y=pageHeight-logoImages.imageLogoHeight2; - var headerRight=370; - - var left = headerRight - logoImages.imageLogoWidth2; - doc.addImage(logoImages.imageLogo2, 'JPEG', left, y, logoImages.imageLogoWidth2, logoImages.imageLogoHeight2); - - - } - + doc.rect(x1, y1, w2, h2, 'FD'); + if (!invoice.is_pro && logoImages.imageLogo2) + { + pageHeight=820; + var left = 250;//headerRight ; + y=pageHeight-logoImages.imageLogoHeight2; + var headerRight=370; + var left = headerRight - logoImages.imageLogoWidth2; + doc.addImage(logoImages.imageLogo2, 'JPEG', left, y, logoImages.imageLogoWidth2, logoImages.imageLogoHeight2); + } } function Report3AddFooter (invoice, account, doc, layout) { - doc.setLineWidth(0.5); + doc.setLineWidth(0.5); + + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { doc.setDrawColor(242,101,34); doc.setFillColor(242,101,34); + } - // return doc.setTextColor(240,240,240);//select color Custom Report GRAY Colour + var x1 = 0;//tableLeft-tablePadding ; + var y1 = 750; + var w2 = 596; + var h2 = 94;//doc.internal.getFontSize()*length+length*1.1;//+h;//+tablePadding; + doc.rect(x1, y1, w2, h2, 'FD'); + if (!invoice.is_pro && logoImages.imageLogo3) + { + pageHeight=820; + // var left = 25;//250;//headerRight ; + y=pageHeight-logoImages.imageLogoHeight3; + //var headerRight=370; + //var left = headerRight - invoice.imageLogoWidth3; + doc.addImage(logoImages.imageLogo3, 'JPEG', 40, y, logoImages.imageLogoWidth3, logoImages.imageLogoHeight3); + } - var x1 = 0;//tableLeft-tablePadding ; - - var y1 = 750; - - var w2 = 596; - var h2 = 94;//doc.internal.getFontSize()*length+length*1.1;//+h;//+tablePadding; - - - - doc.rect(x1, y1, w2, h2, 'FD'); - - - if (!invoice.is_pro && logoImages.imageLogo3) - { - pageHeight=820; - // var left = 25;//250;//headerRight ; - y=pageHeight-logoImages.imageLogoHeight3; - //var headerRight=370; - - //var left = headerRight - invoice.imageLogoWidth3; - doc.addImage(logoImages.imageLogo3, 'JPEG', 40, y, logoImages.imageLogoWidth3, logoImages.imageLogoHeight3); - } - - - doc.setFontSize(10); - var marginLeft = 340; - displayAccount(doc, invoice, marginLeft, 780, layout); + doc.setFontSize(10); + var marginLeft = 340; + displayAccount(doc, invoice, marginLeft, 780, layout); } @@ -1153,8 +1135,14 @@ function GetReportTemplate3(doc, invoice, layout, checkMath) doc.setFontType('bold'); doc.setLineWidth(0.3); - doc.setDrawColor(63,60,60); - doc.setFillColor(63,60,60); + if (NINJA.secondaryColor) { + setDocHexFill(doc, NINJA.secondaryColor); + setDocHexDraw(doc, NINJA.secondaryColor); + } else { + doc.setDrawColor(63,60,60); + doc.setFillColor(63,60,60); + } + var left = layout.marginLeft - layout.tablePadding; var top = layout.tableTop - layout.tablePadding; var width = layout.marginRight - (2 * layout.tablePadding); @@ -1176,6 +1164,13 @@ function GetReportTemplate3(doc, invoice, layout, checkMath) var top = y - layout.tablePadding; var width = layout.marginRight - (2 * layout.tablePadding); var height = 20; + if (NINJA.secondaryColor) { + setDocHexFill(doc, NINJA.secondaryColor); + setDocHexDraw(doc, NINJA.secondaryColor); + } else { + doc.setDrawColor(63,60,60); + doc.setFillColor(63,60,60); + } doc.rect(left, top, width, height, 'FD'); doc.setFontType('bold'); @@ -1202,8 +1197,14 @@ function GetReportTemplate3(doc, invoice, layout, checkMath) function Report3AddHeader (invoice, layout, doc) { doc.setLineWidth(0.5); - doc.setDrawColor(242,101,34); - doc.setFillColor(242,101,34); + + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setDrawColor(242,101,34); + doc.setFillColor(242,101,34); + } var x1 =0; var y1 = 0; @@ -1700,4 +1701,27 @@ function objectEquals(x, y) { var p = Object.keys(x); return Object.keys(y).every(function (i) { return p.indexOf(i) !== -1; }) ? p.every(function (i) { return objectEquals(x[i], y[i]); }) : false; -} \ No newline at end of file +} + +function hexToR(h) {return parseInt((cutHex(h)).substring(0,2),16)} +function hexToG(h) {return parseInt((cutHex(h)).substring(2,4),16)} +function hexToB(h) {return parseInt((cutHex(h)).substring(4,6),16)} +function cutHex(h) {return (h.charAt(0)=="#") ? h.substring(1,7):h} +function setDocHexColor(doc, hex) { + var r = hexToR(hex); + var g = hexToG(hex); + var b = hexToB(hex); + return doc.setTextColor(r, g, b); +} +function setDocHexFill(doc, hex) { + var r = hexToR(hex); + var g = hexToG(hex); + var b = hexToB(hex); + return doc.setFillColor(r, g, b); +} +function setDocHexDraw(doc, hex) { + var r = hexToR(hex); + var g = hexToG(hex); + var b = hexToB(hex); + return doc.setDrawColor(r, g, b); +} diff --git a/public/vendor/spectrum/.bower.json b/public/vendor/spectrum/.bower.json new file mode 100644 index 000000000000..960f9788eb11 --- /dev/null +++ b/public/vendor/spectrum/.bower.json @@ -0,0 +1,35 @@ +{ + "name": "spectrum", + "version": "1.3.4", + "main": [ + "./spectrum.css", + "./spectrum.js" + ], + "docs": "http://bgrins.github.com/spectrum", + "homepage": "http://bgrins.github.com/spectrum", + "demo": "http://jsfiddle.net/bgrins/ctkY3/", + "dependencies": { + "jquery": ">=1.7.2" + }, + "ignore": [ + ".gitignore", + ".travis.yml", + "build/", + "docs/", + "example/", + "Gruntfile.js", + "LICENSE", + "README.md", + "test/" + ], + "_release": "1.3.4", + "_resolution": { + "type": "version", + "tag": "1.3.4", + "commit": "77699c6fbd6a52c82987ae877e365af80e5d2ae2" + }, + "_source": "git://github.com/bgrins/spectrum.git", + "_target": "~1.3.4", + "_originalSource": "spectrum", + "_direct": true +} \ No newline at end of file diff --git a/public/vendor/spectrum/bower.json b/public/vendor/spectrum/bower.json new file mode 100644 index 000000000000..bc6873966dbd --- /dev/null +++ b/public/vendor/spectrum/bower.json @@ -0,0 +1,22 @@ +{ + "name": "spectrum", + "version": "1.3.4", + "main": ["./spectrum.css", "./spectrum.js"], + "docs": "http://bgrins.github.com/spectrum", + "homepage": "http://bgrins.github.com/spectrum", + "demo": "http://jsfiddle.net/bgrins/ctkY3/", + "dependencies": { + "jquery": ">=1.7.2" + }, + "ignore": [ + ".gitignore", + ".travis.yml", + "build/", + "docs/", + "example/", + "Gruntfile.js", + "LICENSE", + "README.md", + "test/" + ] +} diff --git a/public/vendor/spectrum/i18n/jquery.spectrum-de.js b/public/vendor/spectrum/i18n/jquery.spectrum-de.js new file mode 100644 index 000000000000..ed5250d0a9cf --- /dev/null +++ b/public/vendor/spectrum/i18n/jquery.spectrum-de.js @@ -0,0 +1,14 @@ +// Spectrum Colorpicker +// German (de) localization +// https://github.com/bgrins/spectrum + +(function ( $ ) { + + var localization = $.spectrum.localization["de"] = { + cancelText: "Abbrechen", + chooseText: "Wählen" + }; + + $.extend($.fn.spectrum.defaults, localization); + +})( jQuery ); diff --git a/public/vendor/spectrum/i18n/jquery.spectrum-dk.js b/public/vendor/spectrum/i18n/jquery.spectrum-dk.js new file mode 100644 index 000000000000..454f5e181d22 --- /dev/null +++ b/public/vendor/spectrum/i18n/jquery.spectrum-dk.js @@ -0,0 +1,14 @@ +// Spectrum Colorpicker +// Danish (dk) localization +// https://github.com/bgrins/spectrum + +(function ( $ ) { + + var localization = $.spectrum.localization["dk"] = { + cancelText: "annuller", + chooseText: "Vælg" + }; + + $.extend($.fn.spectrum.defaults, localization); + +})( jQuery ); diff --git a/public/vendor/spectrum/i18n/jquery.spectrum-es.js b/public/vendor/spectrum/i18n/jquery.spectrum-es.js new file mode 100644 index 000000000000..b43bb66875c5 --- /dev/null +++ b/public/vendor/spectrum/i18n/jquery.spectrum-es.js @@ -0,0 +1,14 @@ +// Spectrum Colorpicker +// Spanish (es) localization +// https://github.com/bgrins/spectrum + +(function ( $ ) { + + var localization = $.spectrum.localization["es"] = { + cancelText: "Cancelar", + chooseText: "Elegir" + }; + + $.extend($.fn.spectrum.defaults, localization); + +})( jQuery ); diff --git a/public/vendor/spectrum/i18n/jquery.spectrum-fi.js b/public/vendor/spectrum/i18n/jquery.spectrum-fi.js new file mode 100644 index 000000000000..e339dd58c5a9 --- /dev/null +++ b/public/vendor/spectrum/i18n/jquery.spectrum-fi.js @@ -0,0 +1,14 @@ +// Spectrum Colorpicker +// Finnish (fi) localization +// https://github.com/bgrins/spectrum + +(function ( $ ) { + + var localization = $.spectrum.localization["fi"] = { + cancelText: "Kumoa", + chooseText: "Valitse" + }; + + $.extend($.fn.spectrum.defaults, localization); + +})( jQuery ); diff --git a/public/vendor/spectrum/i18n/jquery.spectrum-fr.js b/public/vendor/spectrum/i18n/jquery.spectrum-fr.js new file mode 100644 index 000000000000..5ab531221822 --- /dev/null +++ b/public/vendor/spectrum/i18n/jquery.spectrum-fr.js @@ -0,0 +1,14 @@ +// Spectrum Colorpicker +// French (fr) localization +// https://github.com/bgrins/spectrum + +(function ( $ ) { + + var localization = $.spectrum.localization["fr"] = { + cancelText: "Annuler", + chooseText: "Valider" + }; + + $.extend($.fn.spectrum.defaults, localization); + +})( jQuery ); diff --git a/public/vendor/spectrum/i18n/jquery.spectrum-it.js b/public/vendor/spectrum/i18n/jquery.spectrum-it.js new file mode 100644 index 000000000000..de06ecd62ae4 --- /dev/null +++ b/public/vendor/spectrum/i18n/jquery.spectrum-it.js @@ -0,0 +1,14 @@ +// Spectrum Colorpicker +// Italian (it) localization +// https://github.com/bgrins/spectrum + +(function ( $ ) { + + var localization = $.spectrum.localization["it"] = { + cancelText: "annulla", + chooseText: "scegli" + }; + + $.extend($.fn.spectrum.defaults, localization); + +})( jQuery ); diff --git a/public/vendor/spectrum/i18n/jquery.spectrum-ja.js b/public/vendor/spectrum/i18n/jquery.spectrum-ja.js new file mode 100644 index 000000000000..d0fbeb53caaa --- /dev/null +++ b/public/vendor/spectrum/i18n/jquery.spectrum-ja.js @@ -0,0 +1,14 @@ +// Spectrum Colorpicker +// Japanese (ja) localization +// https://github.com/bgrins/spectrum + +(function ( $ ) { + + var localization = $.spectrum.localization["ja"] = { + cancelText: "中止", + chooseText: "選択" + }; + + $.extend($.fn.spectrum.defaults, localization); + +})( jQuery ); diff --git a/public/vendor/spectrum/i18n/jquery.spectrum-nl.js b/public/vendor/spectrum/i18n/jquery.spectrum-nl.js new file mode 100644 index 000000000000..d52de204ee5a --- /dev/null +++ b/public/vendor/spectrum/i18n/jquery.spectrum-nl.js @@ -0,0 +1,15 @@ +// Spectrum Colorpicker +// Dutch (nl-nl) localization +// https://github.com/bgrins/spectrum + +(function ( $ ) { + + var localization = $.spectrum.localization["nl-nl"] = { + cancelText: "Annuleer", + chooseText: "Kies", + clearText: "Wis kleur selectie" + }; + + $.extend($.fn.spectrum.defaults, localization); + +})( jQuery ); diff --git a/public/vendor/spectrum/i18n/jquery.spectrum-pt-br.js b/public/vendor/spectrum/i18n/jquery.spectrum-pt-br.js new file mode 100644 index 000000000000..12ce327ae4ef --- /dev/null +++ b/public/vendor/spectrum/i18n/jquery.spectrum-pt-br.js @@ -0,0 +1,14 @@ +// Spectrum Colorpicker +// Brazilian (pt-br) localization +// https://github.com/bgrins/spectrum + +(function ( $ ) { + + var localization = $.spectrum.localization["pt-br"] = { + cancelText: "Cancelar", + chooseText: "Escolher" + }; + + $.extend($.fn.spectrum.defaults, localization); + +})( jQuery ); diff --git a/public/vendor/spectrum/i18n/jquery.spectrum-ru.js b/public/vendor/spectrum/i18n/jquery.spectrum-ru.js new file mode 100644 index 000000000000..9710ed055d42 --- /dev/null +++ b/public/vendor/spectrum/i18n/jquery.spectrum-ru.js @@ -0,0 +1,14 @@ +// Spectrum Colorpicker +// Russian (ru) localization +// https://github.com/bgrins/spectrum + +(function ( $ ) { + + var localization = $.spectrum.localization["ru"] = { + cancelText: "отмена", + chooseText: "выбрать" + }; + + $.extend($.fn.spectrum.defaults, localization); + +})( jQuery ); diff --git a/public/vendor/spectrum/i18n/jquery.spectrum-sv.js b/public/vendor/spectrum/i18n/jquery.spectrum-sv.js new file mode 100644 index 000000000000..23a1d4752e0a --- /dev/null +++ b/public/vendor/spectrum/i18n/jquery.spectrum-sv.js @@ -0,0 +1,14 @@ +// Spectrum Colorpicker +// Swedish (sv) localization +// https://github.com/bgrins/spectrum + +(function ( $ ) { + + var localization = $.spectrum.localization["sv"] = { + cancelText: "Avbryt", + chooseText: "Välj" + }; + + $.extend($.fn.spectrum.defaults, localization); + +})( jQuery ); diff --git a/public/vendor/spectrum/i18n/jquery.spectrum-tr.js b/public/vendor/spectrum/i18n/jquery.spectrum-tr.js new file mode 100644 index 000000000000..9a02879b2e0d --- /dev/null +++ b/public/vendor/spectrum/i18n/jquery.spectrum-tr.js @@ -0,0 +1,14 @@ +// Spectrum Colorpicker +// Turkish (tr) localization +// https://github.com/bgrins/spectrum + +(function ( $ ) { + + var localization = $.spectrum.localization["tr"] = { + cancelText: "iptal", + chooseText: "tamam" + }; + + $.extend($.fn.spectrum.defaults, localization); + +})( jQuery ); diff --git a/public/vendor/spectrum/index.html b/public/vendor/spectrum/index.html new file mode 100644 index 000000000000..e3f44f348ff4 --- /dev/null +++ b/public/vendor/spectrum/index.html @@ -0,0 +1,1084 @@ + + + + + Spectrum - The No Hassle jQuery Colorpicker + + + + + + + + + + + + + + + +
    +
    + +
    +
    + +
    + +
    +
    +
    +
    + +
    + +
    + +
    +<input type='color' value='#f594d0' />
    +
    +
    + +

    Why A Colorpicker?

    +

    I wasn't satisfied with the solutions available for colorpicking. + Many of them included a ton of images, were hard to skin or customize, or were very large plugins. + Here are the goals I had when making a new one: +

    + +

    Small Footprint

    +
    see a working jsFiddle example
    +

    Just include the needed CSS and JavaScript files, and you are ready to go!

    +
    +<script src='spectrum.js'></script>
    +<link rel='stylesheet' href='spectrum.css' />
    +
    +

    We don't need no stinkin' images!

    +

    Nobody wants to add a bunch of code into their project. Spectrum is contained in two files, and both are careful not to mess with your existing code.

    + +

    Polyfill

    +

    I wanted an option for the most basic use case, a polyfill for the input[type=color] HTML5 control. + This mode needs to work without JavaScript enabled - and fallback to an input[type=text] like other HTML5 inputs. +

    +

    If you don't want this behavior to happen, but still want to use spectrum elsewhere on the page, you can set $.fn.spectrum.load = false; right after loading the script file.

    + + +

    Customizable

    +

    Just because you don't have to change anything to get it to work, doesn't mean you can't! + It is easy to skin and customize the plugin with CSS, and there are a wide range of modes and options to explore. +

    + +

    Mobile Support

    +

    Along with desktop browser support, I wanted a mobile colorpicker that was touch friendly, worked in iOS and Android, and used standards + that maximize future mobile support. +

    + +

    Devtools

    + +

    + Believe it or not, this colorpicker lives inside of Chrome and Safari devtools to make picking colors easier for web developers and designers. +

    + +

    + When I started the project, I wrote about developer tools concept colorpicker implementation. After that, I was contacted on the devtools mailing list and got some initial feedback about the possibility of integrating it with devtools. Then I pulled the jQuery dependency out of a branch and I submitted a patch to the WebKit project. +

    + +

    + From there, I opened a development case, entitled Web Inspector: Add colorpicker functionality to color swatches in Styles Sidebar. 50+ comments and 10 patches later, the case landed in WebKit. Thanks to all the WebKit developers who helped me along the way with getting the code and UI ready for committing. +

    + + +

    Modes

    +

    input[type=color]

    + +

    + If you just want to provide a polyfill for the native color input, + the easiest way is to create an input with the type of color. + Once a user's browser supports a native color control, it will opt to use their native control instead. +

    +

    Unlike the other modes, your value must be a 6 character hex value starting with a '#'. Why? Because the spec says so, that's why. +

    + +
    +<input type='color' name='color' />
    +<input type='color' name='color2' value='#3355cc' />
    +
    +
    +
    + + + + +
    +
    +

    That's it! + The field will degrade to a text input if the user does not have JavaScript enabled, + so that they will still be able to manually enter a color. You don't need to add a single line of code. +

    + +

    Custom

    +

    If you want to get more into the functionality, just create a normal input and initialize it as a normal jQuery plugin. + You can set a lot of options when initializing the colorpicker. + See the 'Options' section below. +

    + +
    +<input type='text' id="custom" />
    +
    + +
    +<script>
    +$("#custom").spectrum({
    +    color: "#f00"
    +});
    +</script>
    +
    + +
    + +
    + +

    Flat

    +

    Flat + This means that it will always show up at full size, + and be positioned as an inline-block element. + Look to the left for a full sized flat picker. +

    + +
    +<input type='text' id="flat" />
    +<br/>
    +<input type='text' id="flat" />
    +
    +
    +$("#flat").spectrum({
    +    flat: true,
    +    showInput: true
    +});
    +$("#flatClearable").spectrum({
    +    flat: true,
    +    showInput: true,
    +    allowEmpty:true
    +});
    +
    + +
    + +
    + +
    + + + +

    Options

    +
    +$("#picker").spectrum({
    +    color: tinycolor,
    +    flat: bool,
    +    showInput: bool,
    +    showInitial: bool,
    +    allowEmpty: bool,
    +    showAlpha: bool,
    +    disabled: bool,
    +    localStorageKey: string,
    +    showPalette: bool,
    +    showPaletteOnly: bool,
    +    showSelectionPalette: bool,
    +    clickoutFiresChange: bool,
    +    cancelText: string,
    +    chooseText: string,
    +    containerClassName: string,
    +    replacerClassName: string,
    +    preferredFormat: string,
    +    maxSelectionSize: int,
    +    palette: [[string]],
    +    selectionPalette: [string]
    +});
    +
    +
    + Tip: options can be specified in an options object in the spectrum initializer, like $(element).spectrum({showAlpha: true }) or on the element's markup, like <input data-show-alpha="true" />. +
    + +

    Color

    +
    +
    +

    + The initial color will be set with the color option. + If you don't pass in a color, Spectrum will use the value attribute on the input. +

    +

    + The color parsing is based on the TinyColor plugin. + This should parse any color string you throw at it.

    +

    +
    + +
    +<input type='text' class='basic' value='red' />
    +<input type='text' class='basic' value='#0f0' />
    +<input type='text' class='basic' value='blue' />
    +<br />
    +<input type='text' class='override' />
    +<br />
    +<input type='text' class='startEmpty' value='' />
    +            
    + +
    +<script>
    +$(".basic").spectrum();
    +$(".override").spectrum({
    +    color: "yellow"
    +});
    +(".startEmpty").spectrum({
    +    allowEmpty: true
    +});
    +</script>
    +            
    +
    + + + +
    + +
    + +
    +
    + +

    Show Input

    +
    +
    +

    You can add an input to allow free form typing. The color parsing is very permissive in the allowed strings. See TinyColor for more details. +

    +
    +$("#showInput").spectrum({
    +    showInput: true
    +});
    +$("#showInputWithClear").spectrum({
    +    showInput: true,
    +    allowEmpty:true
    +});
    +            
    +
    + +
    + +
    +
    + +

    Show Alpha

    +
    +
    +

    You can allow alpha transparency selection. Check out these examples:

    +
    +
    +$("#showAlpha").spectrum({
    +    showAlpha: true
    +});
    +            
    +
    + +
    +
    + +
    +
    + +

    Disabled

    +
    +
    +

    Spectrum can be automatically disabled if you pass in the disabled flag. Additionally, if the input that you initialize spectrum on is disabled, this will be the default value. Note: you cannot enable spectrum if the input is disabled (see below).

    +
    +
    +$("#disabled").spectrum({
    +    disabled: true
    +});
    +$("input:disabled").spectrum({
    +
    +});
    +            
    +
    + + + +
    +
    + +

    Show Palette

    +
    +
    +

    Spectrum can show a palette below the colorpicker to make it convenient for users to choose from frequently or recently used colors. When the colorpicker is closed, the current color will be added to the palette if it isn't there already. Check it out here:

    +
    +
    +$("#showPalette").spectrum({
    +    showPalette: true,
    +    palette: [
    +        ['black', 'white', 'blanchedalmond'],
    +        ['rgb(255, 128, 0);', 'hsv 100 70 50', 'lightyellow']
    +    ]
    +});
    +            
    +
    + +
    +
    + +

    Show Palette Only

    +
    +
    see a working jsFiddle example
    +
    +

    If you'd like, spectrum can show the palettes you specify, and nothing else.

    +
    + +
    +$("#showPaletteOnly").spectrum({
    +    showPaletteOnly: true,
    +    showPalette:true,
    +    color: 'blanchedalmond',
    +    palette: [
    +        ['black', 'white', 'blanchedalmond',
    +        'rgb(255, 128, 0);', 'hsv 100 70 50'],
    +        ['red', 'yellow', 'green', 'blue', 'violet']
    +    ]
    +});
    +            
    +
    + + Result + + +
    +
    + +

    Show Selection Palette

    +
    +
    +

    Spectrum can keep track of what has been selected by the user with the showSelectionPalette option.

    +

    If the localStorageKey option is defined, the selection will be saved in the browser's localStorage object

    +
    + +
    +$("#showSelectionPalette").spectrum({
    +    showPalette: true,
    +    showSelectionPalette: true, // true by default
    +    palette: [ ]
    +});
    +$("#showSelectionPaletteStorage").spectrum({
    +    showPalette: true,
    +    showSelectionPalette: true,
    +    palette: [ ],
    +    localStorageKey: "spectrum.homepage", // Any Spectrum with the same string will share selection
    +});
    +            
    + +
    + This colorpicker will store what you pick:

    +

    + Try switching between the two colorpickers or reloading your page, the chosen colors are always available:

    + + +
    +
    + +

    Clickout Fires Change

    +
    +
    +

    + When clicking outside of the colorpicker, you can force it to fire a change event rather than having it revert the change. +

    +
    + +
    +$("#clickoutFiresChange").spectrum({
    +    clickoutFiresChange: true
    +});
    +$("#clickoutDoesntChange").spectrum({
    +
    +});
    +            
    + +
    + + +
    +
    + +

    Show Initial

    +
    +
    +

    + Spectrum can show the color that was initially set when opening. + This provides an easy way to click back to what was set when opened. +

    +
    + +
    +$("#showInitial").spectrum({
    +    showInitial: true
    +});
    +            
    + +
    + +
    +
    + +

    Show Input and Initial

    +
    +
    +

    If you specify both the showInput and showInitial options, the CSS keeps things in order by wrapping the buttons to the bottom row, and shrinking the input. Note: this is all customizable via CSS.

    +
    +
    +$("#showInputAndInitial").spectrum({
    +    showInitial: true,
    +    showInput: true
    +});
    +            
    + +
    + +
    +
    +

    Show Input, Initial, and Clear

    +
    +
    +

    If you specify both the showInput, showInitial, and allowEmpty options, the CSS keeps things in order by wrapping the buttons to the bottom row, and shrinking the input. Note: this is all customizable via CSS.

    +
    +
    +$("#showInputInitialClear").spectrum({
    +    allowEmpty:true,
    +    showInitial: true,
    +    showInput: true
    +});
    +            
    + +
    + +
    +
    +

    Button Text

    +
    +
    +

    You can set the button's text using cancelText and chooseText properties.

    +
    + +
    +$("#buttonText").spectrum({
    +    allowEmpty:true,
    +    chooseText: "Alright",
    +    cancelText: "No way"
    +});
    +            
    + +
    + +
    +
    + +

    Show Buttons

    +
    +
    +

    + You can show or hide the buttons using the showButtons property. + If there are no buttons, the behavior will be to fire the `change` event (and update the original input) when the picker is closed. +

    +
    + +
    +$("#hideButtons").spectrum({
    +    showButtons: false
    +});
    +            
    + +
    + +
    +
    + +

    Container Class Name

    +
    +
    +

    + You can add an additional class name to the just the container element using the containerClassName property. +

    +
    + +
    +$("#containerClassName").spectrum({
    +    containerClassName: 'awesome'
    +});
    +            
    +
    +.awesome {
    +    background: purple;
    +}
    +            
    + + +
    + +
    +
    + +

    Replacer Class Name

    +
    +
    +

    + You can add an additional class name to just the replacer element using the replacerClassName property. +

    +
    + +
    +$("#replacerClassName").spectrum({
    +    replacerClassName: 'awesome'
    +});
    +            
    +
    +.awesome {
    +    background: purple;
    +}
    +            
    + + +
    + +
    +
    + +

    Preferred Format

    +
    +
    +

    You can set the format that is displayed in the text box.

    +

    This will also change the format that is displayed in the titles from the palette swatches.

    +
    + +
    +$("#preferredHex").spectrum({
    +    preferredFormat: "hex",
    +    showInput: true,
    +    showPalette: true,
    +    palette: [["red", "rgba(0, 255, 0, .5)", "rgb(0, 0, 255)"]]
    +});
    +$("#preferredHex3").spectrum({
    +    preferredFormat: "hex3",
    +    showInput: true,
    +    showPalette: true,
    +    palette: [["red", "rgba(0, 255, 0, .5)", "rgb(0, 0, 255)"]]
    +});
    +$("#preferredHsl").spectrum({
    +    preferredFormat: "hsl",
    +    showInput: true,
    +    showPalette: true,
    +    palette: [["red", "rgba(0, 255, 0, .5)", "rgb(0, 0, 255)"]]
    +});
    +$("#preferredRgb").spectrum({
    +    preferredFormat: "rgb",
    +    showInput: true,
    +    showPalette: true,
    +    palette: [["red", "rgba(0, 255, 0, .5)", "rgb(0, 0, 255)"]]
    +});
    +$("#preferredName").spectrum({
    +    preferredFormat: "name",
    +    showInput: true,
    +    showPalette: true,
    +    palette: [["red", "rgba(0, 255, 0, .5)", "rgb(0, 0, 255)"]]
    +});
    +$("#preferredNone").spectrum({
    +    showInput: true,
    +    showPalette: true,
    +    palette: [["red", "rgba(0, 255, 0, .5)", "rgb(0, 0, 255)"]]
    +});
    +            
    +
    +
    Hex
    + +
    Hex (3 Characters If Possible)
    + +
    Hsl
    + +
    Rgb
    + +
    Name (Falls back to hex)
    + +
    None (Depends on input - try changing formats with the text box)
    + +
    +
    + +

    Events

    + +
    +$("#picker").spectrum({
    +    move: function(tinycolor) { },
    +    show: function(tinycolor) { },
    +    hide: function(tinycolor) { },
    +    beforeShow: function(tinycolor) { },
    +});
    +
    + +

    change

    +
    +
    +

    Called as the original input changes. Only happens when the input is closed or the 'Choose' button is clicked.

    +
    + +
    +change: function(color) {
    +    color.toHexString(); // #ff0000
    +}
    +            
    + +
    + + +
    +
    + +

    move

    + +
    +
    +

    Called as the user moves around within the colorpicker

    +
    + +
    +move: function(color) {
    +    color.toHexString(); // #ff0000
    +}
    +            
    + +
    + + +
    +
    + +

    hide

    + +
    +
    + +

    + Called after the colorpicker is hidden. + This happens when clicking outside of the picker while it is open. + Note, when any colorpicker on the page is shown it will hide any that are already open. + This event is ignored on a flat colorpicker. +

    +
    + +
    +hide: function(color) {
    +    color.toHexString(); // #ff0000
    +}
    +            
    + +
    + + +
    +
    + +

    show

    + +
    +
    +

    + Called after the colorpicker is opened. + This is ignored on a flat colorpicker. + Note, when any colorpicker on the page is shown it will hide any that are already open. +

    +
    + +
    +show: function(color) {
    +    color.toHexString(); // #ff0000
    +}
    +            
    + +
    + + +
    +
    + +

    beforeShow

    + +
    +
    +

    + You can prevent the colorpicker from showing up if you return false in the beforeShow event. + This event is ignored on a flat colorpicker. +

    +
    + +
    +beforeShow: function(color) {
    +    return false; // Will never show up
    +}
    +            
    + +
    + +
    +
    + +

    dragstart

    + +
    +
    +

    + Called at the beginning of a drag event on either + hue slider, alpha slider, or main color picker areas +

    +
    + +
    +$(element).on("dragstart.spectrum"): function(e, color) {
    +    color.toHexString(); // #ff0000
    +}
    +            
    + +
    + + +
    +
    + +

    dragstop

    + +
    +
    +

    + Called at the end of a drag event on either + hue slider, alpha slider, or main color picker areas +

    +
    + +
    +$(element).on("dragstop.spectrum"): function(e, color) {
    +    color.toHexString(); // #ff0000
    +}
    +            
    + +
    + + +
    +
    + + +

    Methods

    +
    +$("#picker").spectrum("show");
    +$("#picker").spectrum("hide");
    +$("#picker").spectrum("toggle");
    +$("#picker").spectrum("get");
    +$("#picker").spectrum("set", colorString);
    +$("#picker").spectrum("container");
    +$("#picker").spectrum("reflow");
    +$("#picker").spectrum("destroy");
    +$("#picker").spectrum("enable");
    +$("#picker").spectrum("disable");
    +$("#picker").spectrum("option", optionName);
    +$("#picker").spectrum("option", optionName, newOptionValue);
    +
    + +

    show

    + +
    +
    +

    + Shows the colorpicker. +

    +
    +
    + +

    hide

    + +
    +
    +

    + Hides the colorpicker. +

    +
    +
    + +

    toggle

    + +
    +
    +

    + Toggles the colorpicker. +

    +

    + Warning: If you are calling toggle from a click handler, make sure you return false to prevent the colorpicker from immediately hiding after it is toggled. +

    +
    + +
    +$("#btn-toggle").click(function() {
    +    $("#toggle").spectrum("toggle");
    +    return false;
    +});
    +            
    + +
    + + +
    +
    + +

    get

    + +
    +
    +

    + Gets the current value from the colorpicker. +

    +
    +
    + +

    set

    + +
    +
    +

    + Setting the colorpicker programmatically will update the original input. +

    +

    + Note: this will not fire the change event, + to prevent infinite loops from calling set from within change. +

    +
    + +
    +<input type='text' value='blanchedalmond' name='triggerSet' id='triggerSet' />
    +<input type='text' placeholder='Enter A Color' id='enterAColor' />
    +<button id='btnEnterAColor'>Trigger Set</button>
    +
    +<script>
    +$("#triggerSet").spectrum();
    +
    +// Show the original input to demonstrate the value changing when calling `set`
    +$("#triggerSet").show();
    +
    +$("#btnEnterAColor").click(function() {
    +    $("#triggerSet").spectrum("set", $("#enterAColor").val());
    +});
    +</script>
    +            
    + +
    +

    + +
    +
    + +

    container

    + +
    +
    +

    + Retrieves the container element of the colorpicker, in case you want to manaully position it or do other things. +

    +
    +
    + +

    reflow

    + +
    +
    +

    + Resets the positioning of the container element. This could be used was hidden when initialized, or if the colorpicker is inside of a moving area. +

    +
    +
    + +

    destroy

    + +
    +
    +

    + Removes the colorpicker functionality and restores the element to its original state. +

    +
    +
    + +

    enable

    + +
    +
    +

    + Allows selection of the colorpicker component. If it is already enabled, this method does nothing. +

    +

    + Additionally, this will cause the original (now hidden) input to be set as disabled. +

    +
    +
    + +

    disable

    + +
    +
    +

    + Disables selection of the colorpicker component. Adds the sp-disabled class onto the replacer element. If it is already disabled, this method does nothing. +

    +

    + Additionally, this will remove the disabled property on the original (now hidden). +

    +
    +
    + +

    option

    + +
    +
    +

    + Calling option with an option name will return the current value of that option. So, for example: +

    +
    +$("input").spectrum({
    +    showInput: true
    +});
    +
    +$("input").spectrum("option", "showInput"); // true
    +                
    +

    + Calling option with an option name and an option value will set the option to the new value. +

    +
    +$("input").spectrum({
    +    showInput: true
    +});
    +
    +$("input").spectrum("option", "showInput", false);
    +$("input").spectrum("option", "showInput"); // false
    +                
    +
    +
    + + +

    Skinning

    + +

    Since it is all built with HTML/CSS, you can skin it easily. There are two parts to the spectrum.css file, the core rules (at the top of the file), and the themable rules (at the bottom). Feel free to tweak these rules to make it look how you want.

    + +

    Non-input elements

    +

    + You can use any element you would like to trigger the colorpicker: Click me to open a colorpicker, though it is strongly recommended to stick with <input> tags. +

    + +

    Nitty Gritty

    + +

    Browser Support

    +

    I wanted this to work in the latest and greatest browsers, but also target backwords compatibility and mobile support. + Here are the currently supported browers: +

      +
    • IE 6+
    • +
    • Chrome 4+
    • +
    • Firefox 3.6+
    • +
    • Safari 4+
    • +
    • Opera 11.1+
    • +
    • iOS
    • +
    + +

    IE Implementation

    +

    + IE Support is provided using + proprietary filters. + Other browsers use CSS gradients. +

    + + +

    Accepted Color Inputs

    +

    Spectrum will use the color passed in to initialize. If there is no color passed in, + it will try to parse a color based on the value of the input. The color parsing is based on the TinyColor plugin, and accepts many forms of input:

    +
    +red
    +#fff
    +fff
    +#ffffff
    +ffffff
    +rgb(255, 0, 0)
    +rgb 255 0 0
    +hsl(0, 100, 50)
    +hsl(0, 100%, 50%)
    +hsl 0 100 50
    +hsl 0 100% 50%
    +hsv(0, 100%, 100%)
    +hsv(0, 100, 100)
    +hsv 0 100% 100%
    +hsv 0 100 100
    +
    +

    It also provides the following forms of output:

    +
    +var t = $("#element").spectrum("get");
    +t.toHex()       // "ff0000"
    +t.toHexString() // "#ff0000"
    +t.toRgb()       // {"r":255,"g":0,"b":0}
    +t.toRgbString() // "rgb(255, 0, 0)"
    +t.toHsv()       // {"h":0,"s":1,"v":1}
    +t.toHsvString() // "hsv(0, 100%, 100%)"
    +t.toHsl()       // {"h":0,"s":1,"l":0.5}
    +t.toHslString() // "hsl(0, 100%, 50%)"
    +t.toName()      // "red"
    +
    + + + + +
    + +
    + + + + + diff --git a/public/vendor/spectrum/package.json b/public/vendor/spectrum/package.json new file mode 100644 index 000000000000..1fd5d039f8c4 --- /dev/null +++ b/public/vendor/spectrum/package.json @@ -0,0 +1,14 @@ +{ + "name": "spectrum", + "version": "1.3.4", + "repository": { + "type": "git", + "url": "https://bgrins.github.com/spectrum" + }, + "devDependencies": { + "grunt": "~0.4.0", + "grunt-contrib-jshint": "~0.4.3", + "grunt-contrib-qunit": "~0.2.0", + "grunt-contrib-uglify": "~0.2.0" + } +} diff --git a/public/vendor/spectrum/spectrum.css b/public/vendor/spectrum/spectrum.css new file mode 100644 index 000000000000..6a83b72501be --- /dev/null +++ b/public/vendor/spectrum/spectrum.css @@ -0,0 +1,519 @@ +/*** +Spectrum Colorpicker v1.3.4 +https://github.com/bgrins/spectrum +Author: Brian Grinstead +License: MIT +***/ + +.sp-container { + position:absolute; + top:0; + left:0; + display:inline-block; + *display: inline; + *zoom: 1; + /* https://github.com/bgrins/spectrum/issues/40 */ + z-index: 9999994; + overflow: hidden; +} +.sp-container.sp-flat { + position: relative; +} + +/* Fix for * { box-sizing: border-box; } */ +.sp-container, +.sp-container * { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +/* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */ +.sp-top { + position:relative; + width: 100%; + display:inline-block; +} +.sp-top-inner { + position:absolute; + top:0; + left:0; + bottom:0; + right:0; +} +.sp-color { + position: absolute; + top:0; + left:0; + bottom:0; + right:20%; +} +.sp-hue { + position: absolute; + top:0; + right:0; + bottom:0; + left:84%; + height: 100%; +} + +.sp-clear-enabled .sp-hue { + top:33px; + height: 77.5%; +} + +.sp-fill { + padding-top: 80%; +} +.sp-sat, .sp-val { + position: absolute; + top:0; + left:0; + right:0; + bottom:0; +} + +.sp-alpha-enabled .sp-top { + margin-bottom: 18px; +} +.sp-alpha-enabled .sp-alpha { + display: block; +} +.sp-alpha-handle { + position:absolute; + top:-4px; + bottom: -4px; + width: 6px; + left: 50%; + cursor: pointer; + border: 1px solid black; + background: white; + opacity: .8; +} +.sp-alpha { + display: none; + position: absolute; + bottom: -14px; + right: 0; + left: 0; + height: 8px; +} +.sp-alpha-inner { + border: solid 1px #333; +} + +.sp-clear { + display: none; +} + +.sp-clear.sp-clear-display { + background-position: center; +} + +.sp-clear-enabled .sp-clear { + display: block; + position:absolute; + top:0px; + right:0; + bottom:0; + left:84%; + height: 28px; +} + +/* Don't allow text selection */ +.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-clear, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button { + -webkit-user-select:none; + -moz-user-select: -moz-none; + -o-user-select:none; + user-select: none; +} + +.sp-container.sp-input-disabled .sp-input-container { + display: none; +} +.sp-container.sp-buttons-disabled .sp-button-container { + display: none; +} +.sp-palette-only .sp-picker-container { + display: none; +} +.sp-palette-disabled .sp-palette-container { + display: none; +} + +.sp-initial-disabled .sp-initial { + display: none; +} + + +/* Gradients for hue, saturation and value instead of images. Not pretty... but it works */ +.sp-sat { + background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0))); + background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0)); + background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); + background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); + background-image: -ms-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); + background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0)); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)"; + filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81'); +} +.sp-val { + background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0))); + background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); + background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); + background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); + background-image: -ms-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); + background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0)); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)"; + filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000'); +} + +.sp-hue { + background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); + background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); + background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); + background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000)); + background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); +} + +/* IE filters do not support multiple color stops. + Generate 6 divs, line them up, and do two color gradients for each. + Yes, really. + */ +.sp-1 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00'); +} +.sp-2 { + height:16%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00'); +} +.sp-3 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff'); +} +.sp-4 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff'); +} +.sp-5 { + height:16%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff'); +} +.sp-6 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000'); +} + +.sp-hidden { + display: none !important; +} + +/* Clearfix hack */ +.sp-cf:before, .sp-cf:after { content: ""; display: table; } +.sp-cf:after { clear: both; } +.sp-cf { *zoom: 1; } + +/* Mobile devices, make hue slider bigger so it is easier to slide */ +@media (max-device-width: 480px) { + .sp-color { right: 40%; } + .sp-hue { left: 63%; } + .sp-fill { padding-top: 60%; } +} +.sp-dragger { + border-radius: 5px; + height: 5px; + width: 5px; + border: 1px solid #fff; + background: #000; + cursor: pointer; + position:absolute; + top:0; + left: 0; +} +.sp-slider { + position: absolute; + top:0; + cursor:pointer; + height: 3px; + left: -1px; + right: -1px; + border: 1px solid #000; + background: white; + opacity: .8; +} + +/* +Theme authors: +Here are the basic themeable display options (colors, fonts, global widths). +See http://bgrins.github.io/spectrum/themes/ for instructions. +*/ + +.sp-container { + border-radius: 0; + background-color: #ECECEC; + border: solid 1px #f0c49B; + padding: 0; +} +.sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue, .sp-clear +{ + font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} +.sp-top +{ + margin-bottom: 3px; +} +.sp-color, .sp-hue, .sp-clear +{ + border: solid 1px #666; +} + +/* Input */ +.sp-input-container { + float:right; + width: 100px; + margin-bottom: 4px; +} +.sp-initial-disabled .sp-input-container { + width: 100%; +} +.sp-input { + font-size: 12px !important; + border: 1px inset; + padding: 4px 5px; + margin: 0; + width: 100%; + background:transparent; + border-radius: 3px; + color: #222; +} +.sp-input:focus { + border: 1px solid orange; +} +.sp-input.sp-validation-error +{ + border: 1px solid red; + background: #fdd; +} +.sp-picker-container , .sp-palette-container +{ + float:left; + position: relative; + padding: 10px; + padding-bottom: 300px; + margin-bottom: -290px; +} +.sp-picker-container +{ + width: 172px; + border-left: solid 1px #fff; +} + +/* Palettes */ +.sp-palette-container +{ + border-right: solid 1px #ccc; +} + +.sp-palette .sp-thumb-el { + display: block; + position:relative; + float:left; + width: 24px; + height: 15px; + margin: 3px; + cursor: pointer; + border:solid 2px transparent; +} +.sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active { + border-color: orange; +} +.sp-thumb-el +{ + position:relative; +} + +/* Initial */ +.sp-initial +{ + float: left; + border: solid 1px #333; +} +.sp-initial span { + width: 30px; + height: 25px; + border:none; + display:block; + float:left; + margin:0; +} + +.sp-initial .sp-clear-display { + background-position: center; +} + +/* Buttons */ +.sp-button-container { + float: right; +} + +/* Replacer (the little preview div that shows up instead of the ) */ +.sp-replacer { + margin:0; + overflow:hidden; + cursor:pointer; + padding: 4px; + display:inline-block; + *zoom: 1; + *display: inline; + border: solid 1px #91765d; + background: #eee; + color: #333; + vertical-align: middle; +} +.sp-replacer:hover, .sp-replacer.sp-active { + border-color: #F0C49B; + color: #111; +} +.sp-replacer.sp-disabled { + cursor:default; + border-color: silver; + color: silver; +} +.sp-dd { + padding: 2px 0; + height: 16px; + line-height: 16px; + float:left; + font-size:10px; +} +.sp-preview +{ + position:relative; + width:25px; + height: 20px; + border: solid 1px #222; + margin-right: 5px; + float:left; + z-index: 0; +} + +.sp-palette +{ + *width: 220px; + max-width: 220px; +} +.sp-palette .sp-thumb-el +{ + width:16px; + height: 16px; + margin:2px 1px; + border: solid 1px #d0d0d0; +} + +.sp-container +{ + padding-bottom:0; +} + + +/* Buttons: http://hellohappy.org/css3-buttons/ */ +.sp-container button { + background-color: #eeeeee; + background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc); + background-image: -moz-linear-gradient(top, #eeeeee, #cccccc); + background-image: -ms-linear-gradient(top, #eeeeee, #cccccc); + background-image: -o-linear-gradient(top, #eeeeee, #cccccc); + background-image: linear-gradient(to bottom, #eeeeee, #cccccc); + border: 1px solid #ccc; + border-bottom: 1px solid #bbb; + border-radius: 3px; + color: #333; + font-size: 14px; + line-height: 1; + padding: 5px 4px; + text-align: center; + text-shadow: 0 1px 0 #eee; + vertical-align: middle; +} +.sp-container button:hover { + background-color: #dddddd; + background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb); + background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb); + background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb); + background-image: -o-linear-gradient(top, #dddddd, #bbbbbb); + background-image: linear-gradient(to bottom, #dddddd, #bbbbbb); + border: 1px solid #bbb; + border-bottom: 1px solid #999; + cursor: pointer; + text-shadow: 0 1px 0 #ddd; +} +.sp-container button:active { + border: 1px solid #aaa; + border-bottom: 1px solid #888; + -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + -ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + -o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; +} +.sp-cancel +{ + font-size: 11px; + color: #d93f3f !important; + margin:0; + padding:2px; + margin-right: 5px; + vertical-align: middle; + text-decoration:none; + +} +.sp-cancel:hover +{ + color: #d93f3f !important; + text-decoration: underline; +} + + +.sp-palette span:hover, .sp-palette span.sp-thumb-active +{ + border-color: #000; +} + +.sp-preview, .sp-alpha, .sp-thumb-el +{ + position:relative; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); +} +.sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner +{ + display:block; + position:absolute; + top:0;left:0;bottom:0;right:0; +} + +.sp-palette .sp-thumb-inner +{ + background-position: 50% 50%; + background-repeat: no-repeat; +} + +.sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner +{ + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=); +} + +.sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner +{ + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=); +} + +.sp-clear-display { + background-repeat:no-repeat; + background-position: center; + background-image: url(data:image/gif;base64,R0lGODlhFAAUAPcAAAAAAJmZmZ2dnZ6enqKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq/Hx8fLy8vT09PX19ff39/j4+Pn5+fr6+vv7+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAAUABQAAAihAP9FoPCvoMGDBy08+EdhQAIJCCMybCDAAYUEARBAlFiQQoMABQhKUJBxY0SPICEYHBnggEmDKAuoPMjS5cGYMxHW3IiT478JJA8M/CjTZ0GgLRekNGpwAsYABHIypcAgQMsITDtWJYBR6NSqMico9cqR6tKfY7GeBCuVwlipDNmefAtTrkSzB1RaIAoXodsABiZAEFB06gIBWC1mLVgBa0AAOw==); +} diff --git a/public/vendor/spectrum/spectrum.jquery.json b/public/vendor/spectrum/spectrum.jquery.json new file mode 100644 index 000000000000..394c5b04b53b --- /dev/null +++ b/public/vendor/spectrum/spectrum.jquery.json @@ -0,0 +1,28 @@ +{ + "name": "spectrum", + "version": "1.3.4", + "title": "Spectrum Colorpicker", + "description": "The No Hassle jQuery Colorpicker", + "docs": "http://bgrins.github.com/spectrum", + "homepage": "http://bgrins.github.com/spectrum", + "demo": "http://jsfiddle.net/bgrins/ctkY3/", + "author": { + "name" : "Brian Grinstead", + "email" : "briangrinstead@gmail.com", + "url" : "http://briangrinstead.com/" + }, + "keywords": [ + "color", + "colorpicker", + "ui" + ], + "licenses": [ + { + "type": "MIT", + "url": "https://github.com/bgrins/spectrum/blob/master/LICENSE" + } + ], + "dependencies": { + "jquery": ">=1.7.2" + } +} \ No newline at end of file diff --git a/public/vendor/spectrum/spectrum.js b/public/vendor/spectrum/spectrum.js new file mode 100644 index 000000000000..8ced40aedb4b --- /dev/null +++ b/public/vendor/spectrum/spectrum.js @@ -0,0 +1,2080 @@ +// Spectrum Colorpicker v1.3.4 +// https://github.com/bgrins/spectrum +// Author: Brian Grinstead +// License: MIT + +(function (window, $, undefined) { + var defaultOpts = { + + // Callbacks + beforeShow: noop, + move: noop, + change: noop, + show: noop, + hide: noop, + + // Options + color: false, + flat: false, + showInput: false, + allowEmpty: false, + showButtons: true, + clickoutFiresChange: false, + showInitial: false, + showPalette: false, + showPaletteOnly: false, + showSelectionPalette: true, + localStorageKey: false, + appendTo: "body", + maxSelectionSize: 7, + cancelText: "cancel", + chooseText: "choose", + clearText: "Clear Color Selection", + preferredFormat: false, + className: "", // Deprecated - use containerClassName and replacerClassName instead. + containerClassName: "", + replacerClassName: "", + showAlpha: false, + theme: "sp-light", + palette: [["#ffffff", "#000000", "#ff0000", "#ff8000", "#ffff00", "#008000", "#0000ff", "#4b0082", "#9400d3"]], + selectionPalette: [], + disabled: false + }, + spectrums = [], + IE = !!/msie/i.exec( window.navigator.userAgent ), + rgbaSupport = (function() { + function contains( str, substr ) { + return !!~('' + str).indexOf(substr); + } + + var elem = document.createElement('div'); + var style = elem.style; + style.cssText = 'background-color:rgba(0,0,0,.5)'; + return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla'); + })(), + inputTypeColorSupport = (function() { + var colorInput = $("")[0]; + return colorInput.type === "color" && colorInput.value !== "!"; + })(), + replaceInput = [ + "
    ", + "
    ", + "
    ", + "
    " + ].join(''), + markup = (function () { + + // IE does not support gradients with multiple stops, so we need to simulate + // that for the rainbow slider with 8 divs that each have a single gradient + var gradientFix = ""; + if (IE) { + for (var i = 1; i <= 6; i++) { + gradientFix += "
    "; + } + } + + return [ + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + gradientFix, + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "", + "
    ", + "
    ", + "
    ", + "", + "", + "
    ", + "
    ", + "
    " + ].join(""); + })(); + + function paletteTemplate (p, color, className, tooltipFormat) { + var html = []; + for (var i = 0; i < p.length; i++) { + var current = p[i]; + if(current) { + var tiny = tinycolor(current); + var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light"; + c += (tinycolor.equals(color, current)) ? " sp-thumb-active" : ""; + + var formattedString = tiny.toString(tooltipFormat || "rgb"); + var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter(); + html.push(''); + } else { + var cls = 'sp-clear-display'; + html.push(''); + } + } + return "
    " + html.join('') + "
    "; + } + + function hideAll() { + for (var i = 0; i < spectrums.length; i++) { + if (spectrums[i]) { + spectrums[i].hide(); + } + } + } + + function instanceOptions(o, callbackContext) { + var opts = $.extend({}, defaultOpts, o); + opts.callbacks = { + 'move': bind(opts.move, callbackContext), + 'change': bind(opts.change, callbackContext), + 'show': bind(opts.show, callbackContext), + 'hide': bind(opts.hide, callbackContext), + 'beforeShow': bind(opts.beforeShow, callbackContext) + }; + + return opts; + } + + function spectrum(element, o) { + + var opts = instanceOptions(o, element), + flat = opts.flat, + showSelectionPalette = opts.showSelectionPalette, + localStorageKey = opts.localStorageKey, + theme = opts.theme, + callbacks = opts.callbacks, + resize = throttle(reflow, 10), + visible = false, + dragWidth = 0, + dragHeight = 0, + dragHelperHeight = 0, + slideHeight = 0, + slideWidth = 0, + alphaWidth = 0, + alphaSlideHelperWidth = 0, + slideHelperHeight = 0, + currentHue = 0, + currentSaturation = 0, + currentValue = 0, + currentAlpha = 1, + palette = [], + paletteArray = [], + paletteLookup = {}, + selectionPalette = opts.selectionPalette.slice(0), + maxSelectionSize = opts.maxSelectionSize, + draggingClass = "sp-dragging", + shiftMovementDirection = null; + + var doc = element.ownerDocument, + body = doc.body, + boundElement = $(element), + disabled = false, + container = $(markup, doc).addClass(theme), + dragger = container.find(".sp-color"), + dragHelper = container.find(".sp-dragger"), + slider = container.find(".sp-hue"), + slideHelper = container.find(".sp-slider"), + alphaSliderInner = container.find(".sp-alpha-inner"), + alphaSlider = container.find(".sp-alpha"), + alphaSlideHelper = container.find(".sp-alpha-handle"), + textInput = container.find(".sp-input"), + paletteContainer = container.find(".sp-palette"), + initialColorContainer = container.find(".sp-initial"), + cancelButton = container.find(".sp-cancel"), + clearButton = container.find(".sp-clear"), + chooseButton = container.find(".sp-choose"), + isInput = boundElement.is("input"), + isInputTypeColor = isInput && inputTypeColorSupport && boundElement.attr("type") === "color", + shouldReplace = isInput && !flat, + replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className).addClass(opts.replacerClassName) : $([]), + offsetElement = (shouldReplace) ? replacer : boundElement, + previewElement = replacer.find(".sp-preview-inner"), + initialColor = opts.color || (isInput && boundElement.val()), + colorOnShow = false, + preferredFormat = opts.preferredFormat, + currentPreferredFormat = preferredFormat, + clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange, + isEmpty = !initialColor, + allowEmpty = opts.allowEmpty && !isInputTypeColor; + + function applyOptions() { + + if (opts.showPaletteOnly) { + opts.showPalette = true; + } + + if (opts.palette) { + palette = opts.palette.slice(0); + paletteArray = $.isArray(palette[0]) ? palette : [palette]; + paletteLookup = {}; + for (var i = 0; i < paletteArray.length; i++) { + for (var j = 0; j < paletteArray[i].length; j++) { + var rgb = tinycolor(paletteArray[i][j]).toRgbString(); + paletteLookup[rgb] = true; + } + } + } + + container.toggleClass("sp-flat", flat); + container.toggleClass("sp-input-disabled", !opts.showInput); + container.toggleClass("sp-alpha-enabled", opts.showAlpha); + container.toggleClass("sp-clear-enabled", allowEmpty); + container.toggleClass("sp-buttons-disabled", !opts.showButtons); + container.toggleClass("sp-palette-disabled", !opts.showPalette); + container.toggleClass("sp-palette-only", opts.showPaletteOnly); + container.toggleClass("sp-initial-disabled", !opts.showInitial); + container.addClass(opts.className).addClass(opts.containerClassName); + + reflow(); + } + + function initialize() { + + if (IE) { + container.find("*:not(input)").attr("unselectable", "on"); + } + + applyOptions(); + + if (shouldReplace) { + boundElement.after(replacer).hide(); + } + + if (!allowEmpty) { + clearButton.hide(); + } + + if (flat) { + boundElement.after(container).hide(); + } + else { + + var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo); + if (appendTo.length !== 1) { + appendTo = $("body"); + } + + appendTo.append(container); + } + + updateSelectionPaletteFromStorage(); + + offsetElement.bind("click.spectrum touchstart.spectrum", function (e) { + if (!disabled) { + toggle(); + } + + e.stopPropagation(); + + if (!$(e.target).is("input")) { + e.preventDefault(); + } + }); + + if(boundElement.is(":disabled") || (opts.disabled === true)) { + disable(); + } + + // Prevent clicks from bubbling up to document. This would cause it to be hidden. + container.click(stopPropagation); + + // Handle user typed input + textInput.change(setFromTextInput); + textInput.bind("paste", function () { + setTimeout(setFromTextInput, 1); + }); + textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } }); + + cancelButton.text(opts.cancelText); + cancelButton.bind("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + hide("cancel"); + }); + + clearButton.attr("title", opts.clearText); + clearButton.bind("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + isEmpty = true; + move(); + + if(flat) { + //for the flat style, this is a change event + updateOriginalInput(true); + } + }); + + chooseButton.text(opts.chooseText); + chooseButton.bind("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + + if (isValid()) { + updateOriginalInput(true); + hide(); + } + }); + + draggable(alphaSlider, function (dragX, dragY, e) { + currentAlpha = (dragX / alphaWidth); + isEmpty = false; + if (e.shiftKey) { + currentAlpha = Math.round(currentAlpha * 10) / 10; + } + + move(); + }, dragStart, dragStop); + + draggable(slider, function (dragX, dragY) { + currentHue = parseFloat(dragY / slideHeight); + isEmpty = false; + if (!opts.showAlpha) { + currentAlpha = 1; + } + move(); + }, dragStart, dragStop); + + draggable(dragger, function (dragX, dragY, e) { + + // shift+drag should snap the movement to either the x or y axis. + if (!e.shiftKey) { + shiftMovementDirection = null; + } + else if (!shiftMovementDirection) { + var oldDragX = currentSaturation * dragWidth; + var oldDragY = dragHeight - (currentValue * dragHeight); + var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY); + + shiftMovementDirection = furtherFromX ? "x" : "y"; + } + + var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x"; + var setValue = !shiftMovementDirection || shiftMovementDirection === "y"; + + if (setSaturation) { + currentSaturation = parseFloat(dragX / dragWidth); + } + if (setValue) { + currentValue = parseFloat((dragHeight - dragY) / dragHeight); + } + + isEmpty = false; + if (!opts.showAlpha) { + currentAlpha = 1; + } + + move(); + + }, dragStart, dragStop); + + if (!!initialColor) { + set(initialColor); + + // In case color was black - update the preview UI and set the format + // since the set function will not run (default color is black). + updateUI(); + currentPreferredFormat = preferredFormat || tinycolor(initialColor).format; + + addColorToSelectionPalette(initialColor); + } + else { + updateUI(); + } + + if (flat) { + show(); + } + + function palletElementClick(e) { + if (e.data && e.data.ignore) { + set($(this).data("color")); + move(); + } + else { + set($(this).data("color")); + move(); + updateOriginalInput(true); + hide(); + } + + return false; + } + + var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum"; + paletteContainer.delegate(".sp-thumb-el", paletteEvent, palletElementClick); + initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, palletElementClick); + } + + function updateSelectionPaletteFromStorage() { + + if (localStorageKey && window.localStorage) { + + // Migrate old palettes over to new format. May want to remove this eventually. + try { + var oldPalette = window.localStorage[localStorageKey].split(",#"); + if (oldPalette.length > 1) { + delete window.localStorage[localStorageKey]; + $.each(oldPalette, function(i, c) { + addColorToSelectionPalette(c); + }); + } + } + catch(e) { } + + try { + selectionPalette = window.localStorage[localStorageKey].split(";"); + } + catch (e) { } + } + } + + function addColorToSelectionPalette(color) { + if (showSelectionPalette) { + var rgb = tinycolor(color).toRgbString(); + if (!paletteLookup[rgb] && $.inArray(rgb, selectionPalette) === -1) { + selectionPalette.push(rgb); + while(selectionPalette.length > maxSelectionSize) { + selectionPalette.shift(); + } + } + + if (localStorageKey && window.localStorage) { + try { + window.localStorage[localStorageKey] = selectionPalette.join(";"); + } + catch(e) { } + } + } + } + + function getUniqueSelectionPalette() { + var unique = []; + if (opts.showPalette) { + for (i = 0; i < selectionPalette.length; i++) { + var rgb = tinycolor(selectionPalette[i]).toRgbString(); + + if (!paletteLookup[rgb]) { + unique.push(selectionPalette[i]); + } + } + } + + return unique.reverse().slice(0, opts.maxSelectionSize); + } + + function drawPalette() { + + var currentColor = get(); + + var html = $.map(paletteArray, function (palette, i) { + return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i, opts.preferredFormat); + }); + + updateSelectionPaletteFromStorage(); + + if (selectionPalette) { + html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection", opts.preferredFormat)); + } + + paletteContainer.html(html.join("")); + } + + function drawInitial() { + if (opts.showInitial) { + var initial = colorOnShow; + var current = get(); + initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial", opts.preferredFormat)); + } + } + + function dragStart() { + if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) { + reflow(); + } + container.addClass(draggingClass); + shiftMovementDirection = null; + boundElement.trigger('dragstart.spectrum', [ get() ]); + } + + function dragStop() { + container.removeClass(draggingClass); + boundElement.trigger('dragstop.spectrum', [ get() ]); + } + + function setFromTextInput() { + + var value = textInput.val(); + + if ((value === null || value === "") && allowEmpty) { + set(null); + updateOriginalInput(true); + } + else { + var tiny = tinycolor(value); + if (tiny.ok) { + set(tiny); + updateOriginalInput(true); + } + else { + textInput.addClass("sp-validation-error"); + } + } + } + + function toggle() { + if (visible) { + hide(); + } + else { + show(); + } + } + + function show() { + var event = $.Event('beforeShow.spectrum'); + + if (visible) { + reflow(); + return; + } + + boundElement.trigger(event, [ get() ]); + + if (callbacks.beforeShow(get()) === false || event.isDefaultPrevented()) { + return; + } + + hideAll(); + visible = true; + + $(doc).bind("click.spectrum", hide); + $(window).bind("resize.spectrum", resize); + replacer.addClass("sp-active"); + container.removeClass("sp-hidden"); + + reflow(); + updateUI(); + + colorOnShow = get(); + + drawInitial(); + callbacks.show(colorOnShow); + boundElement.trigger('show.spectrum', [ colorOnShow ]); + } + + function hide(e) { + + // Return on right click + if (e && e.type == "click" && e.button == 2) { return; } + + // Return if hiding is unnecessary + if (!visible || flat) { return; } + visible = false; + + $(doc).unbind("click.spectrum", hide); + $(window).unbind("resize.spectrum", resize); + + replacer.removeClass("sp-active"); + container.addClass("sp-hidden"); + + var colorHasChanged = !tinycolor.equals(get(), colorOnShow); + + if (colorHasChanged) { + if (clickoutFiresChange && e !== "cancel") { + updateOriginalInput(true); + } + else { + revert(); + } + } + + callbacks.hide(get()); + boundElement.trigger('hide.spectrum', [ get() ]); + } + + function revert() { + set(colorOnShow, true); + } + + function set(color, ignoreFormatChange) { + if (tinycolor.equals(color, get())) { + // Update UI just in case a validation error needs + // to be cleared. + updateUI(); + return; + } + + var newColor, newHsv; + if (!color && allowEmpty) { + isEmpty = true; + } else { + isEmpty = false; + newColor = tinycolor(color); + newHsv = newColor.toHsv(); + + currentHue = (newHsv.h % 360) / 360; + currentSaturation = newHsv.s; + currentValue = newHsv.v; + currentAlpha = newHsv.a; + } + updateUI(); + + if (newColor && newColor.ok && !ignoreFormatChange) { + currentPreferredFormat = preferredFormat || newColor.format; + } + } + + function get(opts) { + opts = opts || { }; + + if (allowEmpty && isEmpty) { + return null; + } + + return tinycolor.fromRatio({ + h: currentHue, + s: currentSaturation, + v: currentValue, + a: Math.round(currentAlpha * 100) / 100 + }, { format: opts.format || currentPreferredFormat }); + } + + function isValid() { + return !textInput.hasClass("sp-validation-error"); + } + + function move() { + updateUI(); + + callbacks.move(get()); + boundElement.trigger('move.spectrum', [ get() ]); + } + + function updateUI() { + + textInput.removeClass("sp-validation-error"); + + updateHelperLocations(); + + // Update dragger background color (gradients take care of saturation and value). + var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 }); + dragger.css("background-color", flatColor.toHexString()); + + // Get a format that alpha will be included in (hex and names ignore alpha) + var format = currentPreferredFormat; + if (currentAlpha < 1 && !(currentAlpha === 0 && format === "name")) { + if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") { + format = "rgb"; + } + } + + var realColor = get({ format: format }), + displayColor = ''; + + //reset background info for preview element + previewElement.removeClass("sp-clear-display"); + previewElement.css('background-color', 'transparent'); + + if (!realColor && allowEmpty) { + // Update the replaced elements background with icon indicating no color selection + previewElement.addClass("sp-clear-display"); + } + else { + var realHex = realColor.toHexString(), + realRgb = realColor.toRgbString(); + + // Update the replaced elements background color (with actual selected color) + if (rgbaSupport || realColor.alpha === 1) { + previewElement.css("background-color", realRgb); + } + else { + previewElement.css("background-color", "transparent"); + previewElement.css("filter", realColor.toFilter()); + } + + if (opts.showAlpha) { + var rgb = realColor.toRgb(); + rgb.a = 0; + var realAlpha = tinycolor(rgb).toRgbString(); + var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")"; + + if (IE) { + alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex)); + } + else { + alphaSliderInner.css("background", "-webkit-" + gradient); + alphaSliderInner.css("background", "-moz-" + gradient); + alphaSliderInner.css("background", "-ms-" + gradient); + // Use current syntax gradient on unprefixed property. + alphaSliderInner.css("background", + "linear-gradient(to right, " + realAlpha + ", " + realHex + ")"); + } + } + + displayColor = realColor.toString(format); + } + + // Update the text entry input as it changes happen + if (opts.showInput) { + textInput.val(displayColor); + } + + if (opts.showPalette) { + drawPalette(); + } + + drawInitial(); + } + + function updateHelperLocations() { + var s = currentSaturation; + var v = currentValue; + + if(allowEmpty && isEmpty) { + //if selected color is empty, hide the helpers + alphaSlideHelper.hide(); + slideHelper.hide(); + dragHelper.hide(); + } + else { + //make sure helpers are visible + alphaSlideHelper.show(); + slideHelper.show(); + dragHelper.show(); + + // Where to show the little circle in that displays your current selected color + var dragX = s * dragWidth; + var dragY = dragHeight - (v * dragHeight); + dragX = Math.max( + -dragHelperHeight, + Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight) + ); + dragY = Math.max( + -dragHelperHeight, + Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight) + ); + dragHelper.css({ + "top": dragY + "px", + "left": dragX + "px" + }); + + var alphaX = currentAlpha * alphaWidth; + alphaSlideHelper.css({ + "left": (alphaX - (alphaSlideHelperWidth / 2)) + "px" + }); + + // Where to show the bar that displays your current selected hue + var slideY = (currentHue) * slideHeight; + slideHelper.css({ + "top": (slideY - slideHelperHeight) + "px" + }); + } + } + + function updateOriginalInput(fireCallback) { + var color = get(), + displayColor = '', + hasChanged = !tinycolor.equals(color, colorOnShow); + + if (color) { + displayColor = color.toString(currentPreferredFormat); + // Update the selection palette with the current color + addColorToSelectionPalette(color); + } + + if (isInput) { + boundElement.val(displayColor); + } + + colorOnShow = color; + + if (fireCallback && hasChanged) { + callbacks.change(color); + boundElement.trigger('change', [ color ]); + } + } + + function reflow() { + dragWidth = dragger.width(); + dragHeight = dragger.height(); + dragHelperHeight = dragHelper.height(); + slideWidth = slider.width(); + slideHeight = slider.height(); + slideHelperHeight = slideHelper.height(); + alphaWidth = alphaSlider.width(); + alphaSlideHelperWidth = alphaSlideHelper.width(); + + if (!flat) { + container.css("position", "absolute"); + container.offset(getOffset(container, offsetElement)); + } + + updateHelperLocations(); + + if (opts.showPalette) { + drawPalette(); + } + + boundElement.trigger('reflow.spectrum'); + } + + function destroy() { + boundElement.show(); + offsetElement.unbind("click.spectrum touchstart.spectrum"); + container.remove(); + replacer.remove(); + spectrums[spect.id] = null; + } + + function option(optionName, optionValue) { + if (optionName === undefined) { + return $.extend({}, opts); + } + if (optionValue === undefined) { + return opts[optionName]; + } + + opts[optionName] = optionValue; + applyOptions(); + } + + function enable() { + disabled = false; + boundElement.attr("disabled", false); + offsetElement.removeClass("sp-disabled"); + } + + function disable() { + hide(); + disabled = true; + boundElement.attr("disabled", true); + offsetElement.addClass("sp-disabled"); + } + + initialize(); + + var spect = { + show: show, + hide: hide, + toggle: toggle, + reflow: reflow, + option: option, + enable: enable, + disable: disable, + set: function (c) { + set(c); + updateOriginalInput(); + }, + get: get, + destroy: destroy, + container: container + }; + + spect.id = spectrums.push(spect) - 1; + + return spect; + } + + /** + * checkOffset - get the offset below/above and left/right element depending on screen position + * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js + */ + function getOffset(picker, input) { + var extraY = 0; + var dpWidth = picker.outerWidth(); + var dpHeight = picker.outerHeight(); + var inputHeight = input.outerHeight(); + var doc = picker[0].ownerDocument; + var docElem = doc.documentElement; + var viewWidth = docElem.clientWidth + $(doc).scrollLeft(); + var viewHeight = docElem.clientHeight + $(doc).scrollTop(); + var offset = input.offset(); + offset.top += inputHeight; + + offset.left -= + Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? + Math.abs(offset.left + dpWidth - viewWidth) : 0); + + offset.top -= + Math.min(offset.top, ((offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? + Math.abs(dpHeight + inputHeight - extraY) : extraY)); + + return offset; + } + + /** + * noop - do nothing + */ + function noop() { + + } + + /** + * stopPropagation - makes the code only doing this a little easier to read in line + */ + function stopPropagation(e) { + e.stopPropagation(); + } + + /** + * Create a function bound to a given object + * Thanks to underscore.js + */ + function bind(func, obj) { + var slice = Array.prototype.slice; + var args = slice.call(arguments, 2); + return function () { + return func.apply(obj, args.concat(slice.call(arguments))); + }; + } + + /** + * Lightweight drag helper. Handles containment within the element, so that + * when dragging, the x is within [0,element.width] and y is within [0,element.height] + */ + function draggable(element, onmove, onstart, onstop) { + onmove = onmove || function () { }; + onstart = onstart || function () { }; + onstop = onstop || function () { }; + var doc = element.ownerDocument || document; + var dragging = false; + var offset = {}; + var maxHeight = 0; + var maxWidth = 0; + var hasTouch = ('ontouchstart' in window); + + var duringDragEvents = {}; + duringDragEvents["selectstart"] = prevent; + duringDragEvents["dragstart"] = prevent; + duringDragEvents["touchmove mousemove"] = move; + duringDragEvents["touchend mouseup"] = stop; + + function prevent(e) { + if (e.stopPropagation) { + e.stopPropagation(); + } + if (e.preventDefault) { + e.preventDefault(); + } + e.returnValue = false; + } + + function move(e) { + if (dragging) { + // Mouseup happened outside of window + if (IE && document.documentMode < 9 && !e.button) { + return stop(); + } + + var touches = e.originalEvent.touches; + var pageX = touches ? touches[0].pageX : e.pageX; + var pageY = touches ? touches[0].pageY : e.pageY; + + var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); + var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); + + if (hasTouch) { + // Stop scrolling in iOS + prevent(e); + } + + onmove.apply(element, [dragX, dragY, e]); + } + } + + function start(e) { + var rightclick = (e.which) ? (e.which == 3) : (e.button == 2); + var touches = e.originalEvent.touches; + + if (!rightclick && !dragging) { + if (onstart.apply(element, arguments) !== false) { + dragging = true; + maxHeight = $(element).height(); + maxWidth = $(element).width(); + offset = $(element).offset(); + + $(doc).bind(duringDragEvents); + $(doc.body).addClass("sp-dragging"); + + if (!hasTouch) { + move(e); + } + + prevent(e); + } + } + } + + function stop() { + if (dragging) { + $(doc).unbind(duringDragEvents); + $(doc.body).removeClass("sp-dragging"); + onstop.apply(element, arguments); + } + dragging = false; + } + + $(element).bind("touchstart mousedown", start); + } + + function throttle(func, wait, debounce) { + var timeout; + return function () { + var context = this, args = arguments; + var throttler = function () { + timeout = null; + func.apply(context, args); + }; + if (debounce) clearTimeout(timeout); + if (debounce || !timeout) timeout = setTimeout(throttler, wait); + }; + } + + function log(){/* jshint -W021 */if(window.console){if(Function.prototype.bind)log=Function.prototype.bind.call(console.log,console);else log=function(){Function.prototype.apply.call(console.log,console,arguments);};log.apply(this,arguments);}} + + /** + * Define a jQuery plugin + */ + var dataID = "spectrum.id"; + $.fn.spectrum = function (opts, extra) { + + if (typeof opts == "string") { + + var returnValue = this; + var args = Array.prototype.slice.call( arguments, 1 ); + + this.each(function () { + var spect = spectrums[$(this).data(dataID)]; + if (spect) { + var method = spect[opts]; + if (!method) { + throw new Error( "Spectrum: no such method: '" + opts + "'" ); + } + + if (opts == "get") { + returnValue = spect.get(); + } + else if (opts == "container") { + returnValue = spect.container; + } + else if (opts == "option") { + returnValue = spect.option.apply(spect, args); + } + else if (opts == "destroy") { + spect.destroy(); + $(this).removeData(dataID); + } + else { + method.apply(spect, args); + } + } + }); + + return returnValue; + } + + // Initializing a new instance of spectrum + return this.spectrum("destroy").each(function () { + var options = $.extend({}, opts, $(this).data()); + var spect = spectrum(this, options); + $(this).data(dataID, spect.id); + }); + }; + + $.fn.spectrum.load = true; + $.fn.spectrum.loadOpts = {}; + $.fn.spectrum.draggable = draggable; + $.fn.spectrum.defaults = defaultOpts; + + $.spectrum = { }; + $.spectrum.localization = { }; + $.spectrum.palettes = { }; + + $.fn.spectrum.processNativeColorInputs = function () { + if (!inputTypeColorSupport) { + $("input[type=color]").spectrum({ + preferredFormat: "hex6" + }); + } + }; + + // TinyColor v0.9.17 + // https://github.com/bgrins/TinyColor + // 2013-08-10, Brian Grinstead, MIT License + + (function() { + + var trimLeft = /^[\s,#]+/, + trimRight = /\s+$/, + tinyCounter = 0, + math = Math, + mathRound = math.round, + mathMin = math.min, + mathMax = math.max, + mathRandom = math.random; + + function tinycolor (color, opts) { + + color = (color) ? color : ''; + opts = opts || { }; + + // If input is already a tinycolor, return itself + if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { + return color; + } + + var rgb = inputToRGB(color); + var r = rgb.r, + g = rgb.g, + b = rgb.b, + a = rgb.a, + roundA = mathRound(100*a) / 100, + format = opts.format || rgb.format; + + // Don't let the range of [0,255] come back in [0,1]. + // Potentially lose a little bit of precision here, but will fix issues where + // .5 gets interpreted as half of the total, instead of half of 1 + // If it was supposed to be 128, this was already taken care of by `inputToRgb` + if (r < 1) { r = mathRound(r); } + if (g < 1) { g = mathRound(g); } + if (b < 1) { b = mathRound(b); } + + return { + ok: rgb.ok, + format: format, + _tc_id: tinyCounter++, + alpha: a, + getAlpha: function() { + return a; + }, + setAlpha: function(value) { + a = boundAlpha(value); + roundA = mathRound(100*a) / 100; + }, + toHsv: function() { + var hsv = rgbToHsv(r, g, b); + return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a }; + }, + toHsvString: function() { + var hsv = rgbToHsv(r, g, b); + var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); + return (a == 1) ? + "hsv(" + h + ", " + s + "%, " + v + "%)" : + "hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")"; + }, + toHsl: function() { + var hsl = rgbToHsl(r, g, b); + return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a }; + }, + toHslString: function() { + var hsl = rgbToHsl(r, g, b); + var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); + return (a == 1) ? + "hsl(" + h + ", " + s + "%, " + l + "%)" : + "hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")"; + }, + toHex: function(allow3Char) { + return rgbToHex(r, g, b, allow3Char); + }, + toHexString: function(allow3Char) { + return '#' + this.toHex(allow3Char); + }, + toHex8: function() { + return rgbaToHex(r, g, b, a); + }, + toHex8String: function() { + return '#' + this.toHex8(); + }, + toRgb: function() { + return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a }; + }, + toRgbString: function() { + return (a == 1) ? + "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" : + "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")"; + }, + toPercentageRgb: function() { + return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a }; + }, + toPercentageRgbString: function() { + return (a == 1) ? + "rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" : + "rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")"; + }, + toName: function() { + if (a === 0) { + return "transparent"; + } + + return hexNames[rgbToHex(r, g, b, true)] || false; + }, + toFilter: function(secondColor) { + var hex8String = '#' + rgbaToHex(r, g, b, a); + var secondHex8String = hex8String; + var gradientType = opts && opts.gradientType ? "GradientType = 1, " : ""; + + if (secondColor) { + var s = tinycolor(secondColor); + secondHex8String = s.toHex8String(); + } + + return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")"; + }, + toString: function(format) { + var formatSet = !!format; + format = format || this.format; + + var formattedString = false; + var hasAlphaAndFormatNotSet = !formatSet && a < 1 && a > 0; + var formatWithAlpha = hasAlphaAndFormatNotSet && (format === "hex" || format === "hex6" || format === "hex3" || format === "name"); + + if (format === "rgb") { + formattedString = this.toRgbString(); + } + if (format === "prgb") { + formattedString = this.toPercentageRgbString(); + } + if (format === "hex" || format === "hex6") { + formattedString = this.toHexString(); + } + if (format === "hex3") { + formattedString = this.toHexString(true); + } + if (format === "hex8") { + formattedString = this.toHex8String(); + } + if (format === "name") { + formattedString = this.toName(); + } + if (format === "hsl") { + formattedString = this.toHslString(); + } + if (format === "hsv") { + formattedString = this.toHsvString(); + } + + if (formatWithAlpha) { + return this.toRgbString(); + } + + return formattedString || this.toHexString(); + } + }; + } + + // If input is an object, force 1 into "1.0" to handle ratios properly + // String input requires "1.0" as input, so 1 will be treated as 1 + tinycolor.fromRatio = function(color, opts) { + if (typeof color == "object") { + var newColor = {}; + for (var i in color) { + if (color.hasOwnProperty(i)) { + if (i === "a") { + newColor[i] = color[i]; + } + else { + newColor[i] = convertToPercentage(color[i]); + } + } + } + color = newColor; + } + + return tinycolor(color, opts); + }; + + // Given a string or object, convert that input to RGB + // Possible string inputs: + // + // "red" + // "#f00" or "f00" + // "#ff0000" or "ff0000" + // "#ff000000" or "ff000000" + // "rgb 255 0 0" or "rgb (255, 0, 0)" + // "rgb 1.0 0 0" or "rgb (1, 0, 0)" + // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" + // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" + // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" + // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" + // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" + // + function inputToRGB(color) { + + var rgb = { r: 0, g: 0, b: 0 }; + var a = 1; + var ok = false; + var format = false; + + if (typeof color == "string") { + color = stringInputToObject(color); + } + + if (typeof color == "object") { + if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { + rgb = rgbToRgb(color.r, color.g, color.b); + ok = true; + format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; + } + else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { + color.s = convertToPercentage(color.s); + color.v = convertToPercentage(color.v); + rgb = hsvToRgb(color.h, color.s, color.v); + ok = true; + format = "hsv"; + } + else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { + color.s = convertToPercentage(color.s); + color.l = convertToPercentage(color.l); + rgb = hslToRgb(color.h, color.s, color.l); + ok = true; + format = "hsl"; + } + + if (color.hasOwnProperty("a")) { + a = color.a; + } + } + + a = boundAlpha(a); + + return { + ok: ok, + format: color.format || format, + r: mathMin(255, mathMax(rgb.r, 0)), + g: mathMin(255, mathMax(rgb.g, 0)), + b: mathMin(255, mathMax(rgb.b, 0)), + a: a + }; + } + + + // Conversion Functions + // -------------------- + + // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: + // + + // `rgbToRgb` + // Handle bounds / percentage checking to conform to CSS color spec + // + // *Assumes:* r, g, b in [0, 255] or [0, 1] + // *Returns:* { r, g, b } in [0, 255] + function rgbToRgb(r, g, b){ + return { + r: bound01(r, 255) * 255, + g: bound01(g, 255) * 255, + b: bound01(b, 255) * 255 + }; + } + + // `rgbToHsl` + // Converts an RGB color value to HSL. + // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] + // *Returns:* { h, s, l } in [0,1] + function rgbToHsl(r, g, b) { + + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + + var max = mathMax(r, g, b), min = mathMin(r, g, b); + var h, s, l = (max + min) / 2; + + if(max == min) { + h = s = 0; // achromatic + } + else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch(max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + + h /= 6; + } + + return { h: h, s: s, l: l }; + } + + // `hslToRgb` + // Converts an HSL color value to RGB. + // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] + // *Returns:* { r, g, b } in the set [0, 255] + function hslToRgb(h, s, l) { + var r, g, b; + + h = bound01(h, 360); + s = bound01(s, 100); + l = bound01(l, 100); + + function hue2rgb(p, q, t) { + if(t < 0) t += 1; + if(t > 1) t -= 1; + if(t < 1/6) return p + (q - p) * 6 * t; + if(t < 1/2) return q; + if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; + return p; + } + + if(s === 0) { + r = g = b = l; // achromatic + } + else { + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1/3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1/3); + } + + return { r: r * 255, g: g * 255, b: b * 255 }; + } + + // `rgbToHsv` + // Converts an RGB color value to HSV + // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] + // *Returns:* { h, s, v } in [0,1] + function rgbToHsv(r, g, b) { + + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + + var max = mathMax(r, g, b), min = mathMin(r, g, b); + var h, s, v = max; + + var d = max - min; + s = max === 0 ? 0 : d / max; + + if(max == min) { + h = 0; // achromatic + } + else { + switch(max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + return { h: h, s: s, v: v }; + } + + // `hsvToRgb` + // Converts an HSV color value to RGB. + // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] + // *Returns:* { r, g, b } in the set [0, 255] + function hsvToRgb(h, s, v) { + + h = bound01(h, 360) * 6; + s = bound01(s, 100); + v = bound01(v, 100); + + var i = math.floor(h), + f = h - i, + p = v * (1 - s), + q = v * (1 - f * s), + t = v * (1 - (1 - f) * s), + mod = i % 6, + r = [v, q, p, p, t, v][mod], + g = [t, v, v, q, p, p][mod], + b = [p, p, t, v, v, q][mod]; + + return { r: r * 255, g: g * 255, b: b * 255 }; + } + + // `rgbToHex` + // Converts an RGB color to hex + // Assumes r, g, and b are contained in the set [0, 255] + // Returns a 3 or 6 character hex + function rgbToHex(r, g, b, allow3Char) { + + var hex = [ + pad2(mathRound(r).toString(16)), + pad2(mathRound(g).toString(16)), + pad2(mathRound(b).toString(16)) + ]; + + // Return a 3 character hex if possible + if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { + return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); + } + + return hex.join(""); + } + // `rgbaToHex` + // Converts an RGBA color plus alpha transparency to hex + // Assumes r, g, b and a are contained in the set [0, 255] + // Returns an 8 character hex + function rgbaToHex(r, g, b, a) { + + var hex = [ + pad2(convertDecimalToHex(a)), + pad2(mathRound(r).toString(16)), + pad2(mathRound(g).toString(16)), + pad2(mathRound(b).toString(16)) + ]; + + return hex.join(""); + } + + // `equals` + // Can be called with any tinycolor input + tinycolor.equals = function (color1, color2) { + if (!color1 || !color2) { return false; } + return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); + }; + tinycolor.random = function() { + return tinycolor.fromRatio({ + r: mathRandom(), + g: mathRandom(), + b: mathRandom() + }); + }; + + + // Modification Functions + // ---------------------- + // Thanks to less.js for some of the basics here + // + + tinycolor.desaturate = function (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.s -= amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); + }; + tinycolor.saturate = function (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.s += amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); + }; + tinycolor.greyscale = function(color) { + return tinycolor.desaturate(color, 100); + }; + tinycolor.lighten = function(color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.l += amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); + }; + tinycolor.darken = function (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.l -= amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); + }; + tinycolor.complement = function(color) { + var hsl = tinycolor(color).toHsl(); + hsl.h = (hsl.h + 180) % 360; + return tinycolor(hsl); + }; + + + // Combination Functions + // --------------------- + // Thanks to jQuery xColor for some of the ideas behind these + // + + tinycolor.triad = function(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) + ]; + }; + tinycolor.tetrad = function(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) + ]; + }; + tinycolor.splitcomplement = function(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), + tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) + ]; + }; + tinycolor.analogous = function(color, results, slices) { + results = results || 6; + slices = slices || 30; + + var hsl = tinycolor(color).toHsl(); + var part = 360 / slices; + var ret = [tinycolor(color)]; + + for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { + hsl.h = (hsl.h + part) % 360; + ret.push(tinycolor(hsl)); + } + return ret; + }; + tinycolor.monochromatic = function(color, results) { + results = results || 6; + var hsv = tinycolor(color).toHsv(); + var h = hsv.h, s = hsv.s, v = hsv.v; + var ret = []; + var modification = 1 / results; + + while (results--) { + ret.push(tinycolor({ h: h, s: s, v: v})); + v = (v + modification) % 1; + } + + return ret; + }; + + + // Readability Functions + // --------------------- + // + + // `readability` + // Analyze the 2 colors and returns an object with the following properties: + // `brightness`: difference in brightness between the two colors + // `color`: difference in color/hue between the two colors + tinycolor.readability = function(color1, color2) { + var a = tinycolor(color1).toRgb(); + var b = tinycolor(color2).toRgb(); + var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000; + var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000; + var colorDiff = ( + Math.max(a.r, b.r) - Math.min(a.r, b.r) + + Math.max(a.g, b.g) - Math.min(a.g, b.g) + + Math.max(a.b, b.b) - Math.min(a.b, b.b) + ); + + return { + brightness: Math.abs(brightnessA - brightnessB), + color: colorDiff + }; + }; + + // `readable` + // http://www.w3.org/TR/AERT#color-contrast + // Ensure that foreground and background color combinations provide sufficient contrast. + // *Example* + // tinycolor.readable("#000", "#111") => false + tinycolor.readable = function(color1, color2) { + var readability = tinycolor.readability(color1, color2); + return readability.brightness > 125 && readability.color > 500; + }; + + // `mostReadable` + // Given a base color and a list of possible foreground or background + // colors for that base, returns the most readable color. + // *Example* + // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" + tinycolor.mostReadable = function(baseColor, colorList) { + var bestColor = null; + var bestScore = 0; + var bestIsReadable = false; + for (var i=0; i < colorList.length; i++) { + + // We normalize both around the "acceptable" breaking point, + // but rank brightness constrast higher than hue. + + var readability = tinycolor.readability(baseColor, colorList[i]); + var readable = readability.brightness > 125 && readability.color > 500; + var score = 3 * (readability.brightness / 125) + (readability.color / 500); + + if ((readable && ! bestIsReadable) || + (readable && bestIsReadable && score > bestScore) || + ((! readable) && (! bestIsReadable) && score > bestScore)) { + bestIsReadable = readable; + bestScore = score; + bestColor = tinycolor(colorList[i]); + } + } + return bestColor; + }; + + + // Big List of Colors + // ------------------ + // + var names = tinycolor.names = { + aliceblue: "f0f8ff", + antiquewhite: "faebd7", + aqua: "0ff", + aquamarine: "7fffd4", + azure: "f0ffff", + beige: "f5f5dc", + bisque: "ffe4c4", + black: "000", + blanchedalmond: "ffebcd", + blue: "00f", + blueviolet: "8a2be2", + brown: "a52a2a", + burlywood: "deb887", + burntsienna: "ea7e5d", + cadetblue: "5f9ea0", + chartreuse: "7fff00", + chocolate: "d2691e", + coral: "ff7f50", + cornflowerblue: "6495ed", + cornsilk: "fff8dc", + crimson: "dc143c", + cyan: "0ff", + darkblue: "00008b", + darkcyan: "008b8b", + darkgoldenrod: "b8860b", + darkgray: "a9a9a9", + darkgreen: "006400", + darkgrey: "a9a9a9", + darkkhaki: "bdb76b", + darkmagenta: "8b008b", + darkolivegreen: "556b2f", + darkorange: "ff8c00", + darkorchid: "9932cc", + darkred: "8b0000", + darksalmon: "e9967a", + darkseagreen: "8fbc8f", + darkslateblue: "483d8b", + darkslategray: "2f4f4f", + darkslategrey: "2f4f4f", + darkturquoise: "00ced1", + darkviolet: "9400d3", + deeppink: "ff1493", + deepskyblue: "00bfff", + dimgray: "696969", + dimgrey: "696969", + dodgerblue: "1e90ff", + firebrick: "b22222", + floralwhite: "fffaf0", + forestgreen: "228b22", + fuchsia: "f0f", + gainsboro: "dcdcdc", + ghostwhite: "f8f8ff", + gold: "ffd700", + goldenrod: "daa520", + gray: "808080", + green: "008000", + greenyellow: "adff2f", + grey: "808080", + honeydew: "f0fff0", + hotpink: "ff69b4", + indianred: "cd5c5c", + indigo: "4b0082", + ivory: "fffff0", + khaki: "f0e68c", + lavender: "e6e6fa", + lavenderblush: "fff0f5", + lawngreen: "7cfc00", + lemonchiffon: "fffacd", + lightblue: "add8e6", + lightcoral: "f08080", + lightcyan: "e0ffff", + lightgoldenrodyellow: "fafad2", + lightgray: "d3d3d3", + lightgreen: "90ee90", + lightgrey: "d3d3d3", + lightpink: "ffb6c1", + lightsalmon: "ffa07a", + lightseagreen: "20b2aa", + lightskyblue: "87cefa", + lightslategray: "789", + lightslategrey: "789", + lightsteelblue: "b0c4de", + lightyellow: "ffffe0", + lime: "0f0", + limegreen: "32cd32", + linen: "faf0e6", + magenta: "f0f", + maroon: "800000", + mediumaquamarine: "66cdaa", + mediumblue: "0000cd", + mediumorchid: "ba55d3", + mediumpurple: "9370db", + mediumseagreen: "3cb371", + mediumslateblue: "7b68ee", + mediumspringgreen: "00fa9a", + mediumturquoise: "48d1cc", + mediumvioletred: "c71585", + midnightblue: "191970", + mintcream: "f5fffa", + mistyrose: "ffe4e1", + moccasin: "ffe4b5", + navajowhite: "ffdead", + navy: "000080", + oldlace: "fdf5e6", + olive: "808000", + olivedrab: "6b8e23", + orange: "ffa500", + orangered: "ff4500", + orchid: "da70d6", + palegoldenrod: "eee8aa", + palegreen: "98fb98", + paleturquoise: "afeeee", + palevioletred: "db7093", + papayawhip: "ffefd5", + peachpuff: "ffdab9", + peru: "cd853f", + pink: "ffc0cb", + plum: "dda0dd", + powderblue: "b0e0e6", + purple: "800080", + red: "f00", + rosybrown: "bc8f8f", + royalblue: "4169e1", + saddlebrown: "8b4513", + salmon: "fa8072", + sandybrown: "f4a460", + seagreen: "2e8b57", + seashell: "fff5ee", + sienna: "a0522d", + silver: "c0c0c0", + skyblue: "87ceeb", + slateblue: "6a5acd", + slategray: "708090", + slategrey: "708090", + snow: "fffafa", + springgreen: "00ff7f", + steelblue: "4682b4", + tan: "d2b48c", + teal: "008080", + thistle: "d8bfd8", + tomato: "ff6347", + turquoise: "40e0d0", + violet: "ee82ee", + wheat: "f5deb3", + white: "fff", + whitesmoke: "f5f5f5", + yellow: "ff0", + yellowgreen: "9acd32" + }; + + // Make it easy to access colors via `hexNames[hex]` + var hexNames = tinycolor.hexNames = flip(names); + + + // Utilities + // --------- + + // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` + function flip(o) { + var flipped = { }; + for (var i in o) { + if (o.hasOwnProperty(i)) { + flipped[o[i]] = i; + } + } + return flipped; + } + + // Return a valid alpha value [0,1] with all invalid values being set to 1 + function boundAlpha(a) { + a = parseFloat(a); + + if (isNaN(a) || a < 0 || a > 1) { + a = 1; + } + + return a; + } + + // Take input from [0, n] and return it as [0, 1] + function bound01(n, max) { + if (isOnePointZero(n)) { n = "100%"; } + + var processPercent = isPercentage(n); + n = mathMin(max, mathMax(0, parseFloat(n))); + + // Automatically convert percentage into number + if (processPercent) { + n = parseInt(n * max, 10) / 100; + } + + // Handle floating point rounding errors + if ((math.abs(n - max) < 0.000001)) { + return 1; + } + + // Convert into [0, 1] range if it isn't already + return (n % max) / parseFloat(max); + } + + // Force a number between 0 and 1 + function clamp01(val) { + return mathMin(1, mathMax(0, val)); + } + + // Parse a base-16 hex value into a base-10 integer + function parseIntFromHex(val) { + return parseInt(val, 16); + } + + // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 + // + function isOnePointZero(n) { + return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; + } + + // Check to see if string passed in is a percentage + function isPercentage(n) { + return typeof n === "string" && n.indexOf('%') != -1; + } + + // Force a hex value to have 2 characters + function pad2(c) { + return c.length == 1 ? '0' + c : '' + c; + } + + // Replace a decimal with it's percentage value + function convertToPercentage(n) { + if (n <= 1) { + n = (n * 100) + "%"; + } + + return n; + } + + // Converts a decimal to a hex value + function convertDecimalToHex(d) { + return Math.round(parseFloat(d) * 255).toString(16); + } + // Converts a hex value to a decimal + function convertHexToDecimal(h) { + return (parseIntFromHex(h) / 255); + } + + var matchers = (function() { + + // + var CSS_INTEGER = "[-\\+]?\\d+%?"; + + // + var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; + + // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. + var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; + + // Actual matching. + // Parentheses and commas are optional, but not required. + // Whitespace can take the place of commas or opening paren + var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + + return { + rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), + rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), + hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), + hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), + hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), + hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, + hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, + hex8: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ + }; + })(); + + // `stringInputToObject` + // Permissive string parsing. Take in a number of formats, and output an object + // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` + function stringInputToObject(color) { + + color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); + var named = false; + if (names[color]) { + color = names[color]; + named = true; + } + else if (color == 'transparent') { + return { r: 0, g: 0, b: 0, a: 0, format: "name" }; + } + + // Try to match string input using regular expressions. + // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] + // Just return an object and let the conversion functions handle that. + // This way the result will be the same whether the tinycolor is initialized with string or object. + var match; + if ((match = matchers.rgb.exec(color))) { + return { r: match[1], g: match[2], b: match[3] }; + } + if ((match = matchers.rgba.exec(color))) { + return { r: match[1], g: match[2], b: match[3], a: match[4] }; + } + if ((match = matchers.hsl.exec(color))) { + return { h: match[1], s: match[2], l: match[3] }; + } + if ((match = matchers.hsla.exec(color))) { + return { h: match[1], s: match[2], l: match[3], a: match[4] }; + } + if ((match = matchers.hsv.exec(color))) { + return { h: match[1], s: match[2], v: match[3] }; + } + if ((match = matchers.hex8.exec(color))) { + return { + a: convertHexToDecimal(match[1]), + r: parseIntFromHex(match[2]), + g: parseIntFromHex(match[3]), + b: parseIntFromHex(match[4]), + format: named ? "name" : "hex8" + }; + } + if ((match = matchers.hex6.exec(color))) { + return { + r: parseIntFromHex(match[1]), + g: parseIntFromHex(match[2]), + b: parseIntFromHex(match[3]), + format: named ? "name" : "hex" + }; + } + if ((match = matchers.hex3.exec(color))) { + return { + r: parseIntFromHex(match[1] + '' + match[1]), + g: parseIntFromHex(match[2] + '' + match[2]), + b: parseIntFromHex(match[3] + '' + match[3]), + format: named ? "name" : "hex" + }; + } + + return false; + } + + // Expose tinycolor to window, does not need to run in non-browser context. + window.tinycolor = tinycolor; + + })(); + + + $(function () { + if ($.fn.spectrum.load) { + $.fn.spectrum.processNativeColorInputs(); + } + }); + +})(window, jQuery); diff --git a/public/vendor/spectrum/themes/index.html b/public/vendor/spectrum/themes/index.html new file mode 100644 index 000000000000..ff202ad83074 --- /dev/null +++ b/public/vendor/spectrum/themes/index.html @@ -0,0 +1,113 @@ + + + + + Spectrum - The No Hassle jQuery Colorpicker + + + + + + + + + + + + + + + + + +
    +

    Themes

    + +
    + This page is in development. +
    + + + +
    +

    Instructions for building themes

    +

    + You can change most any property on spectrum using CSS. Anything from borders and colors, to the size of the draggable areas, to the layout of the colorpicker can be changed with plain CSS. +

    +

    Playing friendly with other themes

    +

    + Please prefix all of your rules with .theme-name. The exception is for changes to .sp-container and .sp-replacer, which will have your theme name applied. +

    +

    + See a basic scaffold for a super simple theme. See sp-dark.css for a slightly more advanced example. +

    +
    +.theme-name.sp-container {
    +
    +}
    +.theme-name.sp-replacer {
    +
    +}
    +.theme-name .sp-preview {
    +
    +}
    +        
    +

    Submitting a theme

    +

    + If you have made some customizations that you would like to share, please open a pull request with the theme file inside of this themes/ directory in the project. Or open an issue with a link to the theme. +

    +
    +
    + + + + + + + diff --git a/public/vendor/spectrum/themes/sp-dark.css b/public/vendor/spectrum/themes/sp-dark.css new file mode 100644 index 000000000000..4acbc7d02aca --- /dev/null +++ b/public/vendor/spectrum/themes/sp-dark.css @@ -0,0 +1,128 @@ +/* Container */ +.sp-dark.sp-container { + background-color: #333; + border: solid 1px #555; +} + +/* Replacer (the little preview div that shows up instead of the ) */ +.sp-dark.sp-replacer { + border: solid 1px #fff; + background: #333; + color: #eee; + vertical-align: middle; +} +.sp-replacer:hover, .sp-replacer.sp-active { + border-color: #F0C49B; + color: #fff; +} +.sp-replacer.sp-disabled { + border-color: silver; + color: silver; +} +.sp-dark .sp-preview { + border: solid 1px #999; +} +.sp-dark .sp-cancel { + color: #f99f9f !important; +} + +.sp-dark, .sp-dark button, .sp-dark input, .sp-color, .sp-hue { + +} + +/* Input */ +.sp-dark .sp-input-container { + +} +.sp-dark .sp-initial-disabled .sp-input-container { + +} +.sp-dark .sp-input { + +} +.sp-dark .sp-input:focus { + +} +.sp-dark .sp-input.sp-validation-error { + +} + +.sp-dark .sp-picker-container , .sp-dark .sp-palette-container { + +} +.sp-dark .sp-picker-container { + +} + +/* Palettes */ +.sp-dark .sp-palette-container { + +} + +.sp-dark .sp-palette .sp-thumb-el { + +} +.sp-dark .sp-palette .sp-thumb-el:hover, .sp-dark .sp-palette .sp-thumb-el.sp-thumb-active { + +} +.sp-dark .sp-thumb-el { +} + +/* Initial */ +.sp-dark .sp-initial { + +} +.sp-dark .sp-initial span { + +} + +/* Buttons */ +.sp-dark .sp-button-container { + +} + +/* Replacer (the little preview div that shows up instead of the ) */ +.sp-dark.sp-replacer { + +} +.sp-dark.sp-replacer:hover, .sp-dark.sp-replacer.sp-active { + border-color: #F0C49B; + color: #111; +} +.sp-dark.sp-replacer.sp-disabled { + +} +.sp-dark .sp-dd { + +} + + + +.sp-dark .sp-preview { + +} +.sp-dark .sp-palette { + +} +.sp-dark .sp-palette .sp-thumb-el { + +} + +.sp-dark button { + +} +.sp-dark button:hover { + +} +.sp-dark button:active { + +} +.sp-dark .sp-cancel { + +} +.sp-dark .sp-cancel:hover { + +} +.sp-dark .sp-palette span:hover, .sp-dark .sp-palette span.sp-thumb-active { + +}