(function($) { var entryTemplate, pickerTemplate, typeSelectTemplate, $document, radius = 84, square = 100, shift = 97, dragging = false, off = 13, defaults = { color: '#000000', alpha: 100, name: '', index: 0, type: kt_Color.HEX, status: 1 }; var sanitizeVariableName = function(string, fallback) { var sanitized = string.replace(/%[a-fA-F0-9_-]/, ''); sanitized = sanitized.replace(/[^A-Za-z0-9_-]/, ''); if (sanitized === '' && fallback) { return sanitizeVariableName(fallback); } return sanitized; }; var Entry = function(container, options) { if (!(this instanceof Entry)) { return new Entry(container, options); } if (!entryTemplate) { entryTemplate = wp.template('kt_color_entry'); pickerTemplate = $('#tmpl-kt_color_picker').html(); typeSelectTemplate = $('#tmpl-kt_color_type_select').html(); $document = $(document); } var init = $.extend({}, defaults, options); var self = this; this.color = kt_Color(init.color); this.color.setAlpha(init.alpha); this.color.setName(init.name); this.color.enableAutoname(init.name == ''); this.color._type = init.type; this.$picker = $(pickerTemplate).appendTo(document.body); this.$type = $(typeSelectTemplate).appendTo(document.body); this.$type.children('[data-type=' + init.type + ']').addClass('active'); this.$el = $(entryTemplate(init)).appendTo(container); var background = kt_Color('#FF0000'); var set = 'sl'; var autoVariable = init.variable == ''; this.el = { $colorBtn: self.$el.find('.color-btn'), $rgbSample: self.$el.find('.sample .rgb'), $rgbaSample: self.$el.find('.sample .rgba'), $colorInput: self.$el.find('.color-input'), $alphaInput: self.$el.find('.alpha-input'), $hex: self.$el.find('.color-hex'), $type: self.$el.find('.color-type'), $typeSelect: self.$el.find('.type-select'), $status: self.$el.find('.color-status'), $activateBtn: self.$el.find('.buttons .activate'), $deactivateBtn: self.$el.find('.buttons .deactivate'), $removeBtn: self.$el.find('.buttons .remove'), $nameInput: self.$el.find('.name-input'), $variableInput: self.$el.find('.variable-input'), $autonameBtn: self.$el.find('button.autoname'), keyboard: function(e) { switch (e.which) { case kt.key.ENTER: self.el.$colorBtn.trigger('focus'); return false; case kt.key.ESC: self.$el.trigger('blur'); break; } }, view: function() { self.el.$colorInput.val(self.color.toString()); self.el.$alphaInput.val(self.color.getAlpha()); self.el.$rgbSample.css('backgroundColor', self.color.getHEX()); self.el.$rgbaSample.css('backgroundColor', self.color.getRGBA(true)); self.el.$nameInput.val(self.color.getName()).toggleClass('autoname', self.color.autonameEnabled()); self.el.$type.val(self.color._type); self.el.$hex.val(self.color.getHEX()); if (autoVariable) { var varName = sanitizeVariableName(self.color.getName()); self.el.$variableInput.val(varName); } } }; this.picker = { $wheel: self.$picker.children('.wheel'), marker: { $hue: self.$picker.children('.h-marker'), $sl: self.$picker.children('.sl-marker'), $alpha: self.$picker.children('.a-marker') }, $alpha: self.$picker.children('.alpha'), $color: self.$picker.children('.color'), keyboard: function(e) { var f = kt.key.ctrl(e) ? 5 : 2.5, more = '+' + f, less = '-' + f; switch (e.which) { case kt.key.MINUS: case kt.key.MINUS_NUM: self.color.setHue(less); return false; case kt.key.PLUS: case kt.key.PLUS_NUM: self.color.setHue(more); return false; case kt.key.UP: self.color.setLightness(more); return false; case kt.key.DOWN: self.color.setLightness(less); return false; case kt.key.LEFT: self.color.setSaturation(more); return false; case kt.key.RIGHT: self.color.setSaturation(less); return false; case kt.key.SPACE: self.el.$colorBtn.trigger($.Event('click', { which: kt.mouse.LEFT })); return false; case kt.key.ESC: if (self.picker.isHidden()) { self.$el.trigger('focus'); } else { self.picker.hide(); } return false; } }, view: function() { var angle = self.color.getHue() * 6.28 / 360; self.picker.marker.$hue.css({ left: Math.round(Math.sin(angle) * radius) + shift, top: Math.round(-Math.cos(angle) * radius) + shift }); self.picker.marker.$sl.css({ left: shift - Math.round(square * (self.color.getSaturation() / 100 - .5)), top: shift - Math.round(square * (self.color.getLightness() / 100 - .5)) }); self.picker.marker.$alpha.css('top', off + radius * (100 - self.color.getAlpha()) / 50); background.setHue(self.color.getHue()); self.picker.$color.css('backgroundColor', background.getHEX()); self.picker.$alpha.css('backgroundColor', self.color.getHEX()); }, coords: function(e) { var offset = self.picker.$wheel.offset(); return { x: (e.pageX - offset.left) - shift, y: (e.pageY - offset.top) - shift }; }, mousedown: function(e) { if (e.which != kt.mouse.LEFT) { return false; } if (!dragging) { $document.on(self.picker.mouse); dragging = true; } var pos = self.picker.coords(e); set = 'sl'; if (pos.x > shift + 1) { set = 'alpha'; } else if (Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > square) { set = 'hue'; } self.picker.mousemove(e); return false; }, mousemove: function(e) { var pos = self.picker.coords(e); switch (set) { case 'hue': self.color.setHue(Math.atan2(pos.x, -pos.y) * 360 / 6.28); break; case 'sl': self.color.setHSL([self.color.getHue(), -100 * (pos.x / square) + 50, -100 * (pos.y / square) + 50]); break; case 'alpha': self.color.setAlpha(-50 * (pos.y / radius) + 50); break; } }, mouseup: function() { $document.off(self.picker.mouse); dragging = false; }, isHidden: function() { return self.$picker.hasClass('hidden'); }, hide: function() { self.$picker.addClass('hidden'); $document.off('mousedown', self.picker.autohide); }, autohide: function(e) { if (!$(e.target).closest(self.el.$colorBtn).length) { self.picker.hide(); } }, toggle: function(e) { if (kt.mouse.LEFT == e.which) { if (self.picker.isHidden()) { $document.on('mousedown', self.picker.autohide); self.$picker.removeClass('hidden').position({ of: this, at: 'right top', my: 'left top' }); } else { self.picker.hide(); } } } }; this.picker.mouse = { mousemove: self.picker.mousemove, mouseup: self.picker.mouseup }; this.type = { isHidden: function() { return self.$type.hasClass('hidden'); }, hide: function() { self.$type.addClass('hidden'); self.el.$typeSelect.removeClass('active'); $document.off('mousedown', self.type.autohide); }, autohide: function(e) { if (!$(e.target).closest([self.$type[0], self.el.$typeSelect[0]]).length) { self.type.hide(); } }, toggle: function(e) { if (kt.mouse.LEFT == e.which) { if (self.type.isHidden()) { $document.on('mousedown', self.type.autohide); self.el.$typeSelect.addClass('active'); self.$type.removeClass('hidden').position({ of: this, at: 'right bottom', my: 'right top-1px' }); } else { self.type.hide(); } } }, select: function(e) { var $this = $(e.target); var type = $this.data('type'); $this.siblings().removeClass('active'); $this.addClass('active'); self.color.setType(type); self.type.hide(); } }; // add or remove keyboard events when an entry gets or loses focus this.$el.on('focus blur', function(e) { if (e.type == 'focus' || e.type == 'focusin') { self.$el.attr('aria-grabbed', 'true').on('keydown', self.el.keyboard); } else { self.$el.attr('aria-grabbed', 'false').off('keydown', self.el.keyboard); } }); // mouse events for the picker this.$picker.on('mousedown', this.picker.mousedown); // when the color changes update the UI this.color.on('change', this.el.view); this.color.on('change', this.picker.view); // toggle the picker then the color preview button is pressed this.el.$colorBtn.on('mousedown', this.picker.toggle); // add or remove keyboard events when the color preview putton gets or looses focus this.el.$colorBtn.on('focus blur', function(e) { if (e.type == 'focus' || e.type == 'focusin') { self.el.$colorBtn.on('keydown', self.picker.keyboard); } else { self.picker.hide(); self.el.$colorBtn.off('keydown', self.picker.keyboard); } }); // when the color input changes parse its value this.el.$colorInput.on('change', function() { self.color.parse(this.value); this.value = self.color.toString(); }); // when the alpha input changes update the color object this.el.$alphaInput.on('change', function() { self.color.setAlpha(this.value); this.value = self.color.getAlpha(); }); // when the name input changes toggle autonaming and update the color name this.el.$nameInput.on('change', function() { var name = $.trim(this.value); self.color.enableAutoname(name == ''); self.color.setName(name); }); // when the variable name input changes toggle variable autonaming this.el.$variableInput.on('change', function() { autoVariable = this.value == ''; }); // toggle the type select then the type button is pressed this.el.$typeSelect.on('mousedown', this.type.toggle); this.$type.on('mousedown', this.type.select); // when the autoname button is pressed autoname the color this.el.$autonameBtn.on('click', function() { self.color.autoname(true); }); this.el.$activateBtn.on('click', function() { self.activate(); }); this.el.$deactivateBtn.on('click', function() { self.deactivate(); }); this.el.$removeBtn.on('click', function() { self.remove(); }); // initial UI update this.picker.view(); this.el.view(); }; Entry.ACTIVE = 1; Entry.INACTIVE = 2; $.extend(Entry.prototype, { activate: function() { this.$el.removeClass('picker-inactive').addClass('picker-active'); this.el.$status.val(Entry.ACTIVE); this.trigger('change:status'); this.trigger('change'); return this; }, deactivate: function() { this.$el.removeClass('picker-active').addClass('picker-inactive'); this.el.$status.val(Entry.INACTIVE); this.trigger('change:status'); this.trigger('change'); return this; }, remove: function() { this.$el.remove(); this.trigger('remove'); return this; } }); kt.implement(Entry, 'Event'); window.kt_Color_Entry = Entry; })(jQuery);