LinkStack/studio/button-editor/js/jquery.gradientPicker.js
Julian Prieber 62c9baba23 Added custom button editor
Added the long planned button editor. This solution does not look optimal, but works... mostly.

This solution is implemented with JavaScript and the current versions code is very unorganized mostly uncommented and the HTML is still mostly done with inline code. I hope I will fix this in future revisions.

To learn more about the new button editor, read:
https://littlelink-custom.com/blog/upcoming-features/
https://littlelink-custom.com/blog/progress-of-the-new-button-editor/
2022-04-27 20:55:19 +02:00

330 lines
8.4 KiB
JavaScript
Vendored

/**
@author Matt Crinklaw-Vogt (tantaman)
*/
(function( $ ) {
if (!$.event.special.destroyed) {
$.event.special.destroyed = {
remove: function(o) {
if (o.handler) {
o.handler();
}
}
}
}
function ctrlPtComparator(l,r) {
return l.position - r.position;
}
function bind(fn, ctx) {
if (typeof fn.bind === "function") {
return fn.bind(ctx);
} else {
return function() {
fn.apply(ctx, arguments);
}
}
}
var browserPrefix = "";
if ($.browser.mozilla) {
browserPrefix = "-moz-";
} else if ($.browser.webkit) {
browserPrefix = "-webkit-";
} else if ($.browser.opera) {
browserPrefix = "-o-";
} else if ($.browser.msie) {
browserPrefix = "-ms-";
}
function GradientSelection($el, opts) {
this.$el = $el;
this.$el.css("position", "relative");
this.opts = opts;
var $preview = $("<canvas class='gradientPicker-preview'></canvas>");
this.$el.append($preview);
var canvas = $preview[0];
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
this.g2d = canvas.getContext("2d");
var $ctrlPtContainer = $("<div class='gradientPicker-ctrlPts'></div>");
this.$el.append($ctrlPtContainer)
this.$ctrlPtContainer = $ctrlPtContainer;
this.updatePreview = bind(this.updatePreview, this);
this.controlPoints = [];
this.ctrlPtConfig = new ControlPtConfig(this.$el, opts);
for (var i = 0; i < opts.controlPoints.length; ++i) {
var ctrlPt = this.createCtrlPt(opts.controlPoints[i]);
this.controlPoints.push(ctrlPt);
}
this.docClicked = bind(this.docClicked, this);
this.destroyed = bind(this.destroyed, this);
$(document).bind("click", this.docClicked);
this.$el.bind("destroyed", this.destroyed);
this.previewClicked = bind(this.previewClicked, this);
$preview.click(this.previewClicked);
this.updatePreview();
}
GradientSelection.prototype = {
docClicked: function() {
this.ctrlPtConfig.hide();
},
createCtrlPt: function(ctrlPtSetup) {
return new ControlPoint(this.$ctrlPtContainer, ctrlPtSetup, this.opts.orientation, this, this.ctrlPtConfig)
},
destroyed: function() {
$(document).unbind("click", this.docClicked);
},
updateOptions: function(opts) {
$.extend(this.opts, opts);
this.updatePreview();
},
updatePreview: function() {
var result = [];
this.controlPoints.sort(ctrlPtComparator);
if (this.opts.orientation == "horizontal") {
var grad = this.g2d.createLinearGradient(0, 0, this.g2d.canvas.width, 0);
for (var i = 0; i < this.controlPoints.length; ++i) {
var pt = this.controlPoints[i];
grad.addColorStop(pt.position, pt.color);
result.push({
position: pt.position,
color: pt.color
});
}
} else {
}
this.g2d.fillStyle = grad;
this.g2d.fillRect(0, 0, this.g2d.canvas.width, this.g2d.canvas.height);
if (this.opts.generateStyles)
var styles = this._generatePreviewStyles();
this.opts.change(result, styles);
},
removeControlPoint: function(ctrlPt) {
var cpidx = this.controlPoints.indexOf(ctrlPt);
if (cpidx != -1) {
this.controlPoints.splice(cpidx, 1);
ctrlPt.$el.remove();
}
},
previewClicked: function(e) {
var offset = $(e.target).offset();
var x = e.pageX - offset.left;
var y = e.pageY - offset.top;
var imgData = this.g2d.getImageData(x,y,1,1);
var colorStr = "rgb(" + imgData.data[0] + "," + imgData.data[1] + "," + imgData.data[2] + ")";
var cp = this.createCtrlPt({
position: x / this.g2d.canvas.width,
color: colorStr
});
this.controlPoints.push(cp);
this.controlPoints.sort(ctrlPtComparator);
},
_generatePreviewStyles: function() {
//linear-gradient(top, rgb(217,230,163) 86%, rgb(227,249,159) 9%)
var str = this.opts.type + "-gradient(" + ((this.opts.type == "linear") ? (this.opts.fillDirection + ", ") : "");
var first = true;
for (var i = 0; i < this.controlPoints.length; ++i) {
var pt = this.controlPoints[i];
if (!first) {
str += ", ";
} else {
first = false;
}
str += pt.color + " " + ((pt.position*100)|0) + "%";
}
str = str + ")"
var styles = [str, browserPrefix + str];
return styles;
}
};
function ControlPoint($parentEl, initialState, orientation, listener, ctrlPtConfig) {
this.$el = $("<div class='gradientPicker-ctrlPt'></div>");
$parentEl.append(this.$el);
this.$parentEl = $parentEl;
this.configView = ctrlPtConfig;
if (typeof initialState === "string") {
initialState = initialState.split(" ");
this.position = parseFloat(initialState[1])/100;
this.color = initialState[0];
} else {
this.position = initialState.position;
this.color = initialState.color;
}
this.listener = listener;
this.outerWidth = this.$el.outerWidth();
this.$el.css("background-color", this.color);
if (orientation == "horizontal") {
var pxLeft = ($parentEl.width() - this.$el.outerWidth()) * (this.position);
this.$el.css("left", pxLeft);
} else {
var pxTop = ($parentEl.height() - this.$el.outerHeight()) * (this.position);
this.$el.css("top", pxTop);
}
this.drag = bind(this.drag, this);
this.stop = bind(this.stop, this);
this.clicked = bind(this.clicked, this);
this.colorChanged = bind(this.colorChanged, this);
this.$el.draggable({
axis: (orientation == "horizontal") ? "x" : "y",
drag: this.drag,
stop: this.stop,
containment: $parentEl
});
this.$el.click(this.clicked);
}
ControlPoint.prototype = {
drag: function(e, ui) {
// convert position to a %
var left = ui.position.left;
this.position = (left / (this.$parentEl.width() - this.outerWidth));
this.listener.updatePreview();
},
stop: function(e, ui) {
this.listener.updatePreview();
this.configView.show(this.$el.position(), this.color, this);
},
clicked: function(e) {
this.configView.show(this.$el.position(), this.color, this);
e.stopPropagation();
return false;
},
colorChanged: function(c) {
this.color = c;
this.$el.css("background-color", this.color);
this.listener.updatePreview();
},
removeClicked: function() {
this.listener.removeControlPoint(this);
this.listener.updatePreview();
}
};
function ControlPtConfig($parent, opts) {
//color-chooser
this.$el = $('<div class="gradientPicker-ptConfig" style="visibility: hidden"></div>');
$parent.append(this.$el);
var $cpicker = $('<div class="color-chooser"></div>');
this.$el.append($cpicker);
var $rmEl = $("<div class='gradientPicker-close'></div>");
this.$el.append($rmEl);
this.colorChanged = bind(this.colorChanged, this);
this.removeClicked = bind(this.removeClicked, this);
$cpicker.ColorPicker({
onChange: this.colorChanged
});
this.$cpicker = $cpicker;
this.opts = opts;
this.visible = false;
$rmEl.click(this.removeClicked);
}
ControlPtConfig.prototype = {
show: function(position, color, listener) {
this.visible = true;
this.listener = listener;
this.$el.css("visibility", "visible");
this.$cpicker.ColorPickerSetColor(color);
this.$cpicker.css("background-color", color);
if (this.opts.orientation === "horizontal") {
this.$el.css("left", position.left);
} else {
this.$el.css("top", position.top);
}
//else {
// this.visible = false;
//this.$el.css("visibility", "hidden");
//}
},
hide: function() {
if (this.visible) {
this.$el.css("visibility", "hidden");
this.visible = false;
}
},
colorChanged: function(hsb, hex, rgb) {
hex = "#" + hex;
this.listener.colorChanged(hex);
this.$cpicker.css("background-color", hex)
},
removeClicked: function() {
this.listener.removeClicked();
this.hide();
}
};
var methods = {
init: function(opts) {
opts = $.extend({
controlPoints: ["#FFF 0%", "#000 100%"],
orientation: "horizontal",
type: "linear",
fillDirection: "left",
generateStyles: true,
change: function() {}
}, opts);
this.each(function() {
var $this = $(this);
var gradSel = new GradientSelection($this, opts);
$this.data("gradientPicker-sel", gradSel);
});
},
update: function(opts) {
this.each(function() {
var $this = $(this);
var gradSel = $this.data("gradientPicker-sel");
if (gradSel != null) {
gradSel.updateOptions(opts);
}
});
}
};
$.fn.gradientPicker = function(method, opts) {
if (typeof method === "string" && method !== "init") {
methods[method].call(this, opts);
} else {
opts = method;
methods.init.call(this, opts);
}
};
})( jQuery );