28 | $(".example_default").asColorPicker();
29 |
30 |
42 | $(".example_palettes").asColorPicker({
43 | mode: 'palettes'
44 | });
45 |
46 |
58 | $(".example_complex").asColorPicker({
59 | mode: 'complex'
60 | });
61 |
62 |
74 | $(".example_gradient").asColorPicker({
75 | mode: 'gradient'
76 | });
77 |
78 |
90 | $(".example_gradient_2").asColorPicker({
91 | mode: 'gradient',
92 | gradient: {
93 | switchable: false
94 | }
95 | });
96 |
97 |
113 | $(".example_gradient_value").asColorPicker();
114 |
115 |
127 | $(".example_gradient_color").asColorPicker();
128 |
129 |
142 | $(".example_5").asColorPicker({
143 | hideInput: true
144 | });
145 |
146 |
160 | $(".example_6").asColorPicker({
161 | readonly: true
162 | });
163 |
164 |
178 | $(".example_7").asColorPicker({
179 | hideFireChange: false
180 | });
181 |
182 |
|
|
|
|
|
|
260 | |:--:|:--:|:--:|:--:|:--:|:--:|
261 | | Latest ✓ | Latest ✓ | Latest ✓ | Latest ✓ | 9-11 ✓ | Latest ✓ |
262 |
263 | As a jQuery plugin, you also need to see the [jQuery Browser Support](http://jquery.com/browser-support/).
264 |
265 | ## Contributing
266 | Anyone and everyone is welcome to contribute. Please take a moment to
267 | review the [guidelines for contributing](CONTRIBUTING.md). Make sure you're using the latest version of `jquery-asColorPicker` before submitting an issue. There are several ways to help out:
268 |
269 | * [Bug reports](CONTRIBUTING.md#bug-reports)
270 | * [Feature requests](CONTRIBUTING.md#feature-requests)
271 | * [Pull requests](CONTRIBUTING.md#pull-requests)
272 | * Write test cases for open bug issues
273 | * Contribute to the documentation
274 |
275 | ## Development
276 | `jquery-asColorPicker` is built modularly and uses Gulp as a build system to build its distributable files. To install the necessary dependencies for the build system, please run:
277 |
278 | ```sh
279 | npm install -g gulp
280 | npm install -g babel-cli
281 | npm install
282 | ```
283 |
284 | Then you can generate new distributable files from the sources, using:
285 | ```
286 | gulp build
287 | ```
288 |
289 | More gulp tasks can be found [here](CONTRIBUTING.md#available-tasks).
290 |
291 | ## Changelog
292 | To see the list of recent changes, see [Releases section](https://github.com/amazingSurge/jquery-asColorPicker/releases).
293 |
294 | ## Copyright and license
295 | Copyright (C) 2016 amazingSurge.
296 |
297 | Licensed under [the LGPL license](LICENSE).
298 |
299 | [⬆ back to top](#table-of-contents)
300 |
301 | [bower-image]: https://img.shields.io/bower/v/jquery-asColorPicker.svg?style=flat
302 | [bower-link]: https://david-dm.org/amazingSurge/jquery-asColorPicker/dev-status.svg
303 | [npm-image]: https://badge.fury.io/js/jquery-asColorPicker.svg?style=flat
304 | [npm-url]: https://npmjs.org/package/jquery-asColorPicker
305 | [license]: https://img.shields.io/npm/l/jquery-asColorPicker.svg?style=flat
306 | [prs-welcome]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg
307 | [daviddm-image]: https://david-dm.org/amazingSurge/jquery-asColorPicker.svg?style=flat
308 | [daviddm-url]: https://david-dm.org/amazingSurge/jquery-asColorPicker
--------------------------------------------------------------------------------
/src/asColorPicker.js:
--------------------------------------------------------------------------------
1 | import $ from 'jquery';
2 | import DEFAULTS from './defaults';
3 | import MODES from './modes';
4 |
5 | import AsColor from 'jquery-asColor';
6 |
7 | import alpha from './components/alpha';
8 | import hex from './components/hex';
9 | import hue from './components/hue';
10 | import saturation from './components/saturation';
11 | import buttons from './components/buttons';
12 | import trigger from './components/trigger';
13 | import clear from './components/clear';
14 | import info from './components/info';
15 | import palettes from './components/palettes';
16 | import preview from './components/preview';
17 | import gradient from './components/gradient';
18 |
19 | const NAMESPACE = 'asColorPicker';
20 | const COMPONENTS = {};
21 | const LOCALIZATIONS = {
22 | en: {
23 | cancelText: 'cancel',
24 | applyText: 'apply'
25 | }
26 | };
27 |
28 | let id = 0;
29 |
30 | function createId(api) {
31 | api.id = id;
32 | id++;
33 | }
34 |
35 | class AsColorPicker {
36 | constructor(element, options) {
37 | this.element = element;
38 | this.$element = $(element);
39 |
40 | //flag
41 | this.opened = false;
42 | this.firstOpen = true;
43 | this.disabled = false;
44 | this.initialed = false;
45 | this.originValue = this.element.value;
46 | this.isEmpty = false;
47 |
48 | createId(this);
49 |
50 | this.options = $.extend(true, {}, DEFAULTS, options, this.$element.data());
51 | this.namespace = this.options.namespace;
52 |
53 | this.classes = {
54 | wrap: `${this.namespace}-wrap`,
55 | dropdown: `${this.namespace}-dropdown`,
56 | input: `${this.namespace}-input`,
57 | skin: `${this.namespace}_${this.options.skin}`,
58 | open: `${this.namespace}_open`,
59 | mask: `${this.namespace}-mask`,
60 | hideInput: `${this.namespace}_hideInput`,
61 | disabled: `${this.namespace}_disabled`,
62 | mode: `${this.namespace}-mode_${this.options.mode}`
63 | };
64 |
65 | if (this.options.hideInput) {
66 | this.$element.addClass(this.classes.hideInput);
67 | }
68 |
69 | this.components = MODES[this.options.mode];
70 | this._components = $.extend(true, {}, COMPONENTS);
71 |
72 | this._trigger('init');
73 | this.init();
74 | }
75 |
76 | _trigger(eventType, ...params) {
77 | let data = [this].concat(params);
78 |
79 | // event
80 | this.$element.trigger(`${NAMESPACE}::${eventType}`, data);
81 |
82 | // callback
83 | eventType = eventType.replace(/\b\w+\b/g, (word) => {
84 | return word.substring(0, 1).toUpperCase() + word.substring(1);
85 | });
86 | let onFunction = `on${eventType}`;
87 |
88 | if (typeof this.options[onFunction] === 'function') {
89 | this.options[onFunction].apply(this, params);
90 | }
91 | }
92 |
93 | eventName(events) {
94 | if (typeof events !== 'string' || events === '') {
95 | return `.${this.options.namespace}`;
96 | }
97 | events = events.split(' ');
98 |
99 | let length = events.length;
100 | for (let i = 0; i < length; i++) {
101 | events[i] = `${events[i]}.${this.options.namespace}`;
102 | }
103 | return events.join(' ');
104 | }
105 |
106 | init() {
107 | this.color = AsColor(this.element.value, this.options.color);
108 |
109 | this._create();
110 |
111 | if (this.options.skin) {
112 | this.$dropdown.addClass(this.classes.skin);
113 | this.$element.parent().addClass(this.classes.skin);
114 | }
115 |
116 | if (this.options.readonly) {
117 | this.$element.prop('readonly', true);
118 | }
119 |
120 | this._bindEvent();
121 |
122 | this.initialed = true;
123 | this._trigger('ready');
124 | }
125 |
126 | _create() {
127 | this.$dropdown = $(``);
128 | this.$element.wrap(``).addClass(this.classes.input);
129 |
130 | this.$wrap = this.$element.parent();
131 | this.$body = $('body');
132 |
133 | this.$dropdown.data(NAMESPACE, this);
134 |
135 | let component;
136 | $.each(this.components, (key, options) => {
137 | if (options === true) {
138 | options = {};
139 | }
140 | if (this.options[key] !== undefined) {
141 | options = $.extend(true, {}, options, this.options[key]);
142 | }
143 | if (Object.hasOwnProperty.call(this._components, key)) {
144 | component = this._components[key];
145 | component.init(this, options);
146 | }
147 | });
148 |
149 | this._trigger('create');
150 | }
151 |
152 | _bindEvent() {
153 | this.$element.on(this.eventName('click'), () => {
154 | if (!this.opened) {
155 | this.open();
156 | }
157 | return false;
158 | });
159 |
160 | this.$element.on(this.eventName('keydown'), (e) => {
161 | if (e.keyCode === 9) {
162 | this.close();
163 | } else if (e.keyCode === 13) {
164 | this.val(this.element.value);
165 | this.close();
166 | }
167 | });
168 |
169 | this.$element.on(this.eventName('keyup'), () => {
170 | if (this.color.matchString(this.element.value)) {
171 | this.val(this.element.value);
172 | }
173 | });
174 | }
175 |
176 | opacity(v) {
177 | if (v) {
178 | this.color.alpha(v);
179 | } else {
180 | return this.color.alpha();
181 | }
182 | }
183 |
184 | position() {
185 | const hidden = !this.$element.is(':visible');
186 | const offset = hidden ? this.$trigger.offset() : this.$element.offset();
187 | const height = hidden ? this.$trigger.outerHeight() : this.$element.outerHeight();
188 | const width = hidden ? this.$trigger.outerWidth() : this.$element.outerWidth() + this.$trigger.outerWidth();
189 | const pickerWidth = this.$dropdown.outerWidth(true);
190 | const pickerHeight = this.$dropdown.outerHeight(true);
191 | let top;
192 | let left;
193 |
194 | if (pickerHeight + offset.top > $(window).height() + $(window).scrollTop()) {
195 | top = offset.top - pickerHeight;
196 | } else {
197 | top = offset.top + height;
198 | }
199 |
200 | if (pickerWidth + offset.left > $(window).width() + $(window).scrollLeft()) {
201 | left = offset.left - pickerWidth + width;
202 | } else {
203 | left = offset.left;
204 | }
205 |
206 | this.$dropdown.css({
207 | position: 'absolute',
208 | top,
209 | left
210 | });
211 | }
212 |
213 | open() {
214 | if (this.disabled) {
215 | return;
216 | }
217 | this.originValue = this.element.value;
218 |
219 | if (this.$dropdown[0] !== this.$body.children().last()[0]) {
220 | this.$dropdown.detach().appendTo(this.$body);
221 | }
222 |
223 | this.$mask = $(`.${this.classes.mask}`);
224 | if (this.$mask.length === 0) {
225 | this.createMask();
226 | }
227 |
228 | // ensure the mask is always right before the dropdown
229 | if (this.$dropdown.prev()[0] !== this.$mask[0]) {
230 | this.$dropdown.before(this.$mask);
231 | }
232 |
233 | $("#asColorPicker-dropdown").removeAttr("id");
234 | this.$dropdown.attr("id", "asColorPicker-dropdown");
235 |
236 | // show the mask
237 | this.$mask.show();
238 |
239 | this.position();
240 |
241 | $(window).on(this.eventName('resize'), $.proxy(this.position, this));
242 |
243 | this.$dropdown.addClass(this.classes.open);
244 |
245 | this.opened = true;
246 |
247 | if (this.firstOpen) {
248 | this.firstOpen = false;
249 | this._trigger('firstOpen');
250 | }
251 | this._setup();
252 | this._trigger('open');
253 | }
254 |
255 | createMask() {
256 | this.$mask = $(document.createElement("div"));
257 | this.$mask.attr("class", this.classes.mask);
258 | this.$mask.hide();
259 | this.$mask.appendTo(this.$body);
260 |
261 | this.$mask.on(this.eventName("mousedown touchstart click"), e => {
262 | const $dropdown = $("#asColorPicker-dropdown");
263 | let self;
264 | if ($dropdown.length > 0) {
265 | self = $dropdown.data(NAMESPACE);
266 | if (self.opened) {
267 | if (self.options.hideFireChange) {
268 | self.apply();
269 | } else {
270 | self.cancel();
271 | }
272 | }
273 |
274 | e.preventDefault();
275 | e.stopPropagation();
276 | }
277 | });
278 | }
279 |
280 | close() {
281 | this.opened = false;
282 | this.$element.blur();
283 | this.$mask.hide();
284 |
285 | this.$dropdown.removeClass(this.classes.open);
286 |
287 | $(window).off(this.eventName('resize'));
288 |
289 | this._trigger('close');
290 | }
291 |
292 | clear() {
293 | this.val('');
294 | }
295 |
296 | cancel() {
297 | this.close();
298 |
299 | this.set(this.originValue);
300 | }
301 |
302 | apply() {
303 | this._trigger('apply', this.color);
304 | this.close();
305 | }
306 |
307 | val(value) {
308 | if (typeof value === 'undefined') {
309 | return this.color.toString();
310 | }
311 |
312 | this.set(value);
313 | }
314 |
315 | _update() {
316 | this._trigger('update', this.color);
317 | this._updateInput();
318 | }
319 |
320 | _updateInput() {
321 | let value = this.color.toString();
322 | if (this.isEmpty) {
323 | value = '';
324 | }
325 | this._trigger('change', value);
326 | this.$element.val(value);
327 | }
328 |
329 | set(value) {
330 | if (value !== '') {
331 | this.isEmpty = false;
332 | } else {
333 | this.isEmpty = true;
334 | }
335 | return this._set(value);
336 | }
337 |
338 | _set(value) {
339 | if (typeof value === 'string') {
340 | this.color.val(value);
341 | } else {
342 | this.color.set(value);
343 | }
344 |
345 | this._update();
346 | }
347 |
348 | _setup() {
349 | this._trigger('setup', this.color);
350 | }
351 |
352 | get() {
353 | return this.color;
354 | }
355 |
356 | enable() {
357 | this.disabled = false;
358 | this.$parent.addClass(this.classes.disabled);
359 | this._trigger('enable');
360 | return this;
361 | }
362 |
363 | disable() {
364 | this.disabled = true;
365 | this.$parent.removeClass(this.classes.disabled);
366 | this._trigger('disable');
367 | return this;
368 | }
369 |
370 | destroy() {
371 | this.$element.unwrap();
372 | this.$element.off(this.eventName());
373 | this.$mask.remove();
374 | this.$dropdown.remove();
375 |
376 | this.initialized = false;
377 | this.$element.data(NAMESPACE, null);
378 |
379 | this._trigger('destroy');
380 | return this;
381 | }
382 |
383 | getString(name, def) {
384 | if(this.options.lang in LOCALIZATIONS && typeof LOCALIZATIONS[this.options.lang][name] !== 'undefined') {
385 | return LOCALIZATIONS[this.options.lang][name];
386 | }
387 | return def;
388 | }
389 |
390 | static setLocalization(lang, strings) {
391 | LOCALIZATIONS[lang] = strings;
392 | }
393 |
394 | static registerComponent(name, method) {
395 | COMPONENTS[name] = method;
396 | }
397 |
398 | static setDefaults(options) {
399 | $.extend(true, DEFAULTS, $.isPlainObject(options) && options);
400 | }
401 | }
402 |
403 | AsColorPicker.registerComponent('alpha', alpha);
404 | AsColorPicker.registerComponent('hex', hex);
405 | AsColorPicker.registerComponent('hue', hue);
406 | AsColorPicker.registerComponent('saturation', saturation);
407 | AsColorPicker.registerComponent('buttons', buttons);
408 | AsColorPicker.registerComponent('trigger', trigger);
409 | AsColorPicker.registerComponent('clear', clear);
410 | AsColorPicker.registerComponent('info', info);
411 | AsColorPicker.registerComponent('palettes', palettes);
412 | AsColorPicker.registerComponent('preview', preview);
413 | AsColorPicker.registerComponent('gradient', gradient);
414 |
415 | export default AsColorPicker;
416 |
--------------------------------------------------------------------------------
/src/components/gradient.js:
--------------------------------------------------------------------------------
1 | import AsGradient from 'jquery-asGradient';
2 | import AsColor from 'jquery-asColor';
3 |
4 | // gradient
5 | function conventToPercentage(n) {
6 | if (n < 0) {
7 | n = 0;
8 | } else if (n > 1) {
9 | n = 1;
10 | }
11 | return `${n * 100}%`;
12 | }
13 |
14 | var Gradient = function(api, options) {
15 | this.api = api;
16 | this.options = options;
17 | this.classes = {
18 | enable: `${api.namespace}-gradient_enable`,
19 | marker: `${api.namespace}-gradient-marker`,
20 | active: `${api.namespace}-gradient-marker_active`,
21 | focus: `${api.namespace}-gradient_focus`
22 | };
23 | this.isEnabled = false;
24 | this.initialized = false;
25 | this.current = null;
26 | this.value = AsGradient(this.options.settings);
27 | this.$doc = $(document);
28 |
29 | const that = this;
30 | $.extend(that, {
31 | init() {
32 | that.$wrap = $(that.options.template.call(that)).appendTo(api.$dropdown);
33 |
34 | that.$gradient = that.$wrap.filter(`.${api.namespace}-gradient`);
35 |
36 | this.angle.init();
37 | this.preview.init();
38 | this.markers.init();
39 | this.wheel.init();
40 |
41 | this.bind();
42 |
43 | if (that.options.switchable === false || this.value.matchString(api.element.value)) {
44 | that.enable();
45 | }
46 | this.initialized = true;
47 | },
48 | bind() {
49 | const namespace = api.namespace;
50 |
51 | that.$gradient.on('update', () => {
52 | const current = that.value.getById(that.current);
53 |
54 | if (current) {
55 | api._trigger('update', current.color, that.value);
56 | }
57 |
58 | if (api.element.value !== that.value.toString()) {
59 | api._updateInput();
60 | }
61 | });
62 |
63 | // that.$gradient.on('add', function(e, data) {
64 | // if (data.stop) {
65 | // that.active(data.stop.id);
66 | // api._trigger('update', data.stop.color, that.value);
67 | // api._updateInput();
68 | // }
69 | // });
70 |
71 | if (that.options.switchable) {
72 | that.$wrap.on('click', `.${namespace}-gradient-switch`, () => {
73 | if (that.isEnabled) {
74 | that.disable();
75 | } else {
76 | that.enable();
77 | }
78 |
79 | return false;
80 | });
81 | }
82 |
83 | that.$wrap.on('click', `.${namespace}-gradient-cancel`, () => {
84 | if (that.options.switchable === false || AsGradient.matchString(api.originValue)) {
85 | that.overrideCore();
86 | }
87 |
88 | api.cancel();
89 |
90 | return false;
91 | });
92 | },
93 | overrideCore() {
94 | api.set = value => {
95 | if (value !== '') {
96 | api.isEmpty = false;
97 | } else {
98 | api.isEmpty = true;
99 | }
100 | if (typeof value === 'string') {
101 | if (that.options.switchable === false || AsGradient.matchString(value)) {
102 | if (that.isEnabled) {
103 | that.val(value);
104 | api.color = that.value;
105 | that.$gradient.trigger('update', that.value.value);
106 | } else {
107 | that.enable(value);
108 | }
109 | } else {
110 | that.disable();
111 | api.val(value);
112 | }
113 | } else {
114 | const current = that.value.getById(that.current);
115 |
116 | if (current) {
117 | current.color.val(value)
118 | api._trigger('update', current.color, that.value);
119 | }
120 |
121 | that.$gradient.trigger('update', {
122 | id: that.current,
123 | stop: current
124 | });
125 | }
126 | };
127 |
128 | api._setup = () => {
129 | const current = that.value.getById(that.current);
130 |
131 | api._trigger('setup', current.color);
132 | };
133 | },
134 | revertCore() {
135 | api.set = $.proxy(api._set, api);
136 | api._setup = () => {
137 | api._trigger('setup', api.color);
138 | };
139 | },
140 | preview: {
141 | init() {
142 | that.$preview = that.$gradient.find(`.${api.namespace}-gradient-preview`);
143 |
144 | that.$gradient.on('add del update empty', () => {
145 | this.render();
146 | });
147 | },
148 | render() {
149 | that.$preview.css({
150 | 'background-image': that.value.toStringWithAngle('to right', true),
151 | });
152 | that.$preview.css({
153 | 'background-image': that.value.toStringWithAngle('to right'),
154 | });
155 | }
156 | },
157 | markers: {
158 | width: 160,
159 | init() {
160 | that.$markers = that.$gradient.find(`.${api.namespace}-gradient-markers`).attr('tabindex', 0);
161 |
162 | that.$gradient.on('add', (e, data) => {
163 | this.add(data.stop);
164 | });
165 |
166 | that.$gradient.on('active', (e, data) => {
167 | this.active(data.id);
168 | });
169 |
170 | that.$gradient.on('del', (e, data) => {
171 | this.del(data.id);
172 | });
173 |
174 | that.$gradient.on('update', (e, data) => {
175 | if (data.stop) {
176 | this.update(data.stop.id, data.stop.color);
177 | }
178 | });
179 |
180 | that.$gradient.on('empty', () => {
181 | this.empty();
182 | });
183 |
184 | that.$markers.on(that.api.eventName('mousedown'), e => {
185 | const rightclick = (e.which) ? (e.which === 3) : (e.button === 2);
186 | if (rightclick) {
187 | return false;
188 | }
189 |
190 | const position = parseFloat((e.pageX - that.$markers.offset().left) / that.markers.width, 10);
191 | that.add('#fff', position);
192 | return false;
193 | });
194 |
195 | /* eslint consistent-this: "off" */
196 | let self = this;
197 | that.$markers.on(that.api.eventName('mousedown'), 'li', function(e) {
198 | const rightclick = (e.which) ? (e.which === 3) : (e.button === 2);
199 | if (rightclick) {
200 | return false;
201 | }
202 | self.mousedown(this, e);
203 | return false;
204 | });
205 |
206 | that.$doc.on(that.api.eventName('keydown'), e => {
207 | if (that.api.opened && that.$markers.is(`.${that.classes.focus}`)) {
208 |
209 | const key = e.keyCode || e.which;
210 | if (key === 46 || key === 8) {
211 | if (that.value.length <= 2) {
212 | return false;
213 | }
214 |
215 | that.del(that.current);
216 |
217 | return false;
218 | }
219 | }
220 | });
221 |
222 | that.$markers.on(that.api.eventName('focus'), () => {
223 | that.$markers.addClass(that.classes.focus);
224 | }).on(that.api.eventName('blur'), () => {
225 | that.$markers.removeClass(that.classes.focus);
226 | });
227 |
228 | that.$markers.on(that.api.eventName('click'), 'li', function() {
229 | const id = $(this).data('id');
230 | that.active(id);
231 | });
232 | },
233 | getMarker(id) {
234 | return that.$markers.find(`[data-id="${id}"]`);
235 | },
236 | update(id, color) {
237 | const $marker = this.getMarker(id);
238 | $marker.find('span').css('background-color', color.toHEX());
239 | $marker.find('i').css('background-color', color.toHEX());
240 | },
241 | add(stop) {
242 | $(`