(function($, undefined) { // Removing the G flag will cause infinite loop. var gradientRegExp = /(?:-\w+?-)?(?:linear|webkit)-gradient\s*?\((?:linear\s*,\s*)?[\s,]*?(.+?,)([^#t\(]+?,)?\s*((?:(?:(?:rgba?|color-stop|from|to)\(.+?\)|#[\d\w]+|transparent)[\s\d\w%]*?[,\s\)]*)+)\)/ig, detailRegExp = /(rgba?\([^\)]+?\)|#[\d\w]+|transparent)\s*([\d\.\w%]*)|color-stop\(([\d.]*)[\s,]*(rgba?\([^\)]+?\)|#[\d\w]+)\s*\)/ig, stripRegExp = /^\s*|\s*$|,/g, splitRegExp = /\s*,\s*/, numberRegExp = /\d/, zeroTrimRegExp = /^0+|\.?0+$/g, directions = { top: { value: "0", limit: "100%" }, bottom: { value: "100%", limit: "0" }, left: { value: "0", limit: "100%" }, right: { value: "100%", limit: "0" }, center: { value: "50%", limit: "50%" } }, angles = { // hopefully temporary percent: { "0 50%": 0, "50% 100%": 90, "100% 50%": 180, "50% 0": 270, "0 100%": 45, "100% 100%": 135, "100% 0": 225, "0 0": 315 }, directions: { "0": "left", "90": "bottom", "180": "right", "270": "top", "45": "bottom left", "135": "bottom right", "225": "top right", "315": "top left" }, reverted: { "left": "0", "bottom": "90", "right": "180", "top": "270", "bottom left": "45", "bottom right": "135", "top right": "225", "top left": "315" } }; function trimZeroes(value) { return value.toPrecision(2).replace(zeroTrimRegExp, ""); } function normalizePosition(value, inverted) { var output = value.split(" "); if (output.length == 1) { if (/left|right/.test(output[0])) { output = output.concat("center"); } else { output = [ "center" ].concat(output); } } for (var i = 0, len = output.length; i < len; i++) { if (!numberRegExp.test(output[i])) { if (inverted) { output[i] = directions[output[i]].limit; } else { output[i] = directions[output[i]].value; } } else { if (inverted) { output[i] = 100 - parseFloat(output[i]) + "%"; } output[i] = output[i].replace(/^0%/, "0"); } } return output.join(" "); } window.Gradient = kendo.Observable.extend({ init: function(cssValue) { this.set(cssValue); return this; }, set: function (cssValue) { cssValue = cssValue && cssValue.indexOf("gradient") != -1 ? cssValue : "linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,0))"; this.value = this.parseGradient(cssValue); return this; }, get: function ( prefixes, index, direction ) { var output = "", that = this, gradients = [], target = !isNaN(index) ? [ that.value[index]] : that.value; if (prefixes == "svg") { return that._getSVGGradient(target[0], direction); } if (typeof prefixes == "undefined") { prefixes = [ kendo.support.transforms.css ]; } else if (typeof prefixes == "string") { prefixes = prefixes.split(splitRegExp); } $.each (prefixes, function (idx, value) { output = ""; target.forEach(function(gradient) { if (gradient.stops.length == 2 && gradient.stops[0].color.get() == "rgba(0,0,0,0)" && gradient.stops[1].color.get() == "rgba(0,0,0,0)") { output += "none,"; } else if (value == "-webkit-") { output += that._getWebKitGradient(gradient, direction); } else { output += that._getStandardGradient(gradient, value, direction); } }); gradients.push(output.substring(0, output.length-1)); }); return gradients[1] ? gradients : gradients[0]; }, parseGradient: function (cssValue) { var output = [], counter = -1, matches, details, i, lastPosition, color, position, isStandard, buf; while((matches = gradientRegExp.exec(cssValue)) !== null) { output[++counter] = {}; buf = matches[1].replace(stripRegExp, ""); output[counter].start = { original: buf, normalized: normalizePosition(buf) }; output[counter].angle = angles.percent[output[counter].start.normalized]; output[counter].stops = []; if (matches[2]) { buf = matches[2].replace(stripRegExp, ""); output[counter].end = { original: buf, normalized: normalizePosition(buf) }; } else { output[counter].end = { original: false, normalized: normalizePosition(buf, true) }; } i = 0; while((details = detailRegExp.exec(matches[3])) !== null) { color = details[1] || details[4]; isStandard = typeof details[2] != "undefined"; position = isStandard ? details[2] || 0 : details[3] * 100 || 0; lastPosition = isStandard ? details[2] : details[3] * 100; output[counter].stops[i++] = { color: new Color(color), position: parseFloat(position) }; } if (output[counter].stops[i-1].position === 0 && lastPosition == "") { output[counter].stops[i-1].position = 100; } } return output; }, getAngle: function (index) { return this.value[index].angle; }, getDirection: function (index) { return angles.directions[this.getAngle(index)]; }, setAngle: function (index, angle) { if (typeof angle == "string") { angle = angles.reverted[angle]; } angle = angle % 360; var that = this, direction = angles.directions[angle]; if (that.value[index]) { that.value[index].angle = angle; that.value[index].start.original = direction; that.value[index].start.normalized = normalizePosition(direction); that.value[index].end.original = false; that.value[index].end.normalized = normalizePosition(direction, true); } return that; }, closestStop: function (position, index) { var lastValue = { position: 10000 }; this.value[index].stops.forEach(function(value) { if (Math.abs(value.position - position) < Math.abs(lastValue.position - position)) { lastValue = value; } }); return lastValue; }, _getStandardGradient: function (gradient, prefix, direction) { var output = "", parsed, clone = $.extend([], gradient.stops); output += prefix + "linear-gradient(" + (direction ? direction : gradient.start.original) + "," + (gradient.end.original ? gradient.end.original + "," : "" ); clone.sort(function(a,b) { return a.position - b.position; // Always return sorted stops or W3C gradients get confused. }).forEach(function(stop) { if (stop.position >= 0) { parsed = parseInt(stop.position, 10); output += stop.color.get() + (parsed != 0 && stop.position != "100" ? " " + stop.position + "%" : "") + ","; } }); return output.substring(0, output.length - 1) + "),"; }, _getWebKitGradient: function (gradient, direction) { var output = "", normalizedStart = direction ? normalizePosition(direction) : null, normalizedEnd = direction ? normalizePosition(direction, true) : null; output += "-webkit-gradient(linear," + (direction ? normalizedStart : gradient.start.normalized) + "," + (direction ? normalizedEnd : gradient.end.normalized) + ","; gradient.stops.forEach(function(stop) { if (stop.position >= 0) { output += "color-stop(" + (trimZeroes(stop.position / 100) || "0") + ", " + stop.color.get() + "),"; } }); return output.substring(0, output.length - 1) + "),"; }, _getSVGGradient: function (gradient, id, units) { var output = "", color, alpha, clone = $.extend([], gradient.stops), startDirection = gradient.start.normalized.split(" "), endDirection = gradient.end.normalized.split(" "); output += ''; clone.sort(function(a,b) { return a.position - b.position; // Always return sorted stops or W3C gradients get confused. }).forEach(function(stop) { if (stop.position >= 0) { color = $.extend(stop.color.value); alpha = color.alpha; color.alpha = 1; output += ''; } }); return output.replace(/#/g, "%23") + "<%2FlinearGradient>"; } }); })(jQuery);