From b1dab897f27d04e62f4f95c92e1f2dcfe828b534 Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Wed, 5 Aug 2015 20:44:54 +0000 Subject: [PATCH] (legacy) zap protochart --- src/www/protochart/ProtoChart.js | 2653 ------------- src/www/protochart/excanvas-compressed.js | 19 - src/www/protochart/excanvas.js | 785 ---- src/www/protochart/prototype.js | 4221 --------------------- 4 files changed, 7678 deletions(-) delete mode 100644 src/www/protochart/ProtoChart.js delete mode 100644 src/www/protochart/excanvas-compressed.js delete mode 100644 src/www/protochart/excanvas.js delete mode 100644 src/www/protochart/prototype.js diff --git a/src/www/protochart/ProtoChart.js b/src/www/protochart/ProtoChart.js deleted file mode 100644 index 8e006d941..000000000 --- a/src/www/protochart/ProtoChart.js +++ /dev/null @@ -1,2653 +0,0 @@ -/** - * Class: ProtoChart - * Version: v0.5 beta - * - * ProtoChart is a charting lib on top of Prototype. - * This library is heavily motivated by excellent work done by: - * * Flot - * * Flotr - * - * Complete examples can be found at: - */ - -/** - * Events: - * ProtoChart:mousemove - Fired when mouse is moved over the chart - * ProtoChart:plotclick - Fired when graph is clicked - * ProtoChart:dataclick - Fired when graph is clicked AND the click is on a data point - * ProtoChart:selected - Fired when certain region on the graph is selected - * ProtoChart:hit - Fired when mouse is moved near or over certain data point on the graph - */ - - -if(!Proto) var Proto = {}; - -Proto.Chart = Class.create({ - /** - * Function: - * {Object} elem - * {Object} data - * {Object} options - */ - initialize: function(elem, data, options) - { - options = options || {}; - this.graphData = []; - /** - * Property: options - * - * Description: Various options can be set. More details in description. - * - * colors: - * {Array} - pass in a array which contains strings of colors you want to use. Default has 6 color set. - * - * legend: - * {BOOL} - show - if you want to show the legend. Default is false - * {integer} - noColumns - Number of columns for the legend. Default is 1 - * {function} - labelFormatter - A function that returns a string. The function is called with a string and is expected to return a string. Default = null - * {string} - labelBoxBorderColor - border color for the little label boxes. Default #CCC - * {HTMLElem} - container - an HTML id or HTML element where the legend should be rendered. If left null means to put the legend on top of the Chart - * {string} - position - position for the legend on the Chart. Default value 'ne' - * {integer} - margin - default valud of 5 - * {string} - backgroundColor - default to null (which means auto-detect) - * {float} - backgroundOpacity - leave it 0 to avoid background - * - * xaxis (yaxis) options: - * {string} - mode - default is null but you can pass a string "time" to indicate time series - * {integer} - min - * {integer} - max - * {float} - autoscaleMargin - in % to add if auto-setting min/max - * {mixed} - ticks - either [1, 3] or [[1, "a"], 3] or a function which gets axis info and returns ticks - * {function} - tickFormatter - A function that returns a string as a tick label. Default is null - * {float} - tickDecimals - * {integer} - tickSize - * {integer} - minTickSize - * {array} - monthNames - * {string} - timeformat - * - * Points / Lines / Bars options: - * {bool} - show, default is false - * {integer} - radius: default is 3 - * {integer} - lineWidth : default is 2 - * {bool} - fill : default is true - * {string} - fillColor: default is #ffffff - * - * Grid options: - * {string} - color - * {string} - backgroundColor - defualt is *null* - * {string} - tickColor - default is *#dddddd* - * {integer} - labelMargin - should be in pixels default is 3 - * {integer} - borderWidth - default *1* - * {bool} - clickable - default *null* - pass in TRUE if you wish to monitor click events - * {mixed} - coloredAreas - default *null* - pass in mixed object eg. {x1, x2} - * {string} - coloredAreasColor - default *#f4f4f4* - * {bool} - drawXAxis - default *true* - * {bool} - drawYAxis - default *true* - * - * selection options: - * {string} - mode : either "x", "y" or "xy" - * {string} - color : string - */ - this.options = this.merge(options,{ - colors: ["#edc240", "#00A8F0", "#C0D800", "#cb4b4b", "#4da74d", "#9440ed"], - legend: { - show: false, - noColumns: 1, - labelFormatter: null, - labelBoxBorderColor: "#ccc", - container: null, - position: "ne", - margin: 5, - backgroundColor: null, - backgroundOpacity: 0.85 - }, - xaxis: { - mode: null, - min: null, - max: null, - autoscaleMargin: null, - ticks: null, - tickFormatter: null, - tickDecimals: null, - tickSize: null, - minTickSize: null, - monthNames: null, - timeformat: null - }, - yaxis: { - mode: null, - min: null, - max: null, - ticks: null, - tickFormatter: null, - tickDecimals: null, - tickSize: null, - minTickSize: null, - monthNames: null, - timeformat: null, - autoscaleMargin: 0.02 - }, - - points: { - show: false, - radius: 3, - lineWidth: 2, - fill: true, - fillColor: "#ffffff" - }, - lines: { - show: false, - lineWidth: 2, - fill: false, - fillColor: null - }, - bars: { - show: false, - lineWidth: 2, - barWidth: 1, - fill: true, - fillColor: null, - showShadow: false, - fillOpacity: 0.4, - autoScale: true - }, - pies: { - show: false, - radius: 50, - borderWidth: 1, - fill: true, - fillColor: null, - fillOpacity: 0.90, - labelWidth: 30, - fontSize: 11, - autoScale: true - }, - grid: { - color: "#545454", - backgroundColor: null, - tickColor: "#dddddd", - labelMargin: 3, - borderWidth: 1, - clickable: null, - coloredAreas: null, - coloredAreasColor: "#f4f4f4", - drawXAxis: true, - drawYAxis: true - }, - mouse: { - track: false, - position: 'se', - fixedPosition: true, - clsName: 'mouseValHolder', - trackFormatter: this.defaultTrackFormatter, - margin: 3, - color: '#ff3f19', - trackDecimals: 1, - sensibility: 2, - radius: 5, - lineColor: '#cb4b4b' - }, - selection: { - mode: null, - color: "#97CBFF" - }, - allowDataClick: true, - makeRandomColor: false, - shadowSize: 4 - }); - - /* - * Local variables. - */ - this.canvas = null; - this.overlay = null; - this.eventHolder = null; - this.context = null; - this.overlayContext = null; - - this.domObj = $(elem); - - this.xaxis = {}; - this.yaxis = {}; - this.chartOffset = {left: 0, right: 0, top: 0, bottom: 0}; - this.yLabelMaxWidth = 0; - this.yLabelMaxHeight = 0; - this.xLabelBoxWidth = 0; - this.canvasWidth = 0; - this.canvasHeight = 0; - this.chartWidth = 0; - this.chartHeight = 0; - this.hozScale = 0; - this.vertScale = 0; - this.workarounds = {}; - - this.domObj = $(elem); - - this.barDataRange = []; - - this.lastMousePos = { pageX: null, pageY: null }; - this.selection = { first: { x: -1, y: -1}, second: { x: -1, y: -1} }; - this.prevSelection = null; - this.selectionInterval = null; - this.ignoreClick = false; - this.prevHit = null; - - if(this.options.makeRandomColor) - this.options.color = this.makeRandomColor(this.options.colors); - - this.setData(data); - this.constructCanvas(); - this.setupGrid(); - this.draw(); - }, - /** - * Private function internally used. - */ - merge: function(src, dest) - { - var result = dest || {}; - for(var i in src){ - result[i] = (typeof(src[i]) == 'object' && !(src[i].constructor == Array || src[i].constructor == RegExp)) ? this.merge(src[i], dest[i]) : result[i] = src[i]; - } - return result; - }, - /** - * Function: setData - * {Object} data - * - * Description: - * Sets datasoruces properly then sets the Bar Width accordingly, then copies the default data options and then processes the graph data - * - * Returns: none - * - */ - setData: function(data) - { - this.graphData = this.parseData(data); - this.setBarWidth(); - this.copyGraphDataOptions(); - this.processGraphData(); - }, - /** - * Function: parseData - * {Object} data - * - * Return: - * {Object} result - * - * Description: - * Takes the provided data object and converts it into generic data that we can understand. User can pass in data in 3 different ways: - * - [d1, d2] - * - [{data: d1, label: "data1"}, {data: d2, label: "data2"}] - * - [d1, {data: d1, label: "data1"}] - * - * This function parses these senarios and makes it readable - */ - parseData: function(data) - { - var res = []; - data.each(function(d){ - var s; - if(d.data) { - s = {}; - for(var v in d) { - s[v] = d[v]; - } - } - else { - s = {data: d}; - } - res.push(s); - }.bind(this)); - return res; - }, - /** - * function: makeRandomColor - * {Object} colorSet - * - * Return: - * {Array} result - array containing random colors - */ - makeRandomColor: function(colorSet) - { - var randNum = Math.floor(Math.random() * colorSet.length); - var randArr = []; - var newArr = []; - randArr.push(randNum); - - while(randArr.length < colorSet.length) - { - var tempNum = Math.floor(Math.random() * colorSet.length); - - while(checkExisted(tempNum, randArr)) - tempNum = Math.floor(Math.random() * colorSet.length); - - randArr.push(tempNum); - } - - randArr.each(function(ra){ - newArr.push(colorSet[ra]); - - }.bind(this)); - return newArr; - }, - /** - * function: checkExisted - * {Object} needle - * {Object} haystack - * - * return: - * {bool} existed - true if it finds needle in the haystack - */ - checkExisted: function(needle, haystack) - { - var existed = false; - haystack.each(function(aNeedle){ - if(aNeedle == needle) { - existed = true; - throw $break; - } - }.bind(this)); - return existed; - }, - /** - * function: setBarWidth - * - * Description: sets the bar width for Bar Graph, you should enable *autoScale* property for bar graph - */ - setBarWidth: function() - { - if(this.options.bars.show && this.options.bars.autoScale) - { - this.options.bars.barWidth = 1 / this.graphData.length / 1.2; - } - }, - /** - * Function: copyGraphDataOptions - * - * Description: Private function that goes through each graph data (series) and assigned the graph - * properties to it. - */ - copyGraphDataOptions: function() - { - var i, neededColors = this.graphData.length, usedColors = [], assignedColors = []; - - this.graphData.each(function(gd){ - var sc = gd.color; - if(sc) { - --neededColors; - if(Object.isNumber(sc)) { - assignedColors.push(sc); - } - else { - usedColors.push(this.parseColor(sc)); - } - } - }.bind(this)); - - - assignedColors.each(function(ac){ - neededColors = Math.max(neededColors, ac + 1); - }); - - var colors = []; - var variation = 0; - i = 0; - while (colors.length < neededColors) { - var c; - if (this.options.colors.length == i) { - c = new Proto.Color(100, 100, 100); - } - else { - c = this.parseColor(this.options.colors[i]); - } - - var sign = variation % 2 == 1 ? -1 : 1; - var factor = 1 + sign * Math.ceil(variation / 2) * 0.2; - c.scale(factor, factor, factor); - - colors.push(c); - - ++i; - if (i >= this.options.colors.length) { - i = 0; - ++variation; - } - } - - var colorIndex = 0, s; - - this.graphData.each(function(gd){ - if(gd.color == null) - { - gd.color = colors[colorIndex].toString(); - ++colorIndex; - } - else if(Object.isNumber(gd.color)) { - gd.color = colors[gd.color].toString(); - } - - gd.lines = Object.extend(Object.clone(this.options.lines), gd.lines); - gd.points = Object.extend(Object.clone(this.options.points), gd.points); - gd.bars = Object.extend(Object.clone(this.options.bars), gd.bars); - gd.mouse = Object.extend(Object.clone(this.options.mouse), gd.mouse); - if (gd.shadowSize == null) { - gd.shadowSize = this.options.shadowSize; - } - }.bind(this)); - - }, - /** - * Function: processGraphData - * - * Description: processes graph data, setup xaxis and yaxis min and max points. - */ - processGraphData: function() { - - this.xaxis.datamin = this.yaxis.datamin = Number.MAX_VALUE; - this.xaxis.datamax = this.yaxis.datamax = Number.MIN_VALUE; - - this.graphData.each(function(gd) { - var data = gd.data; - data.each(function(d){ - if(d == null) { - return; - } - - var x = d[0], y = d[1]; - if(!x || !y || isNaN(x = +x) || isNaN(y = +y)) { - d = null; - return; - } - - if (x < this.xaxis.datamin) - this.xaxis.datamin = x; - if (x > this.xaxis.datamax) - this.xaxis.datamax = x; - if (y < this.yaxis.datamin) - this.yaxis.datamin = y; - if (y > this.yaxis.datamax) - this.yaxis.datamax = y; - }.bind(this)); - }.bind(this)); - - - if (this.xaxis.datamin == Number.MAX_VALUE) - this.xaxis.datamin = 0; - if (this.yaxis.datamin == Number.MAX_VALUE) - this.yaxis.datamin = 0; - if (this.xaxis.datamax == Number.MIN_VALUE) - this.xaxis.datamax = 1; - if (this.yaxis.datamax == Number.MIN_VALUE) - this.yaxis.datamax = 1; - }, - /** - * Function: constructCanvas - * - * Description: constructs the main canvas for drawing. It replicates the HTML elem (usually DIV) passed - * in via constructor. If there is no height/width assigned to the HTML elem then we take a default size - * of 400px (width) and 300px (height) - */ - constructCanvas: function() { - - this.canvasWidth = this.domObj.getWidth(); - this.canvasHeight = this.domObj.getHeight(); - this.domObj.update(""); // clear target - this.domObj.setStyle({ - "position": "relative" - }); - - if (this.canvasWidth <= 0) { - this.canvasWdith = 400; - } - if(this.canvasHeight <= 0) { - this.canvasHeight = 300; - } - - this.canvas = (Prototype.Browser.IE) ? document.createElement("canvas") : new Element("CANVAS", {'width': this.canvasWidth, 'height': this.canvasHeight}); - Element.extend(this.canvas); - this.canvas.style.width = this.canvasWidth + "px"; - this.canvas.style.height = this.canvasHeight + "px"; - - this.domObj.appendChild(this.canvas); - - if (Prototype.Browser.IE) // excanvas hack - { - this.canvas = $(window.G_vmlCanvasManager.initElement(this.canvas)); - } - this.canvas = $(this.canvas); - - this.context = this.canvas.getContext("2d"); - - this.overlay = (Prototype.Browser.IE) ? document.createElement("canvas") : new Element("CANVAS", {'width': this.canvasWidth, 'height': this.canvasHeight}); - Element.extend(this.overlay); - this.overlay.style.width = this.canvasWidth + "px"; - this.overlay.style.height = this.canvasHeight + "px"; - this.overlay.style.position = "absolute"; - this.overlay.style.left = "0px"; - this.overlay.style.right = "0px"; - - this.overlay.setStyle({ - 'position': 'absolute', - 'left': '0px', - 'right': '0px' - }); - this.domObj.appendChild(this.overlay); - - if (Prototype.Browser.IE) { - this.overlay = $(window.G_vmlCanvasManager.initElement(this.overlay)); - } - - this.overlay = $(this.overlay); - this.overlayContext = this.overlay.getContext("2d"); - - if(this.options.selection.mode) - { - this.overlay.observe('mousedown', this.onMouseDown.bind(this)); - this.overlay.observe('mousemove', this.onMouseMove.bind(this)); - } - if(this.options.grid.clickable) { - this.overlay.observe('click', this.onClick.bind(this)); - } - if(this.options.mouse.track) - { - this.overlay.observe('mousemove', this.onMouseMove.bind(this)); - } - }, - /** - * function: setupGrid - * - * Description: a container function that does a few interesting things. - * - * 1. calls function which makes sure that our axis are expanded if needed - * - * 2. calls function providing xaxis options which fixes the ranges according to data points - * - * 3. calls function for xaxis which generates ticks according to options provided by user - * - * 4. calls function for xaxis that sets the ticks - * - * similar sequence is called for y-axis. - * - * At the end if this is a pie chart than we insert Labels (around the pie chart) via and we also call - */ - setupGrid: function() - { - if(this.options.bars.show) - { - this.xaxis.max += 0.5; - this.xaxis.min -= 0.5; - } - //x-axis - this.extendXRangeIfNeededByBar(); - this.setRange(this.xaxis, this.options.xaxis); - this.prepareTickGeneration(this.xaxis, this.options.xaxis); - this.setTicks(this.xaxis, this.options.xaxis); - - - //y-axis - this.setRange(this.yaxis, this.options.yaxis); - this.prepareTickGeneration(this.yaxis, this.options.yaxis); - this.setTicks(this.yaxis, this.options.yaxis); - this.setSpacing(); - - if(!this.options.pies.show) - { - this.insertLabels(); - } - this.insertLegend(); - }, - /** - * function: setRange - * - * parameters: - * {Object} axis - * {Object} axisOptions - */ - setRange: function(axis, axisOptions) { - var min = axisOptions.min != null ? axisOptions.min : axis.datamin; - var max = axisOptions.max != null ? axisOptions.max : axis.datamax; - - if (max - min == 0.0) { - // degenerate case - var widen; - if (max == 0.0) - widen = 1.0; - else - widen = 0.01; - - min -= widen; - max += widen; - } - else { - // consider autoscaling - var margin = axisOptions.autoscaleMargin; - if (margin != null) { - if (axisOptions.min == null) { - min -= (max - min) * margin; - // make sure we don't go below zero if all values - // are positive - if (min < 0 && axis.datamin >= 0) - min = 0; - } - if (axisOptions.max == null) { - max += (max - min) * margin; - if (max > 0 && axis.datamax <= 0) - max = 0; - } - } - } - axis.min = min; - axis.max = max; - }, - /** - * function: prepareTickGeneration - * - * Parameters: - * {Object} axis - * {Object} axisOptions - */ - prepareTickGeneration: function(axis, axisOptions) { - // estimate number of ticks - var noTicks; - if (Object.isNumber(axisOptions.ticks) && axisOptions.ticks > 0) - noTicks = axisOptions.ticks; - else if (axis == this.xaxis) - noTicks = this.canvasWidth / 100; - else - noTicks = this.canvasHeight / 60; - - var delta = (axis.max - axis.min) / noTicks; - var size, generator, unit, formatter, i, magn, norm; - - if (axisOptions.mode == "time") { - function formatDate(d, fmt, monthNames) { - var leftPad = function(n) { - n = "" + n; - return n.length == 1 ? "0" + n : n; - }; - - var r = []; - var escape = false; - if (monthNames == null) - monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; - for (var i = 0; i < fmt.length; ++i) { - var c = fmt.charAt(i); - - if (escape) { - switch (c) { - case 'h': c = "" + d.getHours(); break; - case 'H': c = leftPad(d.getHours()); break; - case 'M': c = leftPad(d.getMinutes()); break; - case 'S': c = leftPad(d.getSeconds()); break; - case 'd': c = "" + d.getDate(); break; - case 'm': c = "" + (d.getMonth() + 1); break; - case 'y': c = "" + d.getFullYear(); break; - case 'b': c = "" + monthNames[d.getMonth()]; break; - } - r.push(c); - escape = false; - } - else { - if (c == "%") - escape = true; - else - r.push(c); - } - } - return r.join(""); - } - - - // map of app. size of time units in milliseconds - var timeUnitSize = { - "second": 1000, - "minute": 60 * 1000, - "hour": 60 * 60 * 1000, - "day": 24 * 60 * 60 * 1000, - "month": 30 * 24 * 60 * 60 * 1000, - "year": 365.2425 * 24 * 60 * 60 * 1000 - }; - - - // the allowed tick sizes, after 1 year we use - // an integer algorithm - var spec = [ - [1, "second"], [2, "second"], [5, "second"], [10, "second"], - [30, "second"], - [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], - [30, "minute"], - [1, "hour"], [2, "hour"], [4, "hour"], - [8, "hour"], [12, "hour"], - [1, "day"], [2, "day"], [3, "day"], - [0.25, "month"], [0.5, "month"], [1, "month"], - [2, "month"], [3, "month"], [6, "month"], - [1, "year"] - ]; - - var minSize = 0; - if (axisOptions.minTickSize != null) { - if (typeof axisOptions.tickSize == "number") - minSize = axisOptions.tickSize; - else - minSize = axisOptions.minTickSize[0] * timeUnitSize[axisOptions.minTickSize[1]]; - } - - for (i = 0; i < spec.length - 1; ++i) { - if (delta < (spec[i][0] * timeUnitSize[spec[i][1]] + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2 && spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) { - break; - } - } - - size = spec[i][0]; - unit = spec[i][1]; - - // special-case the possibility of several years - if (unit == "year") { - magn = Math.pow(10, Math.floor(Math.log(delta / timeUnitSize.year) / Math.LN10)); - norm = (delta / timeUnitSize.year) / magn; - if (norm < 1.5) - size = 1; - else if (norm < 3) - size = 2; - else if (norm < 7.5) - size = 5; - else - size = 10; - - size *= magn; - } - - if (axisOptions.tickSize) { - size = axisOptions.tickSize[0]; - unit = axisOptions.tickSize[1]; - } - - var floorInBase = this.floorInBase; //gives us a reference to a global function.. - - generator = function(axis) { - var ticks = [], - tickSize = axis.tickSize[0], unit = axis.tickSize[1], - d = new Date(axis.min); - - var step = tickSize * timeUnitSize[unit]; - - - - if (unit == "second") - d.setSeconds(floorInBase(d.getSeconds(), tickSize)); - if (unit == "minute") - d.setMinutes(floorInBase(d.getMinutes(), tickSize)); - if (unit == "hour") - d.setHours(floorInBase(d.getHours(), tickSize)); - if (unit == "month") - d.setMonth(floorInBase(d.getMonth(), tickSize)); - if (unit == "year") - d.setFullYear(floorInBase(d.getFullYear(), tickSize)); - - // reset smaller components - d.setMilliseconds(0); - if (step >= timeUnitSize.minute) - d.setSeconds(0); - if (step >= timeUnitSize.hour) - d.setMinutes(0); - if (step >= timeUnitSize.day) - d.setHours(0); - if (step >= timeUnitSize.day * 4) - d.setDate(1); - if (step >= timeUnitSize.year) - d.setMonth(0); - - - var carry = 0, v; - do { - v = d.getTime(); - ticks.push({ v: v, label: axis.tickFormatter(v, axis) }); - if (unit == "month") { - if (tickSize < 1) { - d.setDate(1); - var start = d.getTime(); - d.setMonth(d.getMonth() + 1); - var end = d.getTime(); - d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize); - carry = d.getHours(); - d.setHours(0); - } - else - d.setMonth(d.getMonth() + tickSize); - } - else if (unit == "year") { - d.setFullYear(d.getFullYear() + tickSize); - } - else - d.setTime(v + step); - } while (v < axis.max); - - return ticks; - }; - - formatter = function (v, axis) { - var d = new Date(v); - - // first check global format - if (axisOptions.timeformat != null) - return formatDate(d, axisOptions.timeformat, axisOptions.monthNames); - - var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]]; - var span = axis.max - axis.min; - - if (t < timeUnitSize.minute) - fmt = "%h:%M:%S"; - else if (t < timeUnitSize.day) { - if (span < 2 * timeUnitSize.day) - fmt = "%h:%M"; - else - fmt = "%b %d %h:%M"; - } - else if (t < timeUnitSize.month) - fmt = "%b %d"; - else if (t < timeUnitSize.year) { - if (span < timeUnitSize.year) - fmt = "%b"; - else - fmt = "%b %y"; - } - else - fmt = "%y"; - - return formatDate(d, fmt, axisOptions.monthNames); - }; - } - else { - // pretty rounding of base-10 numbers - var maxDec = axisOptions.tickDecimals; - var dec = -Math.floor(Math.log(delta) / Math.LN10); - if (maxDec != null && dec > maxDec) - dec = maxDec; - - magn = Math.pow(10, -dec); - norm = delta / magn; // norm is between 1.0 and 10.0 - - if (norm < 1.5) - size = 1; - else if (norm < 3) { - size = 2; - // special case for 2.5, requires an extra decimal - if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) { - size = 2.5; - ++dec; - } - } - else if (norm < 7.5) - size = 5; - else - size = 10; - - size *= magn; - - if (axisOptions.minTickSize != null && size < axisOptions.minTickSize) - size = axisOptions.minTickSize; - - if (axisOptions.tickSize != null) - size = axisOptions.tickSize; - - axis.tickDecimals = Math.max(0, (maxDec != null) ? maxDec : dec); - - var floorInBase = this.floorInBase; - - generator = function (axis) { - var ticks = []; - var start = floorInBase(axis.min, axis.tickSize); - // then spew out all possible ticks - var i = 0, v; - do { - v = start + i * axis.tickSize; - ticks.push({ v: v, label: axis.tickFormatter(v, axis) }); - ++i; - } while (v < axis.max); - return ticks; - }; - - formatter = function (v, axis) { - if(v) { - return v.toFixed(axis.tickDecimals); - } - return 0; - }; - } - - axis.tickSize = unit ? [size, unit] : size; - axis.tickGenerator = generator; - if (Object.isFunction(axisOptions.tickFormatter)) - axis.tickFormatter = function (v, axis) { return "" + axisOptions.tickFormatter(v, axis); }; - else - axis.tickFormatter = formatter; - }, - /** - * function: extendXRangeIfNeededByBar - */ - extendXRangeIfNeededByBar: function() { - - if (this.options.xaxis.max == null) { - // great, we're autoscaling, check if we might need a bump - var newmax = this.xaxis.max; - this.graphData.each(function(gd){ - if(gd.bars.show && gd.bars.barWidth + this.xaxis.datamax > newmax) - { - newmax = this.xaxis.datamax + gd.bars.barWidth; - } - }.bind(this)); - this.xaxis.nax = newmax; - - } - }, - /** - * function: setTicks - * - * parameters: - * {Object} axis - * {Object} axisOptions - */ - setTicks: function(axis, axisOptions) { - axis.ticks = []; - - if (axisOptions.ticks == null) - axis.ticks = axis.tickGenerator(axis); - else if (typeof axisOptions.ticks == "number") { - if (axisOptions.ticks > 0) - axis.ticks = axis.tickGenerator(axis); - } - else if (axisOptions.ticks) { - var ticks = axisOptions.ticks; - - if (Object.isFunction(ticks)) - // generate the ticks - ticks = ticks({ min: axis.min, max: axis.max }); - - // clean up the user-supplied ticks, copy them over - //var i, v; - ticks.each(function(t, i){ - var v = null; - var label = null; - if(typeof t == 'object') { - v = t[0]; - if(t.length > 1) { label = t[1]; } - } - else { - v = t; - } - if(!label) { - label = axis.tickFormatter(v, axis); - } - axis.ticks[i] = {v: v, label: label} - }.bind(this)); - - } - - if (axisOptions.autoscaleMargin != null && axis.ticks.length > 0) { - if (axisOptions.min == null) - axis.min = Math.min(axis.min, axis.ticks[0].v); - if (axisOptions.max == null && axis.ticks.length > 1) - axis.max = Math.min(axis.max, axis.ticks[axis.ticks.length - 1].v); - } - }, - /** - * Function: setSpacing - * - * Parameters: none - */ - setSpacing: function() { - // calculate y label dimensions - var i, labels = [], l; - for (i = 0; i < this.yaxis.ticks.length; ++i) { - l = this.yaxis.ticks[i].label; - - if (l) - labels.push('
' + l + '
'); - } - - if (labels.length > 0) { - var dummyDiv = new Element('div', {'style': 'position:absolute;top:-10000px;font-size:smaller'}); - dummyDiv.update(labels.join("")); - this.domObj.insert(dummyDiv); - this.yLabelMaxWidth = dummyDiv.getWidth(); - this.yLabelMaxHeight = dummyDiv.select('div')[0].getHeight(); - dummyDiv.remove(); - } - - var maxOutset = this.options.grid.borderWidth; - if (this.options.points.show) - maxOutset = Math.max(maxOutset, this.options.points.radius + this.options.points.lineWidth/2); - for (i = 0; i < this.graphData.length; ++i) { - if (this.graphData[i].points.show) - maxOutset = Math.max(maxOutset, this.graphData[i].points.radius + this.graphData[i].points.lineWidth/2); - } - - this.chartOffset.left = this.chartOffset.right = this.chartOffset.top = this.chartOffset.bottom = maxOutset; - - this.chartOffset.left += this.yLabelMaxWidth + this.options.grid.labelMargin; - this.chartWidth = this.canvasWidth - this.chartOffset.left - this.chartOffset.right; - - this.xLabelBoxWidth = this.chartWidth / 6; - labels = []; - - for (i = 0; i < this.xaxis.ticks.length; ++i) { - l = this.xaxis.ticks[i].label; - if (l) { - labels.push('' + l + ''); - } - } - - var xLabelMaxHeight = 0; - if (labels.length > 0) { - var dummyDiv = new Element('div', {'style': 'position:absolute;top:-10000px;font-size:smaller'}); - dummyDiv.update(labels.join("")); - this.domObj.appendChild(dummyDiv); - xLabelMaxHeight = dummyDiv.getHeight(); - dummyDiv.remove(); - } - - this.chartOffset.bottom += xLabelMaxHeight + this.options.grid.labelMargin; - this.chartHeight = this.canvasHeight - this.chartOffset.bottom - this.chartOffset.top; - this.hozScale = this.chartWidth / (this.xaxis.max - this.xaxis.min); - this.vertScale = this.chartHeight / (this.yaxis.max - this.yaxis.min); - }, - /** - * function: draw - */ - draw: function() { - if(this.options.bars.show) - { - this.extendXRangeIfNeededByBar(); - this.setSpacing(); - this.drawGrid(); - this.drawBarGraph(this.graphData, this.barDataRange); - } - else if(this.options.pies.show) - { - this.preparePieData(this.graphData); - this.drawPieGraph(this.graphData); - } - else - { - this.drawGrid(); - for (var i = 0; i < this.graphData.length; i++) { - this.drawGraph(this.graphData[i]); - } - } - }, - /** - * function: translateHoz - * - * Paramters: - * {Object} x - * - * Description: Given a value this function translate it to relative x coord on canvas - */ - translateHoz: function(x) { - return (x - this.xaxis.min) * this.hozScale; - }, - /** - * function: translateVert - * - * parameters: - * {Object} y - * - * Description: Given a value this function translate it to relative y coord on canvas - */ - translateVert: function(y) { - return this.chartHeight - (y - this.yaxis.min) * this.vertScale; - }, - /** - * function: drawGrid - * - * parameters: none - * - * description: draws the actual grid on the canvas - */ - drawGrid: function() { - var i; - - this.context.save(); - this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight); - this.context.translate(this.chartOffset.left, this.chartOffset.top); - - // draw background, if any - if (this.options.grid.backgroundColor != null) { - this.context.fillStyle = this.options.grid.backgroundColor; - this.context.fillRect(0, 0, this.chartWidth, this.chartHeight); - } - - // draw colored areas - if (this.options.grid.coloredAreas) { - var areas = this.options.grid.coloredAreas; - if (Object.isFunction(areas)) { - areas = areas({ xmin: this.xaxis.min, xmax: this.xaxis.max, ymin: this.yaxis.min, ymax: this.yaxis.max }); - } - - areas.each(function(a){ - // clip - if (a.x1 == null || a.x1 < this.xaxis.min) - a.x1 = this.xaxis.min; - if (a.x2 == null || a.x2 > this.xaxis.max) - a.x2 = this.xaxis.max; - if (a.y1 == null || a.y1 < this.yaxis.min) - a.y1 = this.yaxis.min; - if (a.y2 == null || a.y2 > this.yaxis.max) - a.y2 = this.yaxis.max; - - var tmp; - if (a.x1 > a.x2) { - tmp = a.x1; - a.x1 = a.x2; - a.x2 = tmp; - } - if (a.y1 > a.y2) { - tmp = a.y1; - a.y1 = a.y2; - a.y2 = tmp; - } - - if (a.x1 >= this.xaxis.max || a.x2 <= this.xaxis.min || a.x1 == a.x2 - || a.y1 >= this.yaxis.max || a.y2 <= this.yaxis.min || a.y1 == a.y2) - return; - - this.context.fillStyle = a.color || this.options.grid.coloredAreasColor; - this.context.fillRect(Math.floor(this.translateHoz(a.x1)), Math.floor(this.translateVert(a.y2)), - Math.floor(this.translateHoz(a.x2) - this.translateHoz(a.x1)), Math.floor(this.translateVert(a.y1) - this.translateVert(a.y2))); - }.bind(this)); - - - } - - // draw the inner grid - this.context.lineWidth = 1; - this.context.strokeStyle = this.options.grid.tickColor; - this.context.beginPath(); - var v; - if (this.options.grid.drawXAxis) { - this.xaxis.ticks.each(function(aTick){ - v = aTick.v; - if(v <= this.xaxis.min || v >= this.xaxis.max) { - return; - } - this.context.moveTo(Math.floor(this.translateHoz(v)) + this.context.lineWidth / 2, 0); - this.context.lineTo(Math.floor(this.translateHoz(v)) + this.context.lineWidth / 2, this.chartHeight); - }.bind(this)); - - } - - if (this.options.grid.drawYAxis) { - this.yaxis.ticks.each(function(aTick){ - v = aTick.v; - if(v <= this.yaxis.min || v >= this.yaxis.max) { - return; - } - this.context.moveTo(0, Math.floor(this.translateVert(v)) + this.context.lineWidth / 2); - this.context.lineTo(this.chartWidth, Math.floor(this.translateVert(v)) + this.context.lineWidth / 2); - }.bind(this)); - - } - this.context.stroke(); - - if (this.options.grid.borderWidth) { - // draw border - this.context.lineWidth = this.options.grid.borderWidth; - this.context.strokeStyle = this.options.grid.color; - this.context.lineJoin = "round"; - this.context.strokeRect(0, 0, this.chartWidth, this.chartHeight); - this.context.restore(); - } - }, - /** - * function: insertLabels - * - * parameters: none - * - * description: inserts the label with proper spacing. Both on X and Y axis - */ - insertLabels: function() { - this.domObj.select(".tickLabels").invoke('remove'); - - var i, tick; - var html = '
'; - - // do the x-axis - this.xaxis.ticks.each(function(tick){ - if (!tick.label || tick.v < this.xaxis.min || tick.v > this.xaxis.max) - return; - html += '
' + tick.label + "
"; - - }.bind(this)); - - // do the y-axis - this.yaxis.ticks.each(function(tick){ - if (!tick.label || tick.v < this.yaxis.min || tick.v > this.yaxis.max) - return; - html += '
' + tick.label + "
"; - }.bind(this)); - - html += '
'; - - this.domObj.insert(html); - }, - /** - * function: drawGraph - * - * Paramters: - * {Object} graphData - * - * Description: given a graphData (series) this function calls a proper lower level method to draw it. - */ - drawGraph: function(graphData) { - if (graphData.lines.show || (!graphData.bars.show && !graphData.points.show)) - this.drawGraphLines(graphData); - if (graphData.bars.show) - this.drawGraphBar(graphData); - if (graphData.points.show) - this.drawGraphPoints(graphData); - }, - /** - * function: plotLine - * - * parameters: - * {Object} data - * {Object} offset - * - * description: - * Helper function that plots a line based on the data provided - */ - plotLine: function(data, offset) { - var prev, cur = null, drawx = null, drawy = null; - - this.context.beginPath(); - for (var i = 0; i < data.length; ++i) { - prev = cur; - cur = data[i]; - - if (prev == null || cur == null) - continue; - - var x1 = prev[0], y1 = prev[1], - x2 = cur[0], y2 = cur[1]; - - // clip with ymin - if (y1 <= y2 && y1 < this.yaxis.min) { - if (y2 < this.yaxis.min) - continue; // line segment is outside - // compute new intersection point - x1 = (this.yaxis.min - y1) / (y2 - y1) * (x2 - x1) + x1; - y1 = this.yaxis.min; - } - else if (y2 <= y1 && y2 < this.yaxis.min) { - if (y1 < this.yaxis.min) - continue; - x2 = (this.yaxis.min - y1) / (y2 - y1) * (x2 - x1) + x1; - y2 = this.yaxis.min; - } - - // clip with ymax - if (y1 >= y2 && y1 > this.yaxis.max) { - if (y2 > this.yaxis.max) - continue; - x1 = (this.yaxis.max - y1) / (y2 - y1) * (x2 - x1) + x1; - y1 = this.yaxis.max; - } - else if (y2 >= y1 && y2 > this.yaxis.max) { - if (y1 > this.yaxis.max) - continue; - x2 = (this.yaxis.max - y1) / (y2 - y1) * (x2 - x1) + x1; - y2 = this.yaxis.max; - } - - // clip with xmin - if (x1 <= x2 && x1 < this.xaxis.min) { - if (x2 < this.xaxis.min) - continue; - y1 = (this.xaxis.min - x1) / (x2 - x1) * (y2 - y1) + y1; - x1 = this.xaxis.min; - } - else if (x2 <= x1 && x2 < this.xaxis.min) { - if (x1 < this.xaxis.min) - continue; - y2 = (this.xaxis.min - x1) / (x2 - x1) * (y2 - y1) + y1; - x2 = this.xaxis.min; - } - - // clip with xmax - if (x1 >= x2 && x1 > this.xaxis.max) { - if (x2 > this.xaxis.max) - continue; - y1 = (this.xaxis.max - x1) / (x2 - x1) * (y2 - y1) + y1; - x1 = this.xaxis.max; - } - else if (x2 >= x1 && x2 > this.xaxis.max) { - if (x1 > this.xaxis.max) - continue; - y2 = (this.xaxis.max - x1) / (x2 - x1) * (y2 - y1) + y1; - x2 = this.xaxis.max; - } - - if (drawx != this.translateHoz(x1) || drawy != this.translateVert(y1) + offset) - this.context.moveTo(this.translateHoz(x1), this.translateVert(y1) + offset); - - drawx = this.translateHoz(x2); - drawy = this.translateVert(y2) + offset; - this.context.lineTo(drawx, drawy); - } - this.context.stroke(); - }, - /** - * function: plotLineArea - * - * parameters: - * {Object} data - * - * description: - * Helper functoin that plots a colored line graph. This function - * takes the data nad then fill in the area on the graph properly - */ - plotLineArea: function(data) { - var prev, cur = null; - - var bottom = Math.min(Math.max(0, this.yaxis.min), this.yaxis.max); - var top, lastX = 0; - - var areaOpen = false; - - for (var i = 0; i < data.length; ++i) { - prev = cur; - cur = data[i]; - - if (areaOpen && prev != null && cur == null) { - // close area - this.context.lineTo(this.translateHoz(lastX), this.translateVert(bottom)); - this.context.fill(); - areaOpen = false; - continue; - } - - if (prev == null || cur == null) - continue; - - var x1 = prev[0], y1 = prev[1], - x2 = cur[0], y2 = cur[1]; - - // clip x values - - // clip with xmin - if (x1 <= x2 && x1 < this.xaxis.min) { - if (x2 < this.xaxis.min) - continue; - y1 = (this.xaxis.min - x1) / (x2 - x1) * (y2 - y1) + y1; - x1 = this.xaxis.min; - } - else if (x2 <= x1 && x2 < this.xaxis.min) { - if (x1 < this.xaxis.min) - continue; - y2 = (this.xaxis.min - x1) / (x2 - x1) * (y2 - y1) + y1; - x2 = this.xaxis.min; - } - - // clip with xmax - if (x1 >= x2 && x1 > this.xaxis.max) { - if (x2 > this.xaxis.max) - continue; - y1 = (this.xaxis.max - x1) / (x2 - x1) * (y2 - y1) + y1; - x1 = this.xaxis.max; - } - else if (x2 >= x1 && x2 > this.xaxis.max) { - if (x1 > this.xaxis.max) - continue; - y2 = (this.xaxis.max - x1) / (x2 - x1) * (y2 - y1) + y1; - x2 = this.xaxis.max; - } - - if (!areaOpen) { - // open area - this.context.beginPath(); - this.context.moveTo(this.translateHoz(x1), this.translateVert(bottom)); - areaOpen = true; - } - - // now first check the case where both is outside - if (y1 >= this.yaxis.max && y2 >= this.yaxis.max) { - this.context.lineTo(this.translateHoz(x1), this.translateVert(this.yaxis.max)); - this.context.lineTo(this.translateHoz(x2), this.translateVert(this.yaxis.max)); - continue; - } - else if (y1 <= this.yaxis.min && y2 <= this.yaxis.min) { - this.context.lineTo(this.translateHoz(x1), this.translateVert(this.yaxis.min)); - this.context.lineTo(this.translateHoz(x2), this.translateVert(this.yaxis.min)); - continue; - } - - var x1old = x1, x2old = x2; - - // clip with ymin - if (y1 <= y2 && y1 < this.yaxis.min && y2 >= this.yaxis.min) { - x1 = (this.yaxis.min - y1) / (y2 - y1) * (x2 - x1) + x1; - y1 = this.yaxis.min; - } - else if (y2 <= y1 && y2 < this.yaxis.min && y1 >= this.yaxis.min) { - x2 = (this.yaxis.min - y1) / (y2 - y1) * (x2 - x1) + x1; - y2 = this.yaxis.min; - } - - // clip with ymax - if (y1 >= y2 && y1 > this.yaxis.max && y2 <= this.yaxis.max) { - x1 = (this.yaxis.max - y1) / (y2 - y1) * (x2 - x1) + x1; - y1 = this.yaxis.max; - } - else if (y2 >= y1 && y2 > this.yaxis.max && y1 <= this.yaxis.max) { - x2 = (this.yaxis.max - y1) / (y2 - y1) * (x2 - x1) + x1; - y2 = this.yaxis.max; - } - - - // if the x value was changed we got a rectangle - // to fill - if (x1 != x1old) { - if (y1 <= this.yaxis.min) - top = this.yaxis.min; - else - top = this.yaxis.max; - - this.context.lineTo(this.translateHoz(x1old), this.translateVert(top)); - this.context.lineTo(this.translateHoz(x1), this.translateVert(top)); - } - - // fill the triangles - this.context.lineTo(this.translateHoz(x1), this.translateVert(y1)); - this.context.lineTo(this.translateHoz(x2), this.translateVert(y2)); - - // fill the other rectangle if it's there - if (x2 != x2old) { - if (y2 <= this.yaxis.min) - top = this.yaxis.min; - else - top = this.yaxis.max; - - this.context.lineTo(this.translateHoz(x2old), this.translateVert(top)); - this.context.lineTo(this.translateHoz(x2), this.translateVert(top)); - } - - lastX = Math.max(x2, x2old); - } - - if (areaOpen) { - this.context.lineTo(this.translateHoz(lastX), this.translateVert(bottom)); - this.context.fill(); - } - }, - /** - * function: drawGraphLines - * - * parameters: - * {Object} graphData - * - * description: - * Main function that daws the line graph. This function is called - * if lines property is set to show or no other type of - * graph is specified. This function depends on and - * functions. - */ - drawGraphLines: function(graphData) { - this.context.save(); - this.context.translate(this.chartOffset.left, this.chartOffset.top); - this.context.lineJoin = "round"; - - var lw = graphData.lines.lineWidth; - var sw = graphData.shadowSize; - // FIXME: consider another form of shadow when filling is turned on - if (sw > 0) { - // draw shadow in two steps - this.context.lineWidth = sw / 2; - this.context.strokeStyle = "rgba(0,0,0,0.1)"; - this.plotLine(graphData.data, lw/2 + sw/2 + this.context.lineWidth/2); - - this.context.lineWidth = sw / 2; - this.context.strokeStyle = "rgba(0,0,0,0.2)"; - this.plotLine(graphData.data, lw/2 + this.context.lineWidth/2); - } - - this.context.lineWidth = lw; - this.context.strokeStyle = graphData.color; - if (graphData.lines.fill) { - this.context.fillStyle = graphData.lines.fillColor != null ? graphData.lines.fillColor : this.parseColor(graphData.color).scale(null, null, null, 0.4).toString(); - this.plotLineArea(graphData.data, 0); - } - - this.plotLine(graphData.data, 0); - this.context.restore(); - }, - /** - * function: plotPoints - * - * parameters: - * {Object} data - * {Object} radius - * {Object} fill - * - * description: - * Helper function that draws the point graph according to the data provided. Size of each - * point is provided by radius variable and fill specifies if points - * are filled - */ - plotPoints: function(data, radius, fill) { - for (var i = 0; i < data.length; ++i) { - if (data[i] == null) - continue; - - var x = data[i][0], y = data[i][1]; - if (x < this.xaxis.min || x > this.xaxis.max || y < this.yaxis.min || y > this.yaxis.max) - continue; - - this.context.beginPath(); - this.context.arc(this.translateHoz(x), this.translateVert(y), radius, 0, 2 * Math.PI, true); - if (fill) - this.context.fill(); - this.context.stroke(); - } - }, - /** - * function: plotPointShadows - * - * parameters: - * {Object} data - * {Object} offset - * {Object} radius - * - * description: - * Helper function that draws the shadows for the points. - */ - plotPointShadows: function(data, offset, radius) { - for (var i = 0; i < data.length; ++i) { - if (data[i] == null) - continue; - - var x = data[i][0], y = data[i][1]; - if (x < this.xaxis.min || x > this.xaxis.max || y < this.yaxis.min || y > this.yaxis.max) - continue; - this.context.beginPath(); - this.context.arc(this.translateHoz(x), this.translateVert(y) + offset, radius, 0, Math.PI, false); - this.context.stroke(); - } - }, - /** - * function: drawGraphPoints - * - * paramters: - * {Object} graphData - * - * description: - * Draws the point graph onto the canvas. This function depends on helper - * functions and - */ - drawGraphPoints: function(graphData) { - this.context.save(); - this.context.translate(this.chartOffset.left, this.chartOffset.top); - - var lw = graphData.lines.lineWidth; - var sw = graphData.shadowSize; - if (sw > 0) { - // draw shadow in two steps - this.context.lineWidth = sw / 2; - this.context.strokeStyle = "rgba(0,0,0,0.1)"; - this.plotPointShadows(graphData.data, sw/2 + this.context.lineWidth/2, graphData.points.radius); - - this.context.lineWidth = sw / 2; - this.context.strokeStyle = "rgba(0,0,0,0.2)"; - this.plotPointShadows(graphData.data, this.context.lineWidth/2, graphData.points.radius); - } - - this.context.lineWidth = graphData.points.lineWidth; - this.context.strokeStyle = graphData.color; - this.context.fillStyle = graphData.points.fillColor != null ? graphData.points.fillColor : graphData.color; - this.plotPoints(graphData.data, graphData.points.radius, graphData.points.fill); - this.context.restore(); - }, - /** - * function: preparePieData - * - * parameters: - * {Object} graphData - * - * Description: - * Helper function that manipulates the given data stream so that it can - * be plotted as a Pie Chart - */ - preparePieData: function(graphData) - { - for(i = 0; i < graphData.length; i++) - { - var data = 0; - for(j = 0; j < graphData[i].data.length; j++){ - data += parseInt(graphData[i].data[j][1]); - } - graphData[i].data = data; - } - }, - /** - * function: drawPieShadow - * - * {Object} anchorX - * {Object} anchorY - * {Object} radius - * - * description: - * Helper function that draws a shadow for the Pie Chart. This just draws - * a circle with offset that simulates shadow. We do not give each piece - * of the pie an individual shadow. - */ - drawPieShadow: function(anchorX, anchorY, radius) - { - this.context.beginPath(); - this.context.moveTo(anchorX, anchorY); - this.context.fillStyle = 'rgba(0,0,0,' + 0.1 + ')'; - startAngle = 0; - endAngle = (Math.PI/180)*360; - this.context.arc(anchorX + 2, anchorY +2, radius + (this.options.shadowSize/2), startAngle, endAngle, false); - this.context.fill(); - this.context.closePath(); - }, - /** - * function: drawPieGraph - * - * parameters: - * {Object} graphData - * - * description: - * Draws the actual pie chart. This function depends on helper function - * to draw the actual shadow - */ - drawPieGraph: function(graphData) - { - var sumData = 0; - var radius = 0; - var centerX = this.chartWidth/2; - var centerY = this.chartHeight/2; - var startAngle = 0; - var endAngle = 0; - var fontSize = this.options.pies.fontSize; - var labelWidth = this.options.pies.labelWidth; - - //determine Pie Radius - if(!this.options.pies.autoScale) - radius = this.options.pies.radius; - else - radius = (this.chartHeight * 0.85)/2; - - var labelRadius = radius * 1.05; - - for(i = 0; i < graphData.length; i++) - sumData += graphData[i].data; - - // used to adjust labels so that everything adds up to 100% - totalPct = 0; - - //lets draw the shadow first.. we don't need an individual shadow to every pie rather we just - //draw a circle underneath to simulate the shadow... - this.drawPieShadow(centerX, centerY, radius, 0, 0); - - //lets draw the actual pie chart now. - graphData.each(function(gd, j){ - var pct = gd.data / sumData; - startAngle = endAngle; - endAngle += pct * (2 * Math.PI); - var sliceMiddle = (endAngle - startAngle) / 2 + startAngle; - var labelX = centerX + Math.cos(sliceMiddle) * labelRadius; - var labelY = centerY + Math.sin(sliceMiddle) * labelRadius; - var anchorX = centerX; - var anchorY = centerY; - var textAlign = null; - var verticalAlign = null; - var left = 0; - var top = 0; - - //draw pie: - //drawing pie - this.context.beginPath(); - this.context.moveTo(anchorX, anchorY); - this.context.arc(anchorX, anchorY, radius, startAngle, endAngle, false); - this.context.closePath(); - this.context.fillStyle = this.parseColor(gd.color).scale(null, null, null, this.options.pies.fillOpacity).toString(); - - if(this.options.pies.fill) { this.context.fill(); } - - // drawing labels - if (sliceMiddle <= 0.25 * (2 * Math.PI)) - { - // text on top and align left - textAlign = "left"; - verticalAlign = "top"; - left = labelX; - top = labelY + fontSize; - } - else if (sliceMiddle > 0.25 * (2 * Math.PI) && sliceMiddle <= 0.5 * (2 * Math.PI)) - { - // text on bottom and align left - textAlign = "left"; - verticalAlign = "bottom"; - left = labelX - labelWidth; - top = labelY; - } - else if (sliceMiddle > 0.5 * (2 * Math.PI) && sliceMiddle <= 0.75 * (2 * Math.PI)) - { - // text on bottom and align right - textAlign = "right"; - verticalAlign = "bottom"; - left = labelX - labelWidth; - top = labelY - fontSize; - } - else - { - // text on top and align right - textAlign = "right"; - verticalAlign = "bottom"; - left = labelX; - top = labelY - fontSize; - } - - left = left + "px"; - top = top + "px"; - var textVal = Math.round(pct * 100); - - if (j == graphData.length - 1) { - if (textVal + totalPct < 100) { - textVal = textVal + 1; - } else if (textVal + totalPct > 100) { - textVal = textVal - 1; - }; - } - - var html = "
" + textVal + "%
"; - //$(html).appendTo(target); - this.domObj.insert(html); - - totalPct = totalPct + textVal; - }.bind(this)); - - }, - /** - * function: drawBarGraph - * - * parameters: - * {Object} graphData - * {Object} barDataRange - * - * description: - * Goes through each series in graphdata and passes it onto function - */ - drawBarGraph: function(graphData, barDataRange) - { - graphData.each(function(gd, i){ - this.drawGraphBars(gd, i, graphData.size(), barDataRange); - }.bind(this)); - }, - /** - * function: drawGraphBar - * - * parameters: - * {Object} graphData - * - * description: - * This function is called when an individual series in GraphData is bar graph and plots it - */ - drawGraphBar: function(graphData) - { - this.drawGraphBars(graphData, 0, this.graphData.length, this.barDataRange); - }, - /** - * function: plotBars - * - * parameters: - * {Object} graphData - * {Object} data - * {Object} barWidth - * {Object} offset - * {Object} fill - * {Object} counter - * {Object} total - * {Object} barDataRange - * - * description: - * Helper function that draws the bar graph based on data. - */ - plotBars: function(graphData, data, barWidth, offset, fill,counter, total, barDataRange) { - var shift = 0; - - if(total % 2 == 0) - { - shift = (1 + ((counter - total /2 ) - 1)) * barWidth; - } - else - { - var interval = 0.5; - if(counter == (total/2 - interval )) { - shift = - barWidth * interval; - } - else { - shift = (interval + (counter - Math.round(total/2))) * barWidth; - } - } - - var rangeData = []; - data.each(function(d){ - if(!d) return; - - var x = d[0], y = d[1]; - var drawLeft = true, drawTop = true, drawRight = true; - var left = x + shift, right = x + barWidth + shift, bottom = 0, top = y; - var rangeDataPoint = {}; - rangeDataPoint.left = left; - rangeDataPoint.right = right; - rangeDataPoint.value = top; - rangeData.push(rangeDataPoint); - - if (right < this.xaxis.min || left > this.xaxis.max || top < this.yaxis.min || bottom > this.yaxis.max) - return; - - // clip - if (left < this.xaxis.min) { - left = this.xaxis.min; - drawLeft = false; - } - - if (right > this.xaxis.max) { - right = this.xaxis.max; - drawRight = false; - } - - if (bottom < this.yaxis.min) - bottom = this.yaxis.min; - - if (top > this.yaxis.max) { - top = this.yaxis.max; - drawTop = false; - } - - if(graphData.bars.showShadow && graphData.shadowSize > 0) - this.plotShadowOutline(graphData, this.context.strokeStyle, left, bottom, top, right, drawLeft, drawRight, drawTop); - - // fill the bar - if (fill) { - this.context.beginPath(); - this.context.moveTo(this.translateHoz(left), this.translateVert(bottom) + offset); - this.context.lineTo(this.translateHoz(left), this.translateVert(top) + offset); - this.context.lineTo(this.translateHoz(right), this.translateVert(top) + offset); - this.context.lineTo(this.translateHoz(right), this.translateVert(bottom) + offset); - this.context.fill(); - } - - // draw outline - if (drawLeft || drawRight || drawTop) { - this.context.beginPath(); - this.context.moveTo(this.translateHoz(left), this.translateVert(bottom) + offset); - if (drawLeft) - this.context.lineTo(this.translateHoz(left), this.translateVert(top) + offset); - else - this.context.moveTo(this.translateHoz(left), this.translateVert(top) + offset); - - if (drawTop) - this.context.lineTo(this.translateHoz(right), this.translateVert(top) + offset); - else - this.context.moveTo(this.translateHoz(right), this.translateVert(top) + offset); - if (drawRight) - this.context.lineTo(this.translateHoz(right), this.translateVert(bottom) + offset); - else - this.context.moveTo(this.translateHoz(right), this.translateVert(bottom) + offset); - this.context.stroke(); - } - }.bind(this)); - - barDataRange.push(rangeData); - }, - /** - * function: plotShadowOutline - * - * parameters: - * {Object} graphData - * {Object} orgStrokeStyle - * {Object} left - * {Object} bottom - * {Object} top - * {Object} right - * {Object} drawLeft - * {Object} drawRight - * {Object} drawTop - * - * description: - * Helper function that draws a outline simulating shadow for bar chart - */ - plotShadowOutline: function(graphData, orgStrokeStyle, left, bottom, top, right, drawLeft, drawRight, drawTop) - { - var orgOpac = 0.3; - - for(var n = 1; n <= this.options.shadowSize/2; n++) - { - var opac = orgOpac * n; - this.context.beginPath(); - this.context.strokeStyle = "rgba(0,0,0," + opac + ")"; - - this.context.moveTo(this.translateHoz(left) + n, this.translateVert(bottom)); - - if(drawLeft) - this.context.lineTo(this.translateHoz(left) + n, this.translateVert(top) - n); - else - this.context.moveTo(this.translateHoz(left) + n, this.translateVert(top) - n); - - if(drawTop) - this.context.lineTo(this.translateHoz(right) + n, this.translateVert(top) - n); - else - this.context.moveTo(this.translateHoz(right) + n, this.translateVert(top) - n); - - if(drawRight) - this.context.lineTo(this.translateHoz(right) + n, this.translateVert(bottom)); - else - this.context.lineTo(this.translateHoz(right) + n, this.translateVert(bottom)); - - this.context.stroke(); - this.context.closePath(); - } - - this.context.strokeStyle = orgStrokeStyle; - }, - /** - * function: drawGraphBars - * - * parameters: - * {Object} graphData - * {Object} counter - * {Object} total - * {Object} barDataRange - * - * description: - * Draws the actual bar graphs. Calls to draw the individual bar - */ - drawGraphBars: function(graphData, counter, total, barDataRange){ - this.context.save(); - this.context.translate(this.chartOffset.left, this.chartOffset.top); - this.context.lineJoin = "round"; - - var bw = graphData.bars.barWidth; - var lw = Math.min(graphData.bars.lineWidth, bw); - - - this.context.lineWidth = lw; - this.context.strokeStyle = graphData.color; - if (graphData.bars.fill) { - this.context.fillStyle = graphData.bars.fillColor != null ? graphData.bars.fillColor : this.parseColor(graphData.color).scale(null, null, null, this.options.bars.fillOpacity).toString(); - } - this.plotBars(graphData, graphData.data, bw, 0, graphData.bars.fill, counter, total, barDataRange); - this.context.restore(); - }, - /** - * function: insertLegend - * - * description: - * inserts legend onto the graph. *legend: {show: true}* must be set in - * for for this to work. - */ - insertLegend: function() { - this.domObj.select(".legend").invoke('remove'); - - if (!this.options.legend.show) - return; - - var fragments = []; - var rowStarted = false; - this.graphData.each(function(gd, index){ - if(!gd.label) { - return; - } - if(index % this.options.legend.noColumns == 0) { - if(rowStarted) { - fragments.push(''); - } - fragments.push(''); - rowStarted = true; - } - var label = gd.label; - if(this.options.legend.labelFormatter != null) { - label = this.options.legend.labelFormatter(label); - } - - fragments.push( - '
' + - '' + label + ''); - - }.bind(this)); - - if (rowStarted) - fragments.push(''); - - if(fragments.length > 0){ - var table = '' + fragments.join("") + '
'; - if($(this.options.legend.container) != null){ - $(this.options.legend.container).insert(table); - }else{ - var pos = ''; - var p = this.options.legend.position, m = this.options.legend.margin; - - if(p.charAt(0) == 'n') pos += 'top:' + (m + this.chartOffset.top) + 'px;'; - else if(p.charAt(0) == 's') pos += 'bottom:' + (m + this.chartOffset.bottom) + 'px;'; - if(p.charAt(1) == 'e') pos += 'right:' + (m + this.chartOffset.right) + 'px;'; - else if(p.charAt(1) == 'w') pos += 'left:' + (m + this.chartOffset.bottom) + 'px;'; - var div = this.domObj.insert('
' + table + '
').getElementsBySelector('div.ProtoChart-legend').first(); - - if(this.options.legend.backgroundOpacity != 0.0){ - var c = this.options.legend.backgroundColor; - if(c == null){ - var tmp = (this.options.grid.backgroundColor != null) ? this.options.grid.backgroundColor : this.extractColor(div); - c = this.parseColor(tmp).adjust(null, null, null, 1).toString(); - } - this.domObj.insert('
').select('div.ProtoChart-legend-bg').first().setStyle({ - 'opacity': this.options.legend.backgroundOpacity - }); - } - } - } - }, - /** - * Function: onMouseMove - * - * parameters: - * event: {Object} ev - * - * Description: - * Called whenever the mouse is moved on the graph. This takes care of the mousetracking. - * This event also fires event, which gets current position of the - * mouse as a parameters. - */ - onMouseMove: function(ev) { - var e = ev || window.event; - if (e.pageX == null && e.clientX != null) { - var de = document.documentElement, b = $(document.body); - this.lastMousePos.pageX = e.clientX + (de && de.scrollLeft || b.scrollLeft || 0); - this.lastMousePos.pageY = e.clientY + (de && de.scrollTop || b.scrollTop || 0); - } - else { - this.lastMousePos.pageX = e.pageX; - this.lastMousePos.pageY = e.pageY; - } - - var offset = this.overlay.cumulativeOffset(); - var pos = { - x: this.xaxis.min + (e.pageX - offset.left - this.chartOffset.left) / this.hozScale, - y: this.yaxis.max - (e.pageY - offset.top - this.chartOffset.top) / this.vertScale - }; - - if(this.options.mouse.track && this.selectionInterval == null) { - this.hit(ev, pos); - } - this.domObj.fire("ProtoChart:mousemove", [ pos ]); - }, - /** - * Function: onMouseDown - * - * Parameters: - * Event - {Object} e - * - * Description: - * Called whenever the mouse is clicked. - */ - onMouseDown: function(e) { - if (e.which != 1) // only accept left-click - return; - - document.body.focus(); - - if (document.onselectstart !== undefined && this.workarounds.onselectstart == null) { - this.workarounds.onselectstart = document.onselectstart; - document.onselectstart = function () { return false; }; - } - if (document.ondrag !== undefined && this.workarounds.ondrag == null) { - this.workarounds.ondrag = document.ondrag; - document.ondrag = function () { return false; }; - } - - this.setSelectionPos(this.selection.first, e); - - if (this.selectionInterval != null) - clearInterval(this.selectionInterval); - this.lastMousePos.pageX = null; - this.selectionInterval = setInterval(this.updateSelectionOnMouseMove.bind(this), 200); - - this.overlay.observe("mouseup", this.onSelectionMouseUp.bind(this)); - }, - /** - * Function: onClick - * parameters: - * Event - {Object} e - * Description: - * Handles the "click" event on the chart. This function fires event. If - * is enabled then it also fires event which gives - * you access to exact data point where user clicked. - */ - onClick: function(e) { - if (this.ignoreClick) { - this.ignoreClick = false; - return; - } - var offset = this.overlay.cumulativeOffset(); - var pos ={ - x: this.xaxis.min + (e.pageX - offset.left - this.chartOffset.left) / this.hozScale, - y: this.yaxis.max - (e.pageY - offset.top - this.chartOffset.top) / this.vertScale - }; - this.domObj.fire("ProtoChart:plotclick", [ pos ]); - - if(this.options.allowDataClick) - { - var dataPoint = {}; - if(this.options.points.show) - { - dataPoint = this.getDataClickPoint(pos, this.options); - this.domObj.fire("ProtoChart:dataclick", [dataPoint]); - } - else if(this.options.lines.show && this.options.points.show) - { - dataPoint = this.getDataClickPoint(pos, this.options); - this.domObj.fire("ProtoChart:dataclick", [dataPoint]); - } - else if(this.options.bars.show) - { - if(this.barDataRange.length > 0) - { - dataPoint = this.getDataClickPoint(pos, this.options, this.barDataRange); - this.domObj.fire("ProtoChart:dataclick", [dataPoint]); - } - } - } - }, - /** - * Internal function used by onClick method. - */ - getDataClickPoint: function(pos, options, barDataRange) - { - pos.x = parseInt(pos.x); - pos.y = parseInt(pos.y); - var yClick = pos.y.toFixed(0); - var dataVal = {}; - - dataVal.position = pos; - dataVal.value = ''; - - if(options.points.show) - { - this.graphData.each(function(gd){ - var temp = gd.data; - var xClick = parseInt(pos.x.toFixed(0)); - if(xClick < 0) { xClick = 0; } - if(temp[xClick] && yClick >= temp[xClick][1] - (this.options.points.radius * 10) && yClick <= temp[xClick][1] + (this.options.points.radius * 10)) { - dataVal.value = temp[xClick][1]; - throw $break; - } - - }.bind(this)); - } - else if(options.bars.show) - { - xClick = pos.x; - this.barDataRange.each(function(barData){ - barData.each(function(data){ - var temp = data; - if(xClick > temp.left && xClick < temp.right) { - dataVal.value = temp.value; - throw $break; - } - }.bind(this)); - }.bind(this)); - - } - - return dataVal; - }, - /** - * Function: triggerSelectedEvent - * - * Description: - * Internal function called when a selection on the graph is made. This function - * fires event which has a parameter representing the selection - * { - * x1: {int}, y1: {int}, - * x2: {int}, y2: {int} - * } - */ - triggerSelectedEvent: function() { - var x1, x2, y1, y2; - if (this.selection.first.x <= this.selection.second.x) { - x1 = this.selection.first.x; - x2 = this.selection.second.x; - } - else { - x1 = this.selection.second.x; - x2 = this.selection.first.x; - } - - if (this.selection.first.y >= this.selection.second.y) { - y1 = this.selection.first.y; - y2 = this.selection.second.y; - } - else { - y1 = this.selection.second.y; - y2 = this.selection.first.y; - } - - x1 = this.xaxis.min + x1 / this.hozScale; - x2 = this.xaxis.min + x2 / this.hozScale; - - y1 = this.yaxis.max - y1 / this.vertScale; - y2 = this.yaxis.max - y2 / this.vertScale; - - this.domObj.fire("ProtoChart:selected", [ { x1: x1, y1: y1, x2: x2, y2: y2 } ]); - }, - /** - * Internal function - */ - onSelectionMouseUp: function(e) { - if (document.onselectstart !== undefined) - document.onselectstart = this.workarounds.onselectstart; - if (document.ondrag !== undefined) - document.ondrag = this.workarounds.ondrag; - - if (this.selectionInterval != null) { - clearInterval(this.selectionInterval); - this.selectionInterval = null; - } - - this.setSelectionPos(this.selection.second, e); - this.clearSelection(); - if (!this.selectionIsSane() || e.which != 1) - return false; - - this.drawSelection(); - this.triggerSelectedEvent(); - this.ignoreClick = true; - - return false; - }, - setSelectionPos: function(pos, e) { - var offset = $(this.overlay).cumulativeOffset(); - if (this.options.selection.mode == "y") { - if (pos == this.selection.first) - pos.x = 0; - else - pos.x = this.chartWidth; - } - else { - pos.x = e.pageX - offset.left - this.chartOffset.left; - pos.x = Math.min(Math.max(0, pos.x), this.chartWidth); - } - - if (this.options.selection.mode == "x") { - if (pos == this.selection.first) - pos.y = 0; - else - pos.y = this.chartHeight; - } - else { - pos.y = e.pageY - offset.top - this.chartOffset.top; - pos.y = Math.min(Math.max(0, pos.y), this.chartHeight); - } - }, - updateSelectionOnMouseMove: function() { - if (this.lastMousePos.pageX == null) - return; - - this.setSelectionPos(this.selection.second, this.lastMousePos); - this.clearSelection(); - if (this.selectionIsSane()) - this.drawSelection(); - }, - clearSelection: function() { - if (this.prevSelection == null) - return; - - var x = Math.min(this.prevSelection.first.x, this.prevSelection.second.x), - y = Math.min(this.prevSelection.first.y, this.prevSelection.second.y), - w = Math.abs(this.prevSelection.second.x - this.prevSelection.first.x), - h = Math.abs(this.prevSelection.second.y - this.prevSelection.first.y); - - this.overlayContext.clearRect(x + this.chartOffset.left - this.overlayContext.lineWidth, - y + this.chartOffset.top - this.overlayContext.lineWidth, - w + this.overlayContext.lineWidth*2, - h + this.overlayContext.lineWidth*2); - - this.prevSelection = null; - }, - /** - * Function: setSelection - * - * Parameters: - * Area - {Object} area represented as a range like: {x1: 3, y1: 3, x2: 4, y2: 8} - * - * Description: - * Sets the current graph selection to the provided range. Calls and - * functions internally. - */ - setSelection: function(area) { - this.clearSelection(); - - if (this.options.selection.mode == "x") { - this.selection.first.y = 0; - this.selection.second.y = this.chartHeight; - } - else { - this.selection.first.y = (this.yaxis.max - area.y1) * this.vertScale; - this.selection.second.y = (this.yaxis.max - area.y2) * this.vertScale; - } - if (this.options.selection.mode == "y") { - this.selection.first.x = 0; - this.selection.second.x = this.chartWidth; - } - else { - this.selection.first.x = (area.x1 - this.xaxis.min) * this.hozScale; - this.selection.second.x = (area.x2 - this.xaxis.min) * this.hozScale; - } - - this.drawSelection(); - this.triggerSelectedEvent(); - }, - /** - * Function: drawSelection - * Description: Internal function called to draw the selection made on the graph. - */ - drawSelection: function() { - if (this.prevSelection != null && - this.selection.first.x == this.prevSelection.first.x && - this.selection.first.y == this.prevSelection.first.y && - this.selection.second.x == this.prevSelection.second.x && - this.selection.second.y == this.prevSelection.second.y) - { - return; - } - - this.overlayContext.strokeStyle = this.parseColor(this.options.selection.color).scale(null, null, null, 0.8).toString(); - this.overlayContext.lineWidth = 1; - this.context.lineJoin = "round"; - this.overlayContext.fillStyle = this.parseColor(this.options.selection.color).scale(null, null, null, 0.4).toString(); - - this.prevSelection = { first: { x: this.selection.first.x, - y: this.selection.first.y }, - second: { x: this.selection.second.x, - y: this.selection.second.y } }; - - var x = Math.min(this.selection.first.x, this.selection.second.x), - y = Math.min(this.selection.first.y, this.selection.second.y), - w = Math.abs(this.selection.second.x - this.selection.first.x), - h = Math.abs(this.selection.second.y - this.selection.first.y); - - this.overlayContext.fillRect(x + this.chartOffset.left, y + this.chartOffset.top, w, h); - this.overlayContext.strokeRect(x + this.chartOffset.left, y + this.chartOffset.top, w, h); - }, - /** - * Internal function - */ - selectionIsSane: function() { - var minSize = 5; - return Math.abs(this.selection.second.x - this.selection.first.x) >= minSize && - Math.abs(this.selection.second.y - this.selection.first.y) >= minSize; - }, - /** - * Internal function that formats the track. This is the format the text is shown when mouse - * tracking is enabled. - */ - defaultTrackFormatter: function(val) - { - return '['+val.x+', '+val.y+']'; - }, - /** - * Function: clearHit - */ - clearHit: function(){ - if(this.prevHit){ - this.overlayContext.clearRect( - this.translateHoz(this.prevHit.x) + this.chartOffset.left - this.options.mouse.radius*2, - this.translateVert(this.prevHit.y) + this.chartOffset.top - this.options.mouse.radius*2, - this.options.mouse.radius*3 + this.options.points.lineWidth*3, - this.options.mouse.radius*3 + this.options.points.lineWidth*3 - ); - this.prevHit = null; - } - }, - /** - * Function: hit - * - * Parameters: - * event - {Object} event object - * mouse - {Object} mouse object that is used to keep track of mouse movement - * - * Description: - * If hit occurs this function will fire a ProtoChart:hit event. - */ - hit: function(event, mouse){ - /** - * Nearest data element. - */ - var n = { - dist:Number.MAX_VALUE, - x:null, - y:null, - mouse:null - }; - - - for(var i = 0, data, xsens, ysens; i < this.graphData.length; i++){ - if(!this.graphData[i].mouse.track) continue; - data = this.graphData[i].data; - xsens = (this.hozScale*this.graphData[i].mouse.sensibility); - ysens = (this.vertScale*this.graphData[i].mouse.sensibility); - for(var j = 0, xabs, yabs; j < data.length; j++){ - xabs = this.hozScale*Math.abs(data[j][0] - mouse.x); - yabs = this.vertScale*Math.abs(data[j][1] - mouse.y); - - if(xabs < xsens && yabs < ysens && (xabs+yabs) < n.dist){ - n.dist = (xabs+yabs); - n.x = data[j][0]; - n.y = data[j][1]; - n.mouse = this.graphData[i].mouse; - } - } - } - - if(n.mouse && n.mouse.track && !this.prevHit || (this.prevHit && n.x != this.prevHit.x && n.y != this.prevHit.y)){ - var el = this.domObj.select('.'+this.options.mouse.clsName).first(); - if(!el){ - var pos = '', p = this.options.mouse.position, m = this.options.mouse.margin; - if(p.charAt(0) == 'n') pos += 'top:' + (m + this.chartOffset.top) + 'px;'; - else if(p.charAt(0) == 's') pos += 'bottom:' + (m + this.chartOffset.bottom) + 'px;'; - if(p.charAt(1) == 'e') pos += 'right:' + (m + this.chartOffset.right) + 'px;'; - else if(p.charAt(1) == 'w') pos += 'left:' + (m + this.chartOffset.bottom) + 'px;'; - - this.domObj.insert(''); - return; - } - if(n.x !== null && n.y !== null){ - el.setStyle({display:'block'}); - - this.clearHit(); - if(n.mouse.lineColor != null){ - this.overlayContext.save(); - this.overlayContext.translate(this.chartOffset.left, this.chartOffset.top); - this.overlayContext.lineWidth = this.options.points.lineWidth; - this.overlayContext.strokeStyle = n.mouse.lineColor; - this.overlayContext.fillStyle = '#ffffff'; - this.overlayContext.beginPath(); - - - this.overlayContext.arc(this.translateHoz(n.x), this.translateVert(n.y), this.options.mouse.radius, 0, 2 * Math.PI, true); - this.overlayContext.fill(); - this.overlayContext.stroke(); - this.overlayContext.restore(); - } - this.prevHit = n; - - var decimals = n.mouse.trackDecimals; - if(decimals == null || decimals < 0) decimals = 0; - if(!this.options.mouse.fixedPosition) - { - el.setStyle({ - left: (this.translateHoz(n.x) + this.options.mouse.radius + 10) + "px", - top: (this.translateVert(n.y) + this.options.mouse.radius + 10) + "px" - }); - } - el.innerHTML = n.mouse.trackFormatter({x: n.x.toFixed(decimals), y: n.y.toFixed(decimals)}); - this.domObj.fire( 'ProtoChart:hit', [n] ) - }else if(this.options.prevHit){ - el.setStyle({display:'none'}); - this.clearHit(); - } - } - }, - /** - * Internal function - */ - floorInBase: function(n, base) { - return base * Math.floor(n / base); - }, - /** - * Function: extractColor - * - * Parameters: - * element - HTML element or ID of an HTML element - * - * Returns: - * color in string format - */ - extractColor: function(element) - { - var color; - do - { - color = $(element).getStyle('background-color').toLowerCase(); - if(color != '' && color != 'transparent') - { - break; - } - element = element.up(0); //or else just get the parent .... - } while(element.nodeName.toLowerCase() != 'body'); - - //safari fix - if(color == 'rgba(0, 0, 0, 0)') - return 'transparent'; - return color; - }, - /** - * Function: parseColor - * - * Parameters: - * str - color string in different formats - * - * Returns: - * a Proto.Color Object - use toString() function to retreive the color in rgba/rgb format - */ - parseColor: function(str) - { - var result; - - /** - * rgb(num,num,num) - */ - if((result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))) - return new Proto.Color(parseInt(result[1]), parseInt(result[2]), parseInt(result[3])); - - /** - * rgba(num,num,num,num) - */ - if((result = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))) - return new Proto.Color(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]), parseFloat(result[4])); - - /** - * rgb(num%,num%,num%) - */ - if((result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))) - return new Proto.Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55); - - /** - * rgba(num%,num%,num%,num) - */ - if((result = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))) - return new Proto.Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55, parseFloat(result[4])); - - /** - * #a0b1c2 - */ - if((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))) - return new Proto.Color(parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)); - - /** - * #fff - */ - if((result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))) - return new Proto.Color(parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)); - - /** - * Otherwise, check if user wants transparent .. or we just return a standard color; - */ - var name = str.strip().toLowerCase(); - if(name == 'transparent'){ - return new Proto.Color(255, 255, 255, 0); - } - - return new Proto.Color(100,100,100, 1); - - } -}); - -if(!Proto) var Proto = {}; - -/** - * Class: Proto.Color - * - * Helper class that manipulates colors using RGBA values. - * - */ - -Proto.Color = Class.create({ - initialize: function(r, g, b, a) { - this.rgba = ['r', 'g', 'b', 'a']; - var x = 4; - while(-1<--x) { - this[this.rgba[x]] = arguments[x] || ((x==3) ? 1.0 : 0); - } - }, - toString: function() { - if(this.a >= 1.0) { - return "rgb(" + [this.r, this.g, this.b].join(",") +")"; - } - else { - return "rgba("+[this.r, this.g, this.b, this.a].join(",")+")"; - } - }, - scale: function(rf, gf, bf, af) { - x = 4; - while(-1<--x) { - if(arguments[x] != null) { - this[this.rgba[x]] *= arguments[x]; - } - } - return this.normalize(); - }, - adjust: function(rd, gd, bd, ad) { - x = 4; //rgba.length - while (-1<--x) { - if (arguments[x] != null) - this[this.rgba[x]] += arguments[x]; - } - return this.normalize(); - }, - clone: function() { - return new Proto.Color(this.r, this.b, this.g, this.a); - }, - limit: function(val,minVal,maxVal) { - return Math.max(Math.min(val, maxVal), minVal); - }, - normalize: function() { - this.r = this.limit(parseInt(this.r), 0, 255); - this.g = this.limit(parseInt(this.g), 0, 255); - this.b = this.limit(parseInt(this.b), 0, 255); - this.a = this.limit(this.a, 0, 1); - return this; - } -}); diff --git a/src/www/protochart/excanvas-compressed.js b/src/www/protochart/excanvas-compressed.js deleted file mode 100644 index 9d71658ad..000000000 --- a/src/www/protochart/excanvas-compressed.js +++ /dev/null @@ -1,19 +0,0 @@ -if(!window.CanvasRenderingContext2D){(function(){var I=Math,i=I.round,L=I.sin,M=I.cos,m=10,A=m/2,Q={init:function(a){var b=a||document;if(/MSIE/.test(navigator.userAgent)&&!window.opera){var c=this;b.attachEvent("onreadystatechange",function(){c.r(b)})}},r:function(a){if(a.readyState=="complete"){if(!a.namespaces["s"]){a.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml")}var b=a.createStyleSheet();b.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}g_vml_\\:*{behavior:url(#default#VML)}"; -var c=a.getElementsByTagName("canvas");for(var d=0;d"){var d="/"+a.tagName,e;while((e=a.nextSibling)&&e.tagName!=d){e.removeNode()}if(e){e.removeNode()}}a.parentNode.replaceChild(c,a);return c},initElement:function(a){a=this.q(a);a.getContext=function(){if(this.l){return this.l}return this.l=new K(this)};a.attachEvent("onpropertychange",V);a.attachEvent("onresize", -W);var b=a.attributes;if(b.width&&b.width.specified){a.style.width=b.width.nodeValue+"px"}else{a.width=a.clientWidth}if(b.height&&b.height.specified){a.style.height=b.height.nodeValue+"px"}else{a.height=a.clientHeight}return a}};function V(a){var b=a.srcElement;switch(a.propertyName){case "width":b.style.width=b.attributes.width.nodeValue+"px";b.getContext().clearRect();break;case "height":b.style.height=b.attributes.height.nodeValue+"px";b.getContext().clearRect();break}}function W(a){var b=a.srcElement; -if(b.firstChild){b.firstChild.style.width=b.clientWidth+"px";b.firstChild.style.height=b.clientHeight+"px"}}Q.init();var R=[];for(var E=0;E<16;E++){for(var F=0;F<16;F++){R[E*16+F]=E.toString(16)+F.toString(16)}}function J(){return[[1,0,0],[0,1,0],[0,0,1]]}function G(a,b){var c=J();for(var d=0;d<3;d++){for(var e=0;e<3;e++){var g=0;for(var h=0;h<3;h++){g+=a[d][h]*b[h][e]}c[d][e]=g}}return c}function N(a,b){b.fillStyle=a.fillStyle;b.lineCap=a.lineCap;b.lineJoin=a.lineJoin;b.lineWidth=a.lineWidth;b.miterLimit= -a.miterLimit;b.shadowBlur=a.shadowBlur;b.shadowColor=a.shadowColor;b.shadowOffsetX=a.shadowOffsetX;b.shadowOffsetY=a.shadowOffsetY;b.strokeStyle=a.strokeStyle;b.d=a.d;b.e=a.e}function O(a){var b,c=1;a=String(a);if(a.substring(0,3)=="rgb"){var d=a.indexOf("(",3),e=a.indexOf(")",d+1),g=a.substring(d+1,e).split(",");b="#";for(var h=0;h<3;h++){b+=R[Number(g[h])]}if(g.length==4&&a.substr(3,1)=="a"){c=g[3]}}else{b=a}return[b,c]}function S(a){switch(a){case "butt":return"flat";case "round":return"round"; -case "square":default:return"square"}}function K(a){this.a=J();this.m=[];this.k=[];this.c=[];this.strokeStyle="#000";this.fillStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=m*1;this.globalAlpha=1;this.canvas=a;var b=a.ownerDocument.createElement("div");b.style.width=a.clientWidth+"px";b.style.height=a.clientHeight+"px";b.style.overflow="hidden";b.style.position="absolute";a.appendChild(b);this.j=b;this.d=1;this.e=1}var j=K.prototype;j.clearRect=function(){this.j.innerHTML= -"";this.c=[]};j.beginPath=function(){this.c=[]};j.moveTo=function(a,b){this.c.push({type:"moveTo",x:a,y:b});this.f=a;this.g=b};j.lineTo=function(a,b){this.c.push({type:"lineTo",x:a,y:b});this.f=a;this.g=b};j.bezierCurveTo=function(a,b,c,d,e,g){this.c.push({type:"bezierCurveTo",cp1x:a,cp1y:b,cp2x:c,cp2y:d,x:e,y:g});this.f=e;this.g=g};j.quadraticCurveTo=function(a,b,c,d){var e=this.f+0.6666666666666666*(a-this.f),g=this.g+0.6666666666666666*(b-this.g),h=e+(c-this.f)/3,l=g+(d-this.g)/3;this.bezierCurveTo(e, -g,h,l,c,d)};j.arc=function(a,b,c,d,e,g){c*=m;var h=g?"at":"wa",l=a+M(d)*c-A,n=b+L(d)*c-A,o=a+M(e)*c-A,f=b+L(e)*c-A;if(l==o&&!g){l+=0.125}this.c.push({type:h,x:a,y:b,radius:c,xStart:l,yStart:n,xEnd:o,yEnd:f})};j.rect=function(a,b,c,d){this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+d);this.lineTo(a,b+d);this.closePath()};j.strokeRect=function(a,b,c,d){this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+d);this.lineTo(a,b+d);this.closePath();this.stroke()};j.fillRect=function(a, -b,c,d){this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+d);this.lineTo(a,b+d);this.closePath();this.fill()};j.createLinearGradient=function(a,b,c,d){var e=new H("gradient");return e};j.createRadialGradient=function(a,b,c,d,e,g){var h=new H("gradientradial");h.n=c;h.o=g;h.i.x=a;h.i.y=b;return h};j.drawImage=function(a,b){var c,d,e,g,h,l,n,o,f=a.runtimeStyle.width,k=a.runtimeStyle.height;a.runtimeStyle.width="auto";a.runtimeStyle.height="auto";var q=a.width,r=a.height;a.runtimeStyle.width= -f;a.runtimeStyle.height=k;if(arguments.length==3){c=arguments[1];d=arguments[2];h=(l=0);n=(e=q);o=(g=r)}else if(arguments.length==5){c=arguments[1];d=arguments[2];e=arguments[3];g=arguments[4];h=(l=0);n=q;o=r}else if(arguments.length==9){h=arguments[1];l=arguments[2];n=arguments[3];o=arguments[4];c=arguments[5];d=arguments[6];e=arguments[7];g=arguments[8]}else{throw"Invalid number of arguments";}var s=this.b(c,d),t=[],v=10,w=10;t.push(" ','","");this.j.insertAdjacentHTML("BeforeEnd",t.join(""))};j.stroke=function(a){var b=[],c=O(a?this.fillStyle:this.strokeStyle),d=c[0],e=c[1]*this.globalAlpha,g=10,h=10;b.push("n.x){n.x=k.x}if(l.y== -null||k.yn.y){n.y=k.y}}}b.push(' ">');if(typeof this.fillStyle=="object"){var v={x:"50%",y:"50%"},w=n.x-l.x,x=n.y-l.y,p=w>x?w:x;v.x=i(this.fillStyle.i.x/w*100+50)+"%";v.y=i(this.fillStyle.i.y/x*100+50)+"%";var y=[];if(this.fillStyle.p=="gradientradial"){var z=this.fillStyle.n/p*100,B=this.fillStyle.o/p*100-z}else{var z=0,B=100}var C={offset:null,color:null},D={offset:null,color:null};this.fillStyle.h.sort(function(T,U){return T.offset-U.offset});for(var o=0;oC.offset||C.offset==null){C.offset=u.offset;C.color=u.color}if(u.offset')}else if(a){b.push('')}else{b.push("')}b.push("");this.j.insertAdjacentHTML("beforeEnd",b.join(""));this.c=[]};j.fill=function(){this.stroke(true)};j.closePath=function(){this.c.push({type:"close"})};j.b=function(a,b){return{x:m*(a*this.a[0][0]+b*this.a[1][0]+this.a[2][0])-A,y:m*(a*this.a[0][1]+b*this.a[1][1]+this.a[2][1])-A}};j.save=function(){var a={};N(this,a); -this.k.push(a);this.m.push(this.a);this.a=G(J(),this.a)};j.restore=function(){N(this.k.pop(),this);this.a=this.m.pop()};j.translate=function(a,b){var c=[[1,0,0],[0,1,0],[a,b,1]];this.a=G(c,this.a)};j.rotate=function(a){var b=M(a),c=L(a),d=[[b,c,0],[-c,b,0],[0,0,1]];this.a=G(d,this.a)};j.scale=function(a,b){this.d*=a;this.e*=b;var c=[[a,0,0],[0,b,0],[0,0,1]];this.a=G(c,this.a)};j.clip=function(){};j.arcTo=function(){};j.createPattern=function(){return new P};function H(a){this.p=a;this.n=0;this.o= -0;this.h=[];this.i={x:0,y:0}}H.prototype.addColorStop=function(a,b){b=O(b);this.h.push({offset:1-a,color:b})};function P(){}G_vmlCanvasManager=Q;CanvasRenderingContext2D=K;CanvasGradient=H;CanvasPattern=P})()}; diff --git a/src/www/protochart/excanvas.js b/src/www/protochart/excanvas.js deleted file mode 100644 index f8780b62e..000000000 --- a/src/www/protochart/excanvas.js +++ /dev/null @@ -1,785 +0,0 @@ -// Copyright 2006 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -// Known Issues: -// -// * Patterns are not implemented. -// * Radial gradient are not implemented. The VML version of these look very -// different from the canvas one. -// * Clipping paths are not implemented. -// * Coordsize. The width and height attribute have higher priority than the -// width and height style values which isn't correct. -// * Painting mode isn't implemented. -// * Canvas width/height should is using content-box by default. IE in -// Quirks mode will draw the canvas using border-box. Either change your -// doctype to HTML5 -// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype) -// or use Box Sizing Behavior from WebFX -// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html) -// * Optimize. There is always room for speed improvements. - -// only add this code if we do not already have a canvas implementation -if (!window.CanvasRenderingContext2D) { - -(function () { - - // alias some functions to make (compiled) code shorter - var m = Math; - var mr = m.round; - var ms = m.sin; - var mc = m.cos; - - // this is used for sub pixel precision - var Z = 10; - var Z2 = Z / 2; - - var G_vmlCanvasManager_ = { - init: function (opt_doc) { - var doc = opt_doc || document; - if (/MSIE/.test(navigator.userAgent) && !window.opera) { - var self = this; - doc.attachEvent("onreadystatechange", function () { - self.init_(doc); - }); - } - }, - - init_: function (doc) { - if (doc.readyState == "complete") { - // create xmlns - if (!doc.namespaces["g_vml_"]) { - doc.namespaces.add("g_vml_", "urn:schemas-microsoft-com:vml"); - } - - // setup default css - var ss = doc.createStyleSheet(); - ss.cssText = "canvas{display:inline-block;overflow:hidden;" + - // default size is 300x150 in Gecko and Opera - "text-align:left;width:300px;height:150px}" + - "g_vml_\\:*{behavior:url(#default#VML)}"; - - // find all canvas elements - var els = doc.getElementsByTagName("canvas"); - for (var i = 0; i < els.length; i++) { - if (!els[i].getContext) { - this.initElement(els[i]); - } - } - } - }, - - fixElement_: function (el) { - // in IE before version 5.5 we would need to add HTML: to the tag name - // but we do not care about IE before version 6 - var outerHTML = el.outerHTML; - - var newEl = el.ownerDocument.createElement(outerHTML); - // if the tag is still open IE has created the children as siblings and - // it has also created a tag with the name "/FOO" - if (outerHTML.slice(-2) != "/>") { - var tagName = "/" + el.tagName; - var ns; - // remove content - while ((ns = el.nextSibling) && ns.tagName != tagName) { - ns.removeNode(); - } - // remove the incorrect closing tag - if (ns) { - ns.removeNode(); - } - } - el.parentNode.replaceChild(newEl, el); - return newEl; - }, - - /** - * Public initializes a canvas element so that it can be used as canvas - * element from now on. This is called automatically before the page is - * loaded but if you are creating elements using createElement you need to - * make sure this is called on the element. - * @param {HTMLElement} el The canvas element to initialize. - * @return {HTMLElement} the element that was created. - */ - initElement: function (el) { - el = this.fixElement_(el); - el.getContext = function () { - if (this.context_) { - return this.context_; - } - return this.context_ = new CanvasRenderingContext2D_(this); - }; - - // do not use inline function because that will leak memory - el.attachEvent('onpropertychange', onPropertyChange); - el.attachEvent('onresize', onResize); - - var attrs = el.attributes; - if (attrs.width && attrs.width.specified) { - // TODO: use runtimeStyle and coordsize - // el.getContext().setWidth_(attrs.width.nodeValue); - el.style.width = attrs.width.nodeValue + "px"; - } else { - el.width = el.clientWidth; - } - if (attrs.height && attrs.height.specified) { - // TODO: use runtimeStyle and coordsize - // el.getContext().setHeight_(attrs.height.nodeValue); - el.style.height = attrs.height.nodeValue + "px"; - } else { - el.height = el.clientHeight; - } - //el.getContext().setCoordsize_() - return el; - } - }; - - function onPropertyChange(e) { - var el = e.srcElement; - - switch (e.propertyName) { - case 'width': - el.style.width = el.attributes.width.nodeValue + "px"; - el.getContext().clearRect(); - break; - case 'height': - el.style.height = el.attributes.height.nodeValue + "px"; - el.getContext().clearRect(); - break; - } - } - - function onResize(e) { - var el = e.srcElement; - if (el.firstChild) { - el.firstChild.style.width = el.clientWidth + 'px'; - el.firstChild.style.height = el.clientHeight + 'px'; - } - } - - G_vmlCanvasManager_.init(); - - // precompute "00" to "FF" - var dec2hex = []; - for (var i = 0; i < 16; i++) { - for (var j = 0; j < 16; j++) { - dec2hex[i * 16 + j] = i.toString(16) + j.toString(16); - } - } - - function createMatrixIdentity() { - return [ - [1, 0, 0], - [0, 1, 0], - [0, 0, 1] - ]; - } - - function matrixMultiply(m1, m2) { - var result = createMatrixIdentity(); - - for (var x = 0; x < 3; x++) { - for (var y = 0; y < 3; y++) { - var sum = 0; - - for (var z = 0; z < 3; z++) { - sum += m1[x][z] * m2[z][y]; - } - - result[x][y] = sum; - } - } - return result; - } - - function copyState(o1, o2) { - o2.fillStyle = o1.fillStyle; - o2.lineCap = o1.lineCap; - o2.lineJoin = o1.lineJoin; - o2.lineWidth = o1.lineWidth; - o2.miterLimit = o1.miterLimit; - o2.shadowBlur = o1.shadowBlur; - o2.shadowColor = o1.shadowColor; - o2.shadowOffsetX = o1.shadowOffsetX; - o2.shadowOffsetY = o1.shadowOffsetY; - o2.strokeStyle = o1.strokeStyle; - o2.arcScaleX_ = o1.arcScaleX_; - o2.arcScaleY_ = o1.arcScaleY_; - } - - function processStyle(styleString) { - var str, alpha = 1; - - styleString = String(styleString); - if (styleString.substring(0, 3) == "rgb") { - var start = styleString.indexOf("(", 3); - var end = styleString.indexOf(")", start + 1); - var guts = styleString.substring(start + 1, end).split(","); - - str = "#"; - for (var i = 0; i < 3; i++) { - str += dec2hex[Number(guts[i])]; - } - - if ((guts.length == 4) && (styleString.substr(3, 1) == "a")) { - alpha = guts[3]; - } - } else { - str = styleString; - } - - return [str, alpha]; - } - - function processLineCap(lineCap) { - switch (lineCap) { - case "butt": - return "flat"; - case "round": - return "round"; - case "square": - default: - return "square"; - } - } - - /** - * This class implements CanvasRenderingContext2D interface as described by - * the WHATWG. - * @param {HTMLElement} surfaceElement The element that the 2D context should - * be associated with - */ - function CanvasRenderingContext2D_(surfaceElement) { - this.m_ = createMatrixIdentity(); - - this.mStack_ = []; - this.aStack_ = []; - this.currentPath_ = []; - - // Canvas context properties - this.strokeStyle = "#000"; - this.fillStyle = "#000"; - - this.lineWidth = 1; - this.lineJoin = "miter"; - this.lineCap = "butt"; - this.miterLimit = Z * 1; - this.globalAlpha = 1; - this.canvas = surfaceElement; - - var el = surfaceElement.ownerDocument.createElement('div'); - el.style.width = surfaceElement.clientWidth + 'px'; - el.style.height = surfaceElement.clientHeight + 'px'; - el.style.overflow = 'hidden'; - el.style.position = 'absolute'; - surfaceElement.appendChild(el); - - this.element_ = el; - this.arcScaleX_ = 1; - this.arcScaleY_ = 1; - } - - var contextPrototype = CanvasRenderingContext2D_.prototype; - contextPrototype.clearRect = function() { - this.element_.innerHTML = ""; - this.currentPath_ = []; - }; - - contextPrototype.beginPath = function() { - // TODO: Branch current matrix so that save/restore has no effect - // as per safari docs. - - this.currentPath_ = []; - }; - - contextPrototype.moveTo = function(aX, aY) { - this.currentPath_.push({type: "moveTo", x: aX, y: aY}); - this.currentX_ = aX; - this.currentY_ = aY; - }; - - contextPrototype.lineTo = function(aX, aY) { - this.currentPath_.push({type: "lineTo", x: aX, y: aY}); - this.currentX_ = aX; - this.currentY_ = aY; - }; - - contextPrototype.bezierCurveTo = function(aCP1x, aCP1y, - aCP2x, aCP2y, - aX, aY) { - this.currentPath_.push({type: "bezierCurveTo", - cp1x: aCP1x, - cp1y: aCP1y, - cp2x: aCP2x, - cp2y: aCP2y, - x: aX, - y: aY}); - this.currentX_ = aX; - this.currentY_ = aY; - }; - - contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) { - // the following is lifted almost directly from - // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes - var cp1x = this.currentX_ + 2.0 / 3.0 * (aCPx - this.currentX_); - var cp1y = this.currentY_ + 2.0 / 3.0 * (aCPy - this.currentY_); - var cp2x = cp1x + (aX - this.currentX_) / 3.0; - var cp2y = cp1y + (aY - this.currentY_) / 3.0; - this.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, aX, aY); - }; - - contextPrototype.arc = function(aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise) { - aRadius *= Z; - var arcType = aClockwise ? "at" : "wa"; - - var xStart = aX + (mc(aStartAngle) * aRadius) - Z2; - var yStart = aY + (ms(aStartAngle) * aRadius) - Z2; - - var xEnd = aX + (mc(aEndAngle) * aRadius) - Z2; - var yEnd = aY + (ms(aEndAngle) * aRadius) - Z2; - - // IE won't render arches drawn counter clockwise if xStart == xEnd. - if (xStart == xEnd && !aClockwise) { - xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something - // that can be represented in binary - } - - this.currentPath_.push({type: arcType, - x: aX, - y: aY, - radius: aRadius, - xStart: xStart, - yStart: yStart, - xEnd: xEnd, - yEnd: yEnd}); - - }; - - contextPrototype.rect = function(aX, aY, aWidth, aHeight) { - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - }; - - contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) { - // Will destroy any existing path (same as FF behaviour) - this.beginPath(); - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - this.stroke(); - }; - - contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) { - // Will destroy any existing path (same as FF behaviour) - this.beginPath(); - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - this.fill(); - }; - - contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) { - var gradient = new CanvasGradient_("gradient"); - return gradient; - }; - - contextPrototype.createRadialGradient = function(aX0, aY0, - aR0, aX1, - aY1, aR1) { - var gradient = new CanvasGradient_("gradientradial"); - gradient.radius1_ = aR0; - gradient.radius2_ = aR1; - gradient.focus_.x = aX0; - gradient.focus_.y = aY0; - return gradient; - }; - - contextPrototype.drawImage = function (image, var_args) { - var dx, dy, dw, dh, sx, sy, sw, sh; - - // to find the original width we overide the width and height - var oldRuntimeWidth = image.runtimeStyle.width; - var oldRuntimeHeight = image.runtimeStyle.height; - image.runtimeStyle.width = 'auto'; - image.runtimeStyle.height = 'auto'; - - // get the original size - var w = image.width; - var h = image.height; - - // and remove overides - image.runtimeStyle.width = oldRuntimeWidth; - image.runtimeStyle.height = oldRuntimeHeight; - - if (arguments.length == 3) { - dx = arguments[1]; - dy = arguments[2]; - sx = sy = 0; - sw = dw = w; - sh = dh = h; - } else if (arguments.length == 5) { - dx = arguments[1]; - dy = arguments[2]; - dw = arguments[3]; - dh = arguments[4]; - sx = sy = 0; - sw = w; - sh = h; - } else if (arguments.length == 9) { - sx = arguments[1]; - sy = arguments[2]; - sw = arguments[3]; - sh = arguments[4]; - dx = arguments[5]; - dy = arguments[6]; - dw = arguments[7]; - dh = arguments[8]; - } else { - throw "Invalid number of arguments"; - } - - var d = this.getCoords_(dx, dy); - - var w2 = sw / 2; - var h2 = sh / 2; - - var vmlStr = []; - - var W = 10; - var H = 10; - - // For some reason that I've now forgotten, using divs didn't work - vmlStr.push(' ' , - '', - ''); - - this.element_.insertAdjacentHTML("BeforeEnd", - vmlStr.join("")); - }; - - contextPrototype.stroke = function(aFill) { - var lineStr = []; - var lineOpen = false; - var a = processStyle(aFill ? this.fillStyle : this.strokeStyle); - var color = a[0]; - var opacity = a[1] * this.globalAlpha; - - var W = 10; - var H = 10; - - lineStr.push(' max.x) { - max.x = c.x; - } - if (min.y == null || c.y < min.y) { - min.y = c.y; - } - if (max.y == null || c.y > max.y) { - max.y = c.y; - } - } - } - lineStr.push(' ">'); - - if (typeof this.fillStyle == "object") { - var focus = {x: "50%", y: "50%"}; - var width = (max.x - min.x); - var height = (max.y - min.y); - var dimension = (width > height) ? width : height; - - focus.x = mr((this.fillStyle.focus_.x / width) * 100 + 50) + "%"; - focus.y = mr((this.fillStyle.focus_.y / height) * 100 + 50) + "%"; - - var colors = []; - - // inside radius (%) - if (this.fillStyle.type_ == "gradientradial") { - var inside = (this.fillStyle.radius1_ / dimension * 100); - - // percentage that outside radius exceeds inside radius - var expansion = (this.fillStyle.radius2_ / dimension * 100) - inside; - } else { - var inside = 0; - var expansion = 100; - } - - var insidecolor = {offset: null, color: null}; - var outsidecolor = {offset: null, color: null}; - - // We need to sort 'colors' by percentage, from 0 > 100 otherwise ie - // won't interpret it correctly - this.fillStyle.colors_.sort(function (cs1, cs2) { - return cs1.offset - cs2.offset; - }); - - for (var i = 0; i < this.fillStyle.colors_.length; i++) { - var fs = this.fillStyle.colors_[i]; - - colors.push( (fs.offset * expansion) + inside, "% ", fs.color, ","); - - if (fs.offset > insidecolor.offset || insidecolor.offset == null) { - insidecolor.offset = fs.offset; - insidecolor.color = fs.color; - } - - if (fs.offset < outsidecolor.offset || outsidecolor.offset == null) { - outsidecolor.offset = fs.offset; - outsidecolor.color = fs.color; - } - } - colors.pop(); - - lineStr.push(''); - } else if (aFill) { - lineStr.push(''); - } else { - lineStr.push( - '' - ); - } - - lineStr.push(""); - - this.element_.insertAdjacentHTML("beforeEnd", lineStr.join("")); - - //this.currentPath_ = []; - }; - - contextPrototype.fill = function() { - this.stroke(true); - }; - - contextPrototype.closePath = function() { - this.currentPath_.push({type: "close"}); - }; - - /** - * @private - */ - contextPrototype.getCoords_ = function(aX, aY) { - return { - x: Z * (aX * this.m_[0][0] + aY * this.m_[1][0] + this.m_[2][0]) - Z2, - y: Z * (aX * this.m_[0][1] + aY * this.m_[1][1] + this.m_[2][1]) - Z2 - }; - }; - - contextPrototype.save = function() { - var o = {}; - copyState(this, o); - this.aStack_.push(o); - this.mStack_.push(this.m_); - this.m_ = matrixMultiply(createMatrixIdentity(), this.m_); - }; - - contextPrototype.restore = function() { - copyState(this.aStack_.pop(), this); - this.m_ = this.mStack_.pop(); - }; - - contextPrototype.translate = function(aX, aY) { - var m1 = [ - [1, 0, 0], - [0, 1, 0], - [aX, aY, 1] - ]; - - this.m_ = matrixMultiply(m1, this.m_); - }; - - contextPrototype.rotate = function(aRot) { - var c = mc(aRot); - var s = ms(aRot); - - var m1 = [ - [c, s, 0], - [-s, c, 0], - [0, 0, 1] - ]; - - this.m_ = matrixMultiply(m1, this.m_); - }; - - contextPrototype.scale = function(aX, aY) { - this.arcScaleX_ *= aX; - this.arcScaleY_ *= aY; - var m1 = [ - [aX, 0, 0], - [0, aY, 0], - [0, 0, 1] - ]; - - this.m_ = matrixMultiply(m1, this.m_); - }; - - /******** STUBS ********/ - contextPrototype.clip = function() { - // TODO: Implement - }; - - contextPrototype.arcTo = function() { - // TODO: Implement - }; - - contextPrototype.createPattern = function() { - return new CanvasPattern_; - }; - - // Gradient / Pattern Stubs - function CanvasGradient_(aType) { - this.type_ = aType; - this.radius1_ = 0; - this.radius2_ = 0; - this.colors_ = []; - this.focus_ = {x: 0, y: 0}; - } - - CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) { - aColor = processStyle(aColor); - this.colors_.push({offset: 1-aOffset, color: aColor}); - }; - - function CanvasPattern_() {} - - // set up externs - G_vmlCanvasManager = G_vmlCanvasManager_; - CanvasRenderingContext2D = CanvasRenderingContext2D_; - CanvasGradient = CanvasGradient_; - CanvasPattern = CanvasPattern_; - -})(); - -} // if diff --git a/src/www/protochart/prototype.js b/src/www/protochart/prototype.js deleted file mode 100644 index 1075d889a..000000000 --- a/src/www/protochart/prototype.js +++ /dev/null @@ -1,4221 +0,0 @@ -/* Prototype JavaScript framework, version 1.6.0.2 - * (c) 2005-2008 Sam Stephenson - * - * Prototype is freely distributable under the terms of an MIT-style license. - * For details, see the Prototype web site: http://www.prototypejs.org/ - * - *--------------------------------------------------------------------------*/ - -var Prototype = { - Version: '1.6.0.2', - - Browser: { - IE: !!(window.attachEvent && !window.opera), - Opera: !!window.opera, - WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, - Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1, - MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) - }, - - BrowserFeatures: { - XPath: !!document.evaluate, - ElementExtensions: !!window.HTMLElement, - SpecificElementExtensions: - document.createElement('div').__proto__ && - document.createElement('div').__proto__ !== - document.createElement('form').__proto__ - }, - - ScriptFragment: ']*>([\\S\\s]*?)<\/script>', - JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, - - emptyFunction: function() { }, - K: function(x) { return x } -}; - -if (Prototype.Browser.MobileSafari) - Prototype.BrowserFeatures.SpecificElementExtensions = false; - - -/* Based on Alex Arnell's inheritance implementation. */ -var Class = { - create: function() { - var parent = null, properties = $A(arguments); - if (Object.isFunction(properties[0])) - parent = properties.shift(); - - function klass() { - this.initialize.apply(this, arguments); - } - - Object.extend(klass, Class.Methods); - klass.superclass = parent; - klass.subclasses = []; - - if (parent) { - var subclass = function() { }; - subclass.prototype = parent.prototype; - klass.prototype = new subclass; - parent.subclasses.push(klass); - } - - for (var i = 0; i < properties.length; i++) - klass.addMethods(properties[i]); - - if (!klass.prototype.initialize) - klass.prototype.initialize = Prototype.emptyFunction; - - klass.prototype.constructor = klass; - - return klass; - } -}; - -Class.Methods = { - addMethods: function(source) { - var ancestor = this.superclass && this.superclass.prototype; - var properties = Object.keys(source); - - if (!Object.keys({ toString: true }).length) - properties.push("toString", "valueOf"); - - for (var i = 0, length = properties.length; i < length; i++) { - var property = properties[i], value = source[property]; - if (ancestor && Object.isFunction(value) && - value.argumentNames().first() == "$super") { - var method = value, value = Object.extend((function(m) { - return function() { return ancestor[m].apply(this, arguments) }; - })(property).wrap(method), { - valueOf: function() { return method }, - toString: function() { return method.toString() } - }); - } - this.prototype[property] = value; - } - - return this; - } -}; - -var Abstract = { }; - -Object.extend = function(destination, source) { - for (var property in source) - destination[property] = source[property]; - return destination; -}; - -Object.extend(Object, { - inspect: function(object) { - try { - if (Object.isUndefined(object)) return 'undefined'; - if (object === null) return 'null'; - return object.inspect ? object.inspect() : String(object); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; - } - }, - - toJSON: function(object) { - var type = typeof object; - switch (type) { - case 'undefined': - case 'function': - case 'unknown': return; - case 'boolean': return object.toString(); - } - - if (object === null) return 'null'; - if (object.toJSON) return object.toJSON(); - if (Object.isElement(object)) return; - - var results = []; - for (var property in object) { - var value = Object.toJSON(object[property]); - if (!Object.isUndefined(value)) - results.push(property.toJSON() + ': ' + value); - } - - return '{' + results.join(', ') + '}'; - }, - - toQueryString: function(object) { - return $H(object).toQueryString(); - }, - - toHTML: function(object) { - return object && object.toHTML ? object.toHTML() : String.interpret(object); - }, - - keys: function(object) { - var keys = []; - for (var property in object) - keys.push(property); - return keys; - }, - - values: function(object) { - var values = []; - for (var property in object) - values.push(object[property]); - return values; - }, - - clone: function(object) { - return Object.extend({ }, object); - }, - - isElement: function(object) { - return object && object.nodeType == 1; - }, - - isArray: function(object) { - return object != null && typeof object == "object" && - 'splice' in object && 'join' in object; - }, - - isHash: function(object) { - return object instanceof Hash; - }, - - isFunction: function(object) { - return typeof object == "function"; - }, - - isString: function(object) { - return typeof object == "string"; - }, - - isNumber: function(object) { - return typeof object == "number"; - }, - - isUndefined: function(object) { - return typeof object == "undefined"; - } -}); - -Object.extend(Function.prototype, { - argumentNames: function() { - var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip"); - return names.length == 1 && !names[0] ? [] : names; - }, - - bind: function() { - if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; - var __method = this, args = $A(arguments), object = args.shift(); - return function() { - return __method.apply(object, args.concat($A(arguments))); - } - }, - - bindAsEventListener: function() { - var __method = this, args = $A(arguments), object = args.shift(); - return function(event) { - return __method.apply(object, [event || window.event].concat(args)); - } - }, - - curry: function() { - if (!arguments.length) return this; - var __method = this, args = $A(arguments); - return function() { - return __method.apply(this, args.concat($A(arguments))); - } - }, - - delay: function() { - var __method = this, args = $A(arguments), timeout = args.shift() * 1000; - return window.setTimeout(function() { - return __method.apply(__method, args); - }, timeout); - }, - - wrap: function(wrapper) { - var __method = this; - return function() { - return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); - } - }, - - methodize: function() { - if (this._methodized) return this._methodized; - var __method = this; - return this._methodized = function() { - return __method.apply(null, [this].concat($A(arguments))); - }; - } -}); - -Function.prototype.defer = Function.prototype.delay.curry(0.01); - -Date.prototype.toJSON = function() { - return '"' + this.getUTCFullYear() + '-' + - (this.getUTCMonth() + 1).toPaddedString(2) + '-' + - this.getUTCDate().toPaddedString(2) + 'T' + - this.getUTCHours().toPaddedString(2) + ':' + - this.getUTCMinutes().toPaddedString(2) + ':' + - this.getUTCSeconds().toPaddedString(2) + 'Z"'; -}; - -var Try = { - these: function() { - var returnValue; - - for (var i = 0, length = arguments.length; i < length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) { } - } - - return returnValue; - } -}; - -RegExp.prototype.match = RegExp.prototype.test; - -RegExp.escape = function(str) { - return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); -}; - -/*--------------------------------------------------------------------------*/ - -var PeriodicalExecuter = Class.create({ - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - execute: function() { - this.callback(this); - }, - - stop: function() { - if (!this.timer) return; - clearInterval(this.timer); - this.timer = null; - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.execute(); - } finally { - this.currentlyExecuting = false; - } - } - } -}); -Object.extend(String, { - interpret: function(value) { - return value == null ? '' : String(value); - }, - specialChar: { - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '\\': '\\\\' - } -}); - -Object.extend(String.prototype, { - gsub: function(pattern, replacement) { - var result = '', source = this, match; - replacement = arguments.callee.prepareReplacement(replacement); - - while (source.length > 0) { - if (match = source.match(pattern)) { - result += source.slice(0, match.index); - result += String.interpret(replacement(match)); - source = source.slice(match.index + match[0].length); - } else { - result += source, source = ''; - } - } - return result; - }, - - sub: function(pattern, replacement, count) { - replacement = this.gsub.prepareReplacement(replacement); - count = Object.isUndefined(count) ? 1 : count; - - return this.gsub(pattern, function(match) { - if (--count < 0) return match[0]; - return replacement(match); - }); - }, - - scan: function(pattern, iterator) { - this.gsub(pattern, iterator); - return String(this); - }, - - truncate: function(length, truncation) { - length = length || 30; - truncation = Object.isUndefined(truncation) ? '...' : truncation; - return this.length > length ? - this.slice(0, length - truncation.length) + truncation : String(this); - }, - - strip: function() { - return this.replace(/^\s+/, '').replace(/\s+$/, ''); - }, - - stripTags: function() { - return this.replace(/<\/?[^>]+>/gi, ''); - }, - - stripScripts: function() { - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); - }, - - extractScripts: function() { - var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); - var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); - return (this.match(matchAll) || []).map(function(scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }); - }, - - evalScripts: function() { - return this.extractScripts().map(function(script) { return eval(script) }); - }, - - escapeHTML: function() { - var self = arguments.callee; - self.text.data = this; - return self.div.innerHTML; - }, - - unescapeHTML: function() { - var div = new Element('div'); - div.innerHTML = this.stripTags(); - return div.childNodes[0] ? (div.childNodes.length > 1 ? - $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : - div.childNodes[0].nodeValue) : ''; - }, - - toQueryParams: function(separator) { - var match = this.strip().match(/([^?#]*)(#.*)?$/); - if (!match) return { }; - - return match[1].split(separator || '&').inject({ }, function(hash, pair) { - if ((pair = pair.split('='))[0]) { - var key = decodeURIComponent(pair.shift()); - var value = pair.length > 1 ? pair.join('=') : pair[0]; - if (value != undefined) value = decodeURIComponent(value); - - if (key in hash) { - if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; - hash[key].push(value); - } - else hash[key] = value; - } - return hash; - }); - }, - - toArray: function() { - return this.split(''); - }, - - succ: function() { - return this.slice(0, this.length - 1) + - String.fromCharCode(this.charCodeAt(this.length - 1) + 1); - }, - - times: function(count) { - return count < 1 ? '' : new Array(count + 1).join(this); - }, - - camelize: function() { - var parts = this.split('-'), len = parts.length; - if (len == 1) return parts[0]; - - var camelized = this.charAt(0) == '-' - ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) - : parts[0]; - - for (var i = 1; i < len; i++) - camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); - - return camelized; - }, - - capitalize: function() { - return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); - }, - - underscore: function() { - return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); - }, - - dasherize: function() { - return this.gsub(/_/,'-'); - }, - - inspect: function(useDoubleQuotes) { - var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { - var character = String.specialChar[match[0]]; - return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); - }); - if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; - return "'" + escapedString.replace(/'/g, '\\\'') + "'"; - }, - - toJSON: function() { - return this.inspect(true); - }, - - unfilterJSON: function(filter) { - return this.sub(filter || Prototype.JSONFilter, '#{1}'); - }, - - isJSON: function() { - var str = this; - if (str.blank()) return false; - str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); - return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); - }, - - evalJSON: function(sanitize) { - var json = this.unfilterJSON(); - try { - if (!sanitize || json.isJSON()) return eval('(' + json + ')'); - } catch (e) { } - throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); - }, - - include: function(pattern) { - return this.indexOf(pattern) > -1; - }, - - startsWith: function(pattern) { - return this.indexOf(pattern) === 0; - }, - - endsWith: function(pattern) { - var d = this.length - pattern.length; - return d >= 0 && this.lastIndexOf(pattern) === d; - }, - - empty: function() { - return this == ''; - }, - - blank: function() { - return /^\s*$/.test(this); - }, - - interpolate: function(object, pattern) { - return new Template(this, pattern).evaluate(object); - } -}); - -if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { - escapeHTML: function() { - return this.replace(/&/g,'&').replace(//g,'>'); - }, - unescapeHTML: function() { - return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); - } -}); - -String.prototype.gsub.prepareReplacement = function(replacement) { - if (Object.isFunction(replacement)) return replacement; - var template = new Template(replacement); - return function(match) { return template.evaluate(match) }; -}; - -String.prototype.parseQuery = String.prototype.toQueryParams; - -Object.extend(String.prototype.escapeHTML, { - div: document.createElement('div'), - text: document.createTextNode('') -}); - -with (String.prototype.escapeHTML) div.appendChild(text); - -var Template = Class.create({ - initialize: function(template, pattern) { - this.template = template.toString(); - this.pattern = pattern || Template.Pattern; - }, - - evaluate: function(object) { - if (Object.isFunction(object.toTemplateReplacements)) - object = object.toTemplateReplacements(); - - return this.template.gsub(this.pattern, function(match) { - if (object == null) return ''; - - var before = match[1] || ''; - if (before == '\\') return match[2]; - - var ctx = object, expr = match[3]; - var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; - match = pattern.exec(expr); - if (match == null) return before; - - while (match != null) { - var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; - ctx = ctx[comp]; - if (null == ctx || '' == match[3]) break; - expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); - match = pattern.exec(expr); - } - - return before + String.interpret(ctx); - }); - } -}); -Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; - -var $break = { }; - -var Enumerable = { - each: function(iterator, context) { - var index = 0; - iterator = iterator.bind(context); - try { - this._each(function(value) { - iterator(value, index++); - }); - } catch (e) { - if (e != $break) throw e; - } - return this; - }, - - eachSlice: function(number, iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; - var index = -number, slices = [], array = this.toArray(); - while ((index += number) < array.length) - slices.push(array.slice(index, index+number)); - return slices.collect(iterator, context); - }, - - all: function(iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; - var result = true; - this.each(function(value, index) { - result = result && !!iterator(value, index); - if (!result) throw $break; - }); - return result; - }, - - any: function(iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; - var result = false; - this.each(function(value, index) { - if (result = !!iterator(value, index)) - throw $break; - }); - return result; - }, - - collect: function(iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; - var results = []; - this.each(function(value, index) { - results.push(iterator(value, index)); - }); - return results; - }, - - detect: function(iterator, context) { - iterator = iterator.bind(context); - var result; - this.each(function(value, index) { - if (iterator(value, index)) { - result = value; - throw $break; - } - }); - return result; - }, - - findAll: function(iterator, context) { - iterator = iterator.bind(context); - var results = []; - this.each(function(value, index) { - if (iterator(value, index)) - results.push(value); - }); - return results; - }, - - grep: function(filter, iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; - var results = []; - - if (Object.isString(filter)) - filter = new RegExp(filter); - - this.each(function(value, index) { - if (filter.match(value)) - results.push(iterator(value, index)); - }); - return results; - }, - - include: function(object) { - if (Object.isFunction(this.indexOf)) - if (this.indexOf(object) != -1) return true; - - var found = false; - this.each(function(value) { - if (value == object) { - found = true; - throw $break; - } - }); - return found; - }, - - inGroupsOf: function(number, fillWith) { - fillWith = Object.isUndefined(fillWith) ? null : fillWith; - return this.eachSlice(number, function(slice) { - while(slice.length < number) slice.push(fillWith); - return slice; - }); - }, - - inject: function(memo, iterator, context) { - iterator = iterator.bind(context); - this.each(function(value, index) { - memo = iterator(memo, value, index); - }); - return memo; - }, - - invoke: function(method) { - var args = $A(arguments).slice(1); - return this.map(function(value) { - return value[method].apply(value, args); - }); - }, - - max: function(iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; - var result; - this.each(function(value, index) { - value = iterator(value, index); - if (result == null || value >= result) - result = value; - }); - return result; - }, - - min: function(iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; - var result; - this.each(function(value, index) { - value = iterator(value, index); - if (result == null || value < result) - result = value; - }); - return result; - }, - - partition: function(iterator, context) { - iterator = iterator ? iterator.bind(context) : Prototype.K; - var trues = [], falses = []; - this.each(function(value, index) { - (iterator(value, index) ? - trues : falses).push(value); - }); - return [trues, falses]; - }, - - pluck: function(property) { - var results = []; - this.each(function(value) { - results.push(value[property]); - }); - return results; - }, - - reject: function(iterator, context) { - iterator = iterator.bind(context); - var results = []; - this.each(function(value, index) { - if (!iterator(value, index)) - results.push(value); - }); - return results; - }, - - sortBy: function(iterator, context) { - iterator = iterator.bind(context); - return this.map(function(value, index) { - return {value: value, criteria: iterator(value, index)}; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - }, - - toArray: function() { - return this.map(); - }, - - zip: function() { - var iterator = Prototype.K, args = $A(arguments); - if (Object.isFunction(args.last())) - iterator = args.pop(); - - var collections = [this].concat(args).map($A); - return this.map(function(value, index) { - return iterator(collections.pluck(index)); - }); - }, - - size: function() { - return this.toArray().length; - }, - - inspect: function() { - return '#'; - } -}; - -Object.extend(Enumerable, { - map: Enumerable.collect, - find: Enumerable.detect, - select: Enumerable.findAll, - filter: Enumerable.findAll, - member: Enumerable.include, - entries: Enumerable.toArray, - every: Enumerable.all, - some: Enumerable.any -}); -function $A(iterable) { - if (!iterable) return []; - if (iterable.toArray) return iterable.toArray(); - var length = iterable.length || 0, results = new Array(length); - while (length--) results[length] = iterable[length]; - return results; -} - -if (Prototype.Browser.WebKit) { - $A = function(iterable) { - if (!iterable) return []; - if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') && - iterable.toArray) return iterable.toArray(); - var length = iterable.length || 0, results = new Array(length); - while (length--) results[length] = iterable[length]; - return results; - }; -} - -Array.from = $A; - -Object.extend(Array.prototype, Enumerable); - -if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; - -Object.extend(Array.prototype, { - _each: function(iterator) { - for (var i = 0, length = this.length; i < length; i++) - iterator(this[i]); - }, - - clear: function() { - this.length = 0; - return this; - }, - - first: function() { - return this[0]; - }, - - last: function() { - return this[this.length - 1]; - }, - - compact: function() { - return this.select(function(value) { - return value != null; - }); - }, - - flatten: function() { - return this.inject([], function(array, value) { - return array.concat(Object.isArray(value) ? - value.flatten() : [value]); - }); - }, - - without: function() { - var values = $A(arguments); - return this.select(function(value) { - return !values.include(value); - }); - }, - - reverse: function(inline) { - return (inline !== false ? this : this.toArray())._reverse(); - }, - - reduce: function() { - return this.length > 1 ? this : this[0]; - }, - - uniq: function(sorted) { - return this.inject([], function(array, value, index) { - if (0 == index || (sorted ? array.last() != value : !array.include(value))) - array.push(value); - return array; - }); - }, - - intersect: function(array) { - return this.uniq().findAll(function(item) { - return array.detect(function(value) { return item === value }); - }); - }, - - clone: function() { - return [].concat(this); - }, - - size: function() { - return this.length; - }, - - inspect: function() { - return '[' + this.map(Object.inspect).join(', ') + ']'; - }, - - toJSON: function() { - var results = []; - this.each(function(object) { - var value = Object.toJSON(object); - if (!Object.isUndefined(value)) results.push(value); - }); - return '[' + results.join(', ') + ']'; - } -}); - -// use native browser JS 1.6 implementation if available -if (Object.isFunction(Array.prototype.forEach)) - Array.prototype._each = Array.prototype.forEach; - -if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { - i || (i = 0); - var length = this.length; - if (i < 0) i = length + i; - for (; i < length; i++) - if (this[i] === item) return i; - return -1; -}; - -if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { - i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; - var n = this.slice(0, i).reverse().indexOf(item); - return (n < 0) ? n : i - n - 1; -}; - -Array.prototype.toArray = Array.prototype.clone; - -function $w(string) { - if (!Object.isString(string)) return []; - string = string.strip(); - return string ? string.split(/\s+/) : []; -} - -if (Prototype.Browser.Opera){ - Array.prototype.concat = function() { - var array = []; - for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); - for (var i = 0, length = arguments.length; i < length; i++) { - if (Object.isArray(arguments[i])) { - for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) - array.push(arguments[i][j]); - } else { - array.push(arguments[i]); - } - } - return array; - }; -} -Object.extend(Number.prototype, { - toColorPart: function() { - return this.toPaddedString(2, 16); - }, - - succ: function() { - return this + 1; - }, - - times: function(iterator) { - $R(0, this, true).each(iterator); - return this; - }, - - toPaddedString: function(length, radix) { - var string = this.toString(radix || 10); - return '0'.times(length - string.length) + string; - }, - - toJSON: function() { - return isFinite(this) ? this.toString() : 'null'; - } -}); - -$w('abs round ceil floor').each(function(method){ - Number.prototype[method] = Math[method].methodize(); -}); -function $H(object) { - return new Hash(object); -}; - -var Hash = Class.create(Enumerable, (function() { - - function toQueryPair(key, value) { - if (Object.isUndefined(value)) return key; - return key + '=' + encodeURIComponent(String.interpret(value)); - } - - return { - initialize: function(object) { - this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); - }, - - _each: function(iterator) { - for (var key in this._object) { - var value = this._object[key], pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - }, - - set: function(key, value) { - return this._object[key] = value; - }, - - get: function(key) { - return this._object[key]; - }, - - unset: function(key) { - var value = this._object[key]; - delete this._object[key]; - return value; - }, - - toObject: function() { - return Object.clone(this._object); - }, - - keys: function() { - return this.pluck('key'); - }, - - values: function() { - return this.pluck('value'); - }, - - index: function(value) { - var match = this.detect(function(pair) { - return pair.value === value; - }); - return match && match.key; - }, - - merge: function(object) { - return this.clone().update(object); - }, - - update: function(object) { - return new Hash(object).inject(this, function(result, pair) { - result.set(pair.key, pair.value); - return result; - }); - }, - - toQueryString: function() { - return this.map(function(pair) { - var key = encodeURIComponent(pair.key), values = pair.value; - - if (values && typeof values == 'object') { - if (Object.isArray(values)) - return values.map(toQueryPair.curry(key)).join('&'); - } - return toQueryPair(key, values); - }).join('&'); - }, - - inspect: function() { - return '#'; - }, - - toJSON: function() { - return Object.toJSON(this.toObject()); - }, - - clone: function() { - return new Hash(this); - } - } -})()); - -Hash.prototype.toTemplateReplacements = Hash.prototype.toObject; -Hash.from = $H; -var ObjectRange = Class.create(Enumerable, { - initialize: function(start, end, exclusive) { - this.start = start; - this.end = end; - this.exclusive = exclusive; - }, - - _each: function(iterator) { - var value = this.start; - while (this.include(value)) { - iterator(value); - value = value.succ(); - } - }, - - include: function(value) { - if (value < this.start) - return false; - if (this.exclusive) - return value < this.end; - return value <= this.end; - } -}); - -var $R = function(start, end, exclusive) { - return new ObjectRange(start, end, exclusive); -}; - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new XMLHttpRequest()}, - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')} - ) || false; - }, - - activeRequestCount: 0 -}; - -Ajax.Responders = { - responders: [], - - _each: function(iterator) { - this.responders._each(iterator); - }, - - register: function(responder) { - if (!this.include(responder)) - this.responders.push(responder); - }, - - unregister: function(responder) { - this.responders = this.responders.without(responder); - }, - - dispatch: function(callback, request, transport, json) { - this.each(function(responder) { - if (Object.isFunction(responder[callback])) { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) { } - } - }); - } -}; - -Object.extend(Ajax.Responders, Enumerable); - -Ajax.Responders.register({ - onCreate: function() { Ajax.activeRequestCount++ }, - onComplete: function() { Ajax.activeRequestCount-- } -}); - -Ajax.Base = Class.create({ - initialize: function(options) { - this.options = { - method: 'post', - asynchronous: true, - contentType: 'application/x-www-form-urlencoded', - encoding: 'UTF-8', - parameters: '', - evalJSON: true, - evalJS: true - }; - Object.extend(this.options, options || { }); - - this.options.method = this.options.method.toLowerCase(); - - if (Object.isString(this.options.parameters)) - this.options.parameters = this.options.parameters.toQueryParams(); - else if (Object.isHash(this.options.parameters)) - this.options.parameters = this.options.parameters.toObject(); - } -}); - -Ajax.Request = Class.create(Ajax.Base, { - _complete: false, - - initialize: function($super, url, options) { - $super(options); - this.transport = Ajax.getTransport(); - this.request(url); - }, - - request: function(url) { - this.url = url; - this.method = this.options.method; - var params = Object.clone(this.options.parameters); - - if (!['get', 'post'].include(this.method)) { - // simulate other verbs over post - params['_method'] = this.method; - this.method = 'post'; - } - - this.parameters = params; - - if (params = Object.toQueryString(params)) { - // when GET, append parameters to URL - if (this.method == 'get') - this.url += (this.url.include('?') ? '&' : '?') + params; - else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) - params += '&_='; - } - - try { - var response = new Ajax.Response(this); - if (this.options.onCreate) this.options.onCreate(response); - Ajax.Responders.dispatch('onCreate', this, response); - - this.transport.open(this.method.toUpperCase(), this.url, - this.options.asynchronous); - - if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); - - this.transport.onreadystatechange = this.onStateChange.bind(this); - this.setRequestHeaders(); - - this.body = this.method == 'post' ? (this.options.postBody || params) : null; - this.transport.send(this.body); - - /* Force Firefox to handle ready state 4 for synchronous requests */ - if (!this.options.asynchronous && this.transport.overrideMimeType) - this.onStateChange(); - - } - catch (e) { - this.dispatchException(e); - } - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState > 1 && !((readyState == 4) && this._complete)) - this.respondToReadyState(this.transport.readyState); - }, - - setRequestHeaders: function() { - var headers = { - 'X-Requested-With': 'XMLHttpRequest', - 'X-Prototype-Version': Prototype.Version, - 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' - }; - - if (this.method == 'post') { - headers['Content-type'] = this.options.contentType + - (this.options.encoding ? '; charset=' + this.options.encoding : ''); - - /* Force "Connection: close" for older Mozilla browsers to work - * around a bug where XMLHttpRequest sends an incorrect - * Content-length header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType && - (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) - headers['Connection'] = 'close'; - } - - // user-defined headers - if (typeof this.options.requestHeaders == 'object') { - var extras = this.options.requestHeaders; - - if (Object.isFunction(extras.push)) - for (var i = 0, length = extras.length; i < length; i += 2) - headers[extras[i]] = extras[i+1]; - else - $H(extras).each(function(pair) { headers[pair.key] = pair.value }); - } - - for (var name in headers) - this.transport.setRequestHeader(name, headers[name]); - }, - - success: function() { - var status = this.getStatus(); - return !status || (status >= 200 && status < 300); - }, - - getStatus: function() { - try { - return this.transport.status || 0; - } catch (e) { return 0 } - }, - - respondToReadyState: function(readyState) { - var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); - - if (state == 'Complete') { - try { - this._complete = true; - (this.options['on' + response.status] - || this.options['on' + (this.success() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - var contentType = response.getHeader('Content-type'); - if (this.options.evalJS == 'force' - || (this.options.evalJS && this.isSameOrigin() && contentType - && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) - this.evalResponse(); - } - - try { - (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); - Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - if (state == 'Complete') { - // avoid memory leak in MSIE: clean up - this.transport.onreadystatechange = Prototype.emptyFunction; - } - }, - - isSameOrigin: function() { - var m = this.url.match(/^\s*https?:\/\/[^\/]*/); - return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ - protocol: location.protocol, - domain: document.domain, - port: location.port ? ':' + location.port : '' - })); - }, - - getHeader: function(name) { - try { - return this.transport.getResponseHeader(name) || null; - } catch (e) { return null } - }, - - evalResponse: function() { - try { - return eval((this.transport.responseText || '').unfilterJSON()); - } catch (e) { - this.dispatchException(e); - } - }, - - dispatchException: function(exception) { - (this.options.onException || Prototype.emptyFunction)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - -Ajax.Response = Class.create({ - initialize: function(request){ - this.request = request; - var transport = this.transport = request.transport, - readyState = this.readyState = transport.readyState; - - if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { - this.status = this.getStatus(); - this.statusText = this.getStatusText(); - this.responseText = String.interpret(transport.responseText); - this.headerJSON = this._getHeaderJSON(); - } - - if(readyState == 4) { - var xml = transport.responseXML; - this.responseXML = Object.isUndefined(xml) ? null : xml; - this.responseJSON = this._getResponseJSON(); - } - }, - - status: 0, - statusText: '', - - getStatus: Ajax.Request.prototype.getStatus, - - getStatusText: function() { - try { - return this.transport.statusText || ''; - } catch (e) { return '' } - }, - - getHeader: Ajax.Request.prototype.getHeader, - - getAllHeaders: function() { - try { - return this.getAllResponseHeaders(); - } catch (e) { return null } - }, - - getResponseHeader: function(name) { - return this.transport.getResponseHeader(name); - }, - - getAllResponseHeaders: function() { - return this.transport.getAllResponseHeaders(); - }, - - _getHeaderJSON: function() { - var json = this.getHeader('X-JSON'); - if (!json) return null; - json = decodeURIComponent(escape(json)); - try { - return json.evalJSON(this.request.options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - }, - - _getResponseJSON: function() { - var options = this.request.options; - if (!options.evalJSON || (options.evalJSON != 'force' && - !(this.getHeader('Content-type') || '').include('application/json')) || - this.responseText.blank()) - return null; - try { - return this.responseText.evalJSON(options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - } -}); - -Ajax.Updater = Class.create(Ajax.Request, { - initialize: function($super, container, url, options) { - this.container = { - success: (container.success || container), - failure: (container.failure || (container.success ? null : container)) - }; - - options = Object.clone(options); - var onComplete = options.onComplete; - options.onComplete = (function(response, json) { - this.updateContent(response.responseText); - if (Object.isFunction(onComplete)) onComplete(response, json); - }).bind(this); - - $super(url, options); - }, - - updateContent: function(responseText) { - var receiver = this.container[this.success() ? 'success' : 'failure'], - options = this.options; - - if (!options.evalScripts) responseText = responseText.stripScripts(); - - if (receiver = $(receiver)) { - if (options.insertion) { - if (Object.isString(options.insertion)) { - var insertion = { }; insertion[options.insertion] = responseText; - receiver.insert(insertion); - } - else options.insertion(receiver, responseText); - } - else receiver.update(responseText); - } - } -}); - -Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { - initialize: function($super, container, url, options) { - $super(options); - this.onComplete = this.options.onComplete; - - this.frequency = (this.options.frequency || 2); - this.decay = (this.options.decay || 1); - - this.updater = { }; - this.container = container; - this.url = url; - - this.start(); - }, - - start: function() { - this.options.onComplete = this.updateComplete.bind(this); - this.onTimerEvent(); - }, - - stop: function() { - this.updater.options.onComplete = undefined; - clearTimeout(this.timer); - (this.onComplete || Prototype.emptyFunction).apply(this, arguments); - }, - - updateComplete: function(response) { - if (this.options.decay) { - this.decay = (response.responseText == this.lastText ? - this.decay * this.options.decay : 1); - - this.lastText = response.responseText; - } - this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); - }, - - onTimerEvent: function() { - this.updater = new Ajax.Updater(this.container, this.url, this.options); - } -}); -function $(element) { - if (arguments.length > 1) { - for (var i = 0, elements = [], length = arguments.length; i < length; i++) - elements.push($(arguments[i])); - return elements; - } - if (Object.isString(element)) - element = document.getElementById(element); - return Element.extend(element); -} - -if (Prototype.BrowserFeatures.XPath) { - document._getElementsByXPath = function(expression, parentElement) { - var results = []; - var query = document.evaluate(expression, $(parentElement) || document, - null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); - for (var i = 0, length = query.snapshotLength; i < length; i++) - results.push(Element.extend(query.snapshotItem(i))); - return results; - }; -} - -/*--------------------------------------------------------------------------*/ - -if (!window.Node) var Node = { }; - -if (!Node.ELEMENT_NODE) { - // DOM level 2 ECMAScript Language Binding - Object.extend(Node, { - ELEMENT_NODE: 1, - ATTRIBUTE_NODE: 2, - TEXT_NODE: 3, - CDATA_SECTION_NODE: 4, - ENTITY_REFERENCE_NODE: 5, - ENTITY_NODE: 6, - PROCESSING_INSTRUCTION_NODE: 7, - COMMENT_NODE: 8, - DOCUMENT_NODE: 9, - DOCUMENT_TYPE_NODE: 10, - DOCUMENT_FRAGMENT_NODE: 11, - NOTATION_NODE: 12 - }); -} - -(function() { - var element = this.Element; - this.Element = function(tagName, attributes) { - attributes = attributes || { }; - tagName = tagName.toLowerCase(); - var cache = Element.cache; - if (Prototype.Browser.IE && attributes.name) { - tagName = '<' + tagName + ' name="' + attributes.name + '">'; - delete attributes.name; - return Element.writeAttribute(document.createElement(tagName), attributes); - } - if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); - return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); - }; - Object.extend(this.Element, element || { }); -}).call(window); - -Element.cache = { }; - -Element.Methods = { - visible: function(element) { - return $(element).style.display != 'none'; - }, - - toggle: function(element) { - element = $(element); - Element[Element.visible(element) ? 'hide' : 'show'](element); - return element; - }, - - hide: function(element) { - $(element).style.display = 'none'; - return element; - }, - - show: function(element) { - $(element).style.display = ''; - return element; - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - return element; - }, - - update: function(element, content) { - element = $(element); - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) return element.update().insert(content); - content = Object.toHTML(content); - element.innerHTML = content.stripScripts(); - content.evalScripts.bind(content).defer(); - return element; - }, - - replace: function(element, content) { - element = $(element); - if (content && content.toElement) content = content.toElement(); - else if (!Object.isElement(content)) { - content = Object.toHTML(content); - var range = element.ownerDocument.createRange(); - range.selectNode(element); - content.evalScripts.bind(content).defer(); - content = range.createContextualFragment(content.stripScripts()); - } - element.parentNode.replaceChild(content, element); - return element; - }, - - insert: function(element, insertions) { - element = $(element); - - if (Object.isString(insertions) || Object.isNumber(insertions) || - Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) - insertions = {bottom:insertions}; - - var content, insert, tagName, childNodes; - - for (var position in insertions) { - content = insertions[position]; - position = position.toLowerCase(); - insert = Element._insertionTranslations[position]; - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - insert(element, content); - continue; - } - - content = Object.toHTML(content); - - tagName = ((position == 'before' || position == 'after') - ? element.parentNode : element).tagName.toUpperCase(); - - childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - - if (position == 'top' || position == 'after') childNodes.reverse(); - childNodes.each(insert.curry(element)); - - content.evalScripts.bind(content).defer(); - } - - return element; - }, - - wrap: function(element, wrapper, attributes) { - element = $(element); - if (Object.isElement(wrapper)) - $(wrapper).writeAttribute(attributes || { }); - else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); - else wrapper = new Element('div', wrapper); - if (element.parentNode) - element.parentNode.replaceChild(wrapper, element); - wrapper.appendChild(element); - return wrapper; - }, - - inspect: function(element) { - element = $(element); - var result = '<' + element.tagName.toLowerCase(); - $H({'id': 'id', 'className': 'class'}).each(function(pair) { - var property = pair.first(), attribute = pair.last(); - var value = (element[property] || '').toString(); - if (value) result += ' ' + attribute + '=' + value.inspect(true); - }); - return result + '>'; - }, - - recursivelyCollect: function(element, property) { - element = $(element); - var elements = []; - while (element = element[property]) - if (element.nodeType == 1) - elements.push(Element.extend(element)); - return elements; - }, - - ancestors: function(element) { - return $(element).recursivelyCollect('parentNode'); - }, - - descendants: function(element) { - return $(element).select("*"); - }, - - firstDescendant: function(element) { - element = $(element).firstChild; - while (element && element.nodeType != 1) element = element.nextSibling; - return $(element); - }, - - immediateDescendants: function(element) { - if (!(element = $(element).firstChild)) return []; - while (element && element.nodeType != 1) element = element.nextSibling; - if (element) return [element].concat($(element).nextSiblings()); - return []; - }, - - previousSiblings: function(element) { - return $(element).recursivelyCollect('previousSibling'); - }, - - nextSiblings: function(element) { - return $(element).recursivelyCollect('nextSibling'); - }, - - siblings: function(element) { - element = $(element); - return element.previousSiblings().reverse().concat(element.nextSiblings()); - }, - - match: function(element, selector) { - if (Object.isString(selector)) - selector = new Selector(selector); - return selector.match($(element)); - }, - - up: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(element.parentNode); - var ancestors = element.ancestors(); - return Object.isNumber(expression) ? ancestors[expression] : - Selector.findElement(ancestors, expression, index); - }, - - down: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return element.firstDescendant(); - return Object.isNumber(expression) ? element.descendants()[expression] : - element.select(expression)[index || 0]; - }, - - previous: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); - var previousSiblings = element.previousSiblings(); - return Object.isNumber(expression) ? previousSiblings[expression] : - Selector.findElement(previousSiblings, expression, index); - }, - - next: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); - var nextSiblings = element.nextSiblings(); - return Object.isNumber(expression) ? nextSiblings[expression] : - Selector.findElement(nextSiblings, expression, index); - }, - - select: function() { - var args = $A(arguments), element = $(args.shift()); - return Selector.findChildElements(element, args); - }, - - adjacent: function() { - var args = $A(arguments), element = $(args.shift()); - return Selector.findChildElements(element.parentNode, args).without(element); - }, - - identify: function(element) { - element = $(element); - var id = element.readAttribute('id'), self = arguments.callee; - if (id) return id; - do { id = 'anonymous_element_' + self.counter++ } while ($(id)); - element.writeAttribute('id', id); - return id; - }, - - readAttribute: function(element, name) { - element = $(element); - if (Prototype.Browser.IE) { - var t = Element._attributeTranslations.read; - if (t.values[name]) return t.values[name](element, name); - if (t.names[name]) name = t.names[name]; - if (name.include(':')) { - return (!element.attributes || !element.attributes[name]) ? null : - element.attributes[name].value; - } - } - return element.getAttribute(name); - }, - - writeAttribute: function(element, name, value) { - element = $(element); - var attributes = { }, t = Element._attributeTranslations.write; - - if (typeof name == 'object') attributes = name; - else attributes[name] = Object.isUndefined(value) ? true : value; - - for (var attr in attributes) { - name = t.names[attr] || attr; - value = attributes[attr]; - if (t.values[attr]) name = t.values[attr](element, value); - if (value === false || value === null) - element.removeAttribute(name); - else if (value === true) - element.setAttribute(name, name); - else element.setAttribute(name, value); - } - return element; - }, - - getHeight: function(element) { - return $(element).getDimensions().height; - }, - - getWidth: function(element) { - return $(element).getDimensions().width; - }, - - classNames: function(element) { - return new Element.ClassNames(element); - }, - - hasClassName: function(element, className) { - if (!(element = $(element))) return; - var elementClassName = element.className; - return (elementClassName.length > 0 && (elementClassName == className || - new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); - }, - - addClassName: function(element, className) { - if (!(element = $(element))) return; - if (!element.hasClassName(className)) - element.className += (element.className ? ' ' : '') + className; - return element; - }, - - removeClassName: function(element, className) { - if (!(element = $(element))) return; - element.className = element.className.replace( - new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); - return element; - }, - - toggleClassName: function(element, className) { - if (!(element = $(element))) return; - return element[element.hasClassName(className) ? - 'removeClassName' : 'addClassName'](className); - }, - - // removes whitespace-only text node children - cleanWhitespace: function(element) { - element = $(element); - var node = element.firstChild; - while (node) { - var nextNode = node.nextSibling; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - element.removeChild(node); - node = nextNode; - } - return element; - }, - - empty: function(element) { - return $(element).innerHTML.blank(); - }, - - descendantOf: function(element, ancestor) { - element = $(element), ancestor = $(ancestor); - var originalAncestor = ancestor; - - if (element.compareDocumentPosition) - return (element.compareDocumentPosition(ancestor) & 8) === 8; - - if (element.sourceIndex && !Prototype.Browser.Opera) { - var e = element.sourceIndex, a = ancestor.sourceIndex, - nextAncestor = ancestor.nextSibling; - if (!nextAncestor) { - do { ancestor = ancestor.parentNode; } - while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode); - } - if (nextAncestor && nextAncestor.sourceIndex) - return (e > a && e < nextAncestor.sourceIndex); - } - - while (element = element.parentNode) - if (element == originalAncestor) return true; - return false; - }, - - scrollTo: function(element) { - element = $(element); - var pos = element.cumulativeOffset(); - window.scrollTo(pos[0], pos[1]); - return element; - }, - - getStyle: function(element, style) { - element = $(element); - style = style == 'float' ? 'cssFloat' : style.camelize(); - var value = element.style[style]; - if (!value) { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css[style] : null; - } - if (style == 'opacity') return value ? parseFloat(value) : 1.0; - return value == 'auto' ? null : value; - }, - - getOpacity: function(element) { - return $(element).getStyle('opacity'); - }, - - setStyle: function(element, styles) { - element = $(element); - var elementStyle = element.style, match; - if (Object.isString(styles)) { - element.style.cssText += ';' + styles; - return styles.include('opacity') ? - element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; - } - for (var property in styles) - if (property == 'opacity') element.setOpacity(styles[property]); - else - elementStyle[(property == 'float' || property == 'cssFloat') ? - (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : - property] = styles[property]; - - return element; - }, - - setOpacity: function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - return element; - }, - - getDimensions: function(element) { - element = $(element); - var display = $(element).getStyle('display'); - if (display != 'none' && display != null) // Safari bug - return {width: element.offsetWidth, height: element.offsetHeight}; - - // All *Width and *Height properties give 0 on elements with display none, - // so enable the element temporarily - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - var originalDisplay = els.display; - els.visibility = 'hidden'; - els.position = 'absolute'; - els.display = 'block'; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = originalDisplay; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - - makePositioned: function(element) { - element = $(element); - var pos = Element.getStyle(element, 'position'); - if (pos == 'static' || !pos) { - element._madePositioned = true; - element.style.position = 'relative'; - // Opera returns the offset relative to the positioning context, when an - // element is position relative but top and left have not been defined - if (window.opera) { - element.style.top = 0; - element.style.left = 0; - } - } - return element; - }, - - undoPositioned: function(element) { - element = $(element); - if (element._madePositioned) { - element._madePositioned = undefined; - element.style.position = - element.style.top = - element.style.left = - element.style.bottom = - element.style.right = ''; - } - return element; - }, - - makeClipping: function(element) { - element = $(element); - if (element._overflow) return element; - element._overflow = Element.getStyle(element, 'overflow') || 'auto'; - if (element._overflow !== 'hidden') - element.style.overflow = 'hidden'; - return element; - }, - - undoClipping: function(element) { - element = $(element); - if (!element._overflow) return element; - element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; - element._overflow = null; - return element; - }, - - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - if (element.tagName == 'BODY') break; - var p = Element.getStyle(element, 'position'); - if (p !== 'static') break; - } - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - absolutize: function(element) { - element = $(element); - if (element.getStyle('position') == 'absolute') return; - // Position.prepare(); // To be done manually by Scripty when it needs it. - - var offsets = element.positionedOffset(); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.width = width + 'px'; - element.style.height = height + 'px'; - return element; - }, - - relativize: function(element) { - element = $(element); - if (element.getStyle('position') == 'relative') return; - // Position.prepare(); // To be done manually by Scripty when it needs it. - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - return element; - }, - - cumulativeScrollOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - getOffsetParent: function(element) { - if (element.offsetParent) return $(element.offsetParent); - if (element == document.body) return $(element); - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return $(element); - - return $(document.body); - }, - - viewportOffset: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - // Safari fix - if (element.offsetParent == document.body && - Element.getStyle(element, 'position') == 'absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - if (!Prototype.Browser.Opera || element.tagName == 'BODY') { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } - } while (element = element.parentNode); - - return Element._returnOffset(valueL, valueT); - }, - - clonePosition: function(element, source) { - var options = Object.extend({ - setLeft: true, - setTop: true, - setWidth: true, - setHeight: true, - offsetTop: 0, - offsetLeft: 0 - }, arguments[2] || { }); - - // find page position of source - source = $(source); - var p = source.viewportOffset(); - - // find coordinate system to use - element = $(element); - var delta = [0, 0]; - var parent = null; - // delta [0,0] will do fine with position: fixed elements, - // position:absolute needs offsetParent deltas - if (Element.getStyle(element, 'position') == 'absolute') { - parent = element.getOffsetParent(); - delta = parent.viewportOffset(); - } - - // correct by body offsets (fixes Safari) - if (parent == document.body) { - delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; - } - - // set position - if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; - if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; - if (options.setWidth) element.style.width = source.offsetWidth + 'px'; - if (options.setHeight) element.style.height = source.offsetHeight + 'px'; - return element; - } -}; - -Element.Methods.identify.counter = 1; - -Object.extend(Element.Methods, { - getElementsBySelector: Element.Methods.select, - childElements: Element.Methods.immediateDescendants -}); - -Element._attributeTranslations = { - write: { - names: { - className: 'class', - htmlFor: 'for' - }, - values: { } - } -}; - -if (Prototype.Browser.Opera) { - Element.Methods.getStyle = Element.Methods.getStyle.wrap( - function(proceed, element, style) { - switch (style) { - case 'left': case 'top': case 'right': case 'bottom': - if (proceed(element, 'position') === 'static') return null; - case 'height': case 'width': - // returns '0px' for hidden elements; we want it to return null - if (!Element.visible(element)) return null; - - // returns the border-box dimensions rather than the content-box - // dimensions, so we subtract padding and borders from the value - var dim = parseInt(proceed(element, style), 10); - - if (dim !== element['offset' + style.capitalize()]) - return dim + 'px'; - - var properties; - if (style === 'height') { - properties = ['border-top-width', 'padding-top', - 'padding-bottom', 'border-bottom-width']; - } - else { - properties = ['border-left-width', 'padding-left', - 'padding-right', 'border-right-width']; - } - return properties.inject(dim, function(memo, property) { - var val = proceed(element, property); - return val === null ? memo : memo - parseInt(val, 10); - }) + 'px'; - default: return proceed(element, style); - } - } - ); - - Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( - function(proceed, element, attribute) { - if (attribute === 'title') return element.title; - return proceed(element, attribute); - } - ); -} - -else if (Prototype.Browser.IE) { - // IE doesn't report offsets correctly for static elements, so we change them - // to "relative" to get the values, then change them back. - Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( - function(proceed, element) { - element = $(element); - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - - $w('positionedOffset viewportOffset').each(function(method) { - Element.Methods[method] = Element.Methods[method].wrap( - function(proceed, element) { - element = $(element); - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - // Trigger hasLayout on the offset parent so that IE6 reports - // accurate offsetTop and offsetLeft values for position: fixed. - var offsetParent = element.getOffsetParent(); - if (offsetParent && offsetParent.getStyle('position') === 'fixed') - offsetParent.setStyle({ zoom: 1 }); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - }); - - Element.Methods.getStyle = function(element, style) { - element = $(element); - style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); - var value = element.style[style]; - if (!value && element.currentStyle) value = element.currentStyle[style]; - - if (style == 'opacity') { - if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) - if (value[1]) return parseFloat(value[1]) / 100; - return 1.0; - } - - if (value == 'auto') { - if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) - return element['offset' + style.capitalize()] + 'px'; - return null; - } - return value; - }; - - Element.Methods.setOpacity = function(element, value) { - function stripAlpha(filter){ - return filter.replace(/alpha\([^\)]*\)/gi,''); - } - element = $(element); - var currentStyle = element.currentStyle; - if ((currentStyle && !currentStyle.hasLayout) || - (!currentStyle && element.style.zoom == 'normal')) - element.style.zoom = 1; - - var filter = element.getStyle('filter'), style = element.style; - if (value == 1 || value === '') { - (filter = stripAlpha(filter)) ? - style.filter = filter : style.removeAttribute('filter'); - return element; - } else if (value < 0.00001) value = 0; - style.filter = stripAlpha(filter) + - 'alpha(opacity=' + (value * 100) + ')'; - return element; - }; - - Element._attributeTranslations = { - read: { - names: { - 'class': 'className', - 'for': 'htmlFor' - }, - values: { - _getAttr: function(element, attribute) { - return element.getAttribute(attribute, 2); - }, - _getAttrNode: function(element, attribute) { - var node = element.getAttributeNode(attribute); - return node ? node.value : ""; - }, - _getEv: function(element, attribute) { - attribute = element.getAttribute(attribute); - return attribute ? attribute.toString().slice(23, -2) : null; - }, - _flag: function(element, attribute) { - return $(element).hasAttribute(attribute) ? attribute : null; - }, - style: function(element) { - return element.style.cssText.toLowerCase(); - }, - title: function(element) { - return element.title; - } - } - } - }; - - Element._attributeTranslations.write = { - names: Object.extend({ - cellpadding: 'cellPadding', - cellspacing: 'cellSpacing' - }, Element._attributeTranslations.read.names), - values: { - checked: function(element, value) { - element.checked = !!value; - }, - - style: function(element, value) { - element.style.cssText = value ? value : ''; - } - } - }; - - Element._attributeTranslations.has = {}; - - $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + - 'encType maxLength readOnly longDesc').each(function(attr) { - Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; - Element._attributeTranslations.has[attr.toLowerCase()] = attr; - }); - - (function(v) { - Object.extend(v, { - href: v._getAttr, - src: v._getAttr, - type: v._getAttr, - action: v._getAttrNode, - disabled: v._flag, - checked: v._flag, - readonly: v._flag, - multiple: v._flag, - onload: v._getEv, - onunload: v._getEv, - onclick: v._getEv, - ondblclick: v._getEv, - onmousedown: v._getEv, - onmouseup: v._getEv, - onmouseover: v._getEv, - onmousemove: v._getEv, - onmouseout: v._getEv, - onfocus: v._getEv, - onblur: v._getEv, - onkeypress: v._getEv, - onkeydown: v._getEv, - onkeyup: v._getEv, - onsubmit: v._getEv, - onreset: v._getEv, - onselect: v._getEv, - onchange: v._getEv - }); - })(Element._attributeTranslations.read.values); -} - -else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1) ? 0.999999 : - (value === '') ? '' : (value < 0.00001) ? 0 : value; - return element; - }; -} - -else if (Prototype.Browser.WebKit) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - - if (value == 1) - if(element.tagName == 'IMG' && element.width) { - element.width++; element.width--; - } else try { - var n = document.createTextNode(' '); - element.appendChild(n); - element.removeChild(n); - } catch (e) { } - - return element; - }; - - // Safari returns margins on body which is incorrect if the child is absolutely - // positioned. For performance reasons, redefine Element#cumulativeOffset for - // KHTML/WebKit only. - Element.Methods.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return Element._returnOffset(valueL, valueT); - }; -} - -if (Prototype.Browser.IE || Prototype.Browser.Opera) { - // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements - Element.Methods.update = function(element, content) { - element = $(element); - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) return element.update().insert(content); - - content = Object.toHTML(content); - var tagName = element.tagName.toUpperCase(); - - if (tagName in Element._insertionTranslations.tags) { - $A(element.childNodes).each(function(node) { element.removeChild(node) }); - Element._getContentFromAnonymousElement(tagName, content.stripScripts()) - .each(function(node) { element.appendChild(node) }); - } - else element.innerHTML = content.stripScripts(); - - content.evalScripts.bind(content).defer(); - return element; - }; -} - -if ('outerHTML' in document.createElement('div')) { - Element.Methods.replace = function(element, content) { - element = $(element); - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - element.parentNode.replaceChild(content, element); - return element; - } - - content = Object.toHTML(content); - var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); - - if (Element._insertionTranslations.tags[tagName]) { - var nextSibling = element.next(); - var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - parent.removeChild(element); - if (nextSibling) - fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); - else - fragments.each(function(node) { parent.appendChild(node) }); - } - else element.outerHTML = content.stripScripts(); - - content.evalScripts.bind(content).defer(); - return element; - }; -} - -Element._returnOffset = function(l, t) { - var result = [l, t]; - result.left = l; - result.top = t; - return result; -}; - -Element._getContentFromAnonymousElement = function(tagName, html) { - var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; - if (t) { - div.innerHTML = t[0] + html + t[1]; - t[2].times(function() { div = div.firstChild }); - } else div.innerHTML = html; - return $A(div.childNodes); -}; - -Element._insertionTranslations = { - before: function(element, node) { - element.parentNode.insertBefore(node, element); - }, - top: function(element, node) { - element.insertBefore(node, element.firstChild); - }, - bottom: function(element, node) { - element.appendChild(node); - }, - after: function(element, node) { - element.parentNode.insertBefore(node, element.nextSibling); - }, - tags: { - TABLE: ['', '
', 1], - TBODY: ['', '
', 2], - TR: ['', '
', 3], - TD: ['
', '
', 4], - SELECT: ['', 1] - } -}; - -(function() { - Object.extend(this.tags, { - THEAD: this.tags.TBODY, - TFOOT: this.tags.TBODY, - TH: this.tags.TD - }); -}).call(Element._insertionTranslations); - -Element.Methods.Simulated = { - hasAttribute: function(element, attribute) { - attribute = Element._attributeTranslations.has[attribute] || attribute; - var node = $(element).getAttributeNode(attribute); - return node && node.specified; - } -}; - -Element.Methods.ByTag = { }; - -Object.extend(Element, Element.Methods); - -if (!Prototype.BrowserFeatures.ElementExtensions && - document.createElement('div').__proto__) { - window.HTMLElement = { }; - window.HTMLElement.prototype = document.createElement('div').__proto__; - Prototype.BrowserFeatures.ElementExtensions = true; -} - -Element.extend = (function() { - if (Prototype.BrowserFeatures.SpecificElementExtensions) - return Prototype.K; - - var Methods = { }, ByTag = Element.Methods.ByTag; - - var extend = Object.extend(function(element) { - if (!element || element._extendedByPrototype || - element.nodeType != 1 || element == window) return element; - - var methods = Object.clone(Methods), - tagName = element.tagName, property, value; - - // extend methods for specific tags - if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); - - for (property in methods) { - value = methods[property]; - if (Object.isFunction(value) && !(property in element)) - element[property] = value.methodize(); - } - - element._extendedByPrototype = Prototype.emptyFunction; - return element; - - }, { - refresh: function() { - // extend methods for all tags (Safari doesn't need this) - if (!Prototype.BrowserFeatures.ElementExtensions) { - Object.extend(Methods, Element.Methods); - Object.extend(Methods, Element.Methods.Simulated); - } - } - }); - - extend.refresh(); - return extend; -})(); - -Element.hasAttribute = function(element, attribute) { - if (element.hasAttribute) return element.hasAttribute(attribute); - return Element.Methods.Simulated.hasAttribute(element, attribute); -}; - -Element.addMethods = function(methods) { - var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; - - if (!methods) { - Object.extend(Form, Form.Methods); - Object.extend(Form.Element, Form.Element.Methods); - Object.extend(Element.Methods.ByTag, { - "FORM": Object.clone(Form.Methods), - "INPUT": Object.clone(Form.Element.Methods), - "SELECT": Object.clone(Form.Element.Methods), - "TEXTAREA": Object.clone(Form.Element.Methods) - }); - } - - if (arguments.length == 2) { - var tagName = methods; - methods = arguments[1]; - } - - if (!tagName) Object.extend(Element.Methods, methods || { }); - else { - if (Object.isArray(tagName)) tagName.each(extend); - else extend(tagName); - } - - function extend(tagName) { - tagName = tagName.toUpperCase(); - if (!Element.Methods.ByTag[tagName]) - Element.Methods.ByTag[tagName] = { }; - Object.extend(Element.Methods.ByTag[tagName], methods); - } - - function copy(methods, destination, onlyIfAbsent) { - onlyIfAbsent = onlyIfAbsent || false; - for (var property in methods) { - var value = methods[property]; - if (!Object.isFunction(value)) continue; - if (!onlyIfAbsent || !(property in destination)) - destination[property] = value.methodize(); - } - } - - function findDOMClass(tagName) { - var klass; - var trans = { - "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", - "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", - "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", - "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", - "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": - "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": - "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": - "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": - "FrameSet", "IFRAME": "IFrame" - }; - if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName.capitalize() + 'Element'; - if (window[klass]) return window[klass]; - - window[klass] = { }; - window[klass].prototype = document.createElement(tagName).__proto__; - return window[klass]; - } - - if (F.ElementExtensions) { - copy(Element.Methods, HTMLElement.prototype); - copy(Element.Methods.Simulated, HTMLElement.prototype, true); - } - - if (F.SpecificElementExtensions) { - for (var tag in Element.Methods.ByTag) { - var klass = findDOMClass(tag); - if (Object.isUndefined(klass)) continue; - copy(T[tag], klass.prototype); - } - } - - Object.extend(Element, Element.Methods); - delete Element.ByTag; - - if (Element.extend.refresh) Element.extend.refresh(); - Element.cache = { }; -}; - -document.viewport = { - getDimensions: function() { - var dimensions = { }; - var B = Prototype.Browser; - $w('width height').each(function(d) { - var D = d.capitalize(); - dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] : - (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D]; - }); - return dimensions; - }, - - getWidth: function() { - return this.getDimensions().width; - }, - - getHeight: function() { - return this.getDimensions().height; - }, - - getScrollOffsets: function() { - return Element._returnOffset( - window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, - window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); - } -}; -/* Portions of the Selector class are derived from Jack Slocum’s DomQuery, - * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style - * license. Please see http://www.yui-ext.com/ for more information. */ - -var Selector = Class.create({ - initialize: function(expression) { - this.expression = expression.strip(); - this.compileMatcher(); - }, - - shouldUseXPath: function() { - if (!Prototype.BrowserFeatures.XPath) return false; - - var e = this.expression; - - // Safari 3 chokes on :*-of-type and :empty - if (Prototype.Browser.WebKit && - (e.include("-of-type") || e.include(":empty"))) - return false; - - // XPath can't do namespaced attributes, nor can it read - // the "checked" property from DOM nodes - if ((/(\[[\w-]*?:|:checked)/).test(this.expression)) - return false; - - return true; - }, - - compileMatcher: function() { - if (this.shouldUseXPath()) - return this.compileXPathMatcher(); - - var e = this.expression, ps = Selector.patterns, h = Selector.handlers, - c = Selector.criteria, le, p, m; - - if (Selector._cache[e]) { - this.matcher = Selector._cache[e]; - return; - } - - this.matcher = ["this.matcher = function(root) {", - "var r = root, h = Selector.handlers, c = false, n;"]; - - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - p = ps[i]; - if (m = e.match(p)) { - this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : - new Template(c[i]).evaluate(m)); - e = e.replace(m[0], ''); - break; - } - } - } - - this.matcher.push("return h.unique(n);\n}"); - eval(this.matcher.join('\n')); - Selector._cache[this.expression] = this.matcher; - }, - - compileXPathMatcher: function() { - var e = this.expression, ps = Selector.patterns, - x = Selector.xpath, le, m; - - if (Selector._cache[e]) { - this.xpath = Selector._cache[e]; return; - } - - this.matcher = ['.//*']; - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - if (m = e.match(ps[i])) { - this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : - new Template(x[i]).evaluate(m)); - e = e.replace(m[0], ''); - break; - } - } - } - - this.xpath = this.matcher.join(''); - Selector._cache[this.expression] = this.xpath; - }, - - findElements: function(root) { - root = root || document; - if (this.xpath) return document._getElementsByXPath(this.xpath, root); - return this.matcher(root); - }, - - match: function(element) { - this.tokens = []; - - var e = this.expression, ps = Selector.patterns, as = Selector.assertions; - var le, p, m; - - while (e && le !== e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - p = ps[i]; - if (m = e.match(p)) { - // use the Selector.assertions methods unless the selector - // is too complex. - if (as[i]) { - this.tokens.push([i, Object.clone(m)]); - e = e.replace(m[0], ''); - } else { - // reluctantly do a document-wide search - // and look for a match in the array - return this.findElements(document).include(element); - } - } - } - } - - var match = true, name, matches; - for (var i = 0, token; token = this.tokens[i]; i++) { - name = token[0], matches = token[1]; - if (!Selector.assertions[name](element, matches)) { - match = false; break; - } - } - - return match; - }, - - toString: function() { - return this.expression; - }, - - inspect: function() { - return "#"; - } -}); - -Object.extend(Selector, { - _cache: { }, - - xpath: { - descendant: "//*", - child: "/*", - adjacent: "/following-sibling::*[1]", - laterSibling: '/following-sibling::*', - tagName: function(m) { - if (m[1] == '*') return ''; - return "[local-name()='" + m[1].toLowerCase() + - "' or local-name()='" + m[1].toUpperCase() + "']"; - }, - className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", - id: "[@id='#{1}']", - attrPresence: function(m) { - m[1] = m[1].toLowerCase(); - return new Template("[@#{1}]").evaluate(m); - }, - attr: function(m) { - m[1] = m[1].toLowerCase(); - m[3] = m[5] || m[6]; - return new Template(Selector.xpath.operators[m[2]]).evaluate(m); - }, - pseudo: function(m) { - var h = Selector.xpath.pseudos[m[1]]; - if (!h) return ''; - if (Object.isFunction(h)) return h(m); - return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); - }, - operators: { - '=': "[@#{1}='#{3}']", - '!=': "[@#{1}!='#{3}']", - '^=': "[starts-with(@#{1}, '#{3}')]", - '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", - '*=': "[contains(@#{1}, '#{3}')]", - '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", - '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" - }, - pseudos: { - 'first-child': '[not(preceding-sibling::*)]', - 'last-child': '[not(following-sibling::*)]', - 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', - 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", - 'checked': "[@checked]", - 'disabled': "[@disabled]", - 'enabled': "[not(@disabled)]", - 'not': function(m) { - var e = m[6], p = Selector.patterns, - x = Selector.xpath, le, v; - - var exclusion = []; - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in p) { - if (m = e.match(p[i])) { - v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); - exclusion.push("(" + v.substring(1, v.length - 1) + ")"); - e = e.replace(m[0], ''); - break; - } - } - } - return "[not(" + exclusion.join(" and ") + ")]"; - }, - 'nth-child': function(m) { - return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); - }, - 'nth-last-child': function(m) { - return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); - }, - 'nth-of-type': function(m) { - return Selector.xpath.pseudos.nth("position() ", m); - }, - 'nth-last-of-type': function(m) { - return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); - }, - 'first-of-type': function(m) { - m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); - }, - 'last-of-type': function(m) { - m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); - }, - 'only-of-type': function(m) { - var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); - }, - nth: function(fragment, m) { - var mm, formula = m[6], predicate; - if (formula == 'even') formula = '2n+0'; - if (formula == 'odd') formula = '2n+1'; - if (mm = formula.match(/^(\d+)$/)) // digit only - return '[' + fragment + "= " + mm[1] + ']'; - if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b - if (mm[1] == "-") mm[1] = -1; - var a = mm[1] ? Number(mm[1]) : 1; - var b = mm[2] ? Number(mm[2]) : 0; - predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + - "((#{fragment} - #{b}) div #{a} >= 0)]"; - return new Template(predicate).evaluate({ - fragment: fragment, a: a, b: b }); - } - } - } - }, - - criteria: { - tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', - className: 'n = h.className(n, r, "#{1}", c); c = false;', - id: 'n = h.id(n, r, "#{1}", c); c = false;', - attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', - attr: function(m) { - m[3] = (m[5] || m[6]); - return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); - }, - pseudo: function(m) { - if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); - return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); - }, - descendant: 'c = "descendant";', - child: 'c = "child";', - adjacent: 'c = "adjacent";', - laterSibling: 'c = "laterSibling";' - }, - - patterns: { - // combinators must be listed first - // (and descendant needs to be last combinator) - laterSibling: /^\s*~\s*/, - child: /^\s*>\s*/, - adjacent: /^\s*\+\s*/, - descendant: /^\s/, - - // selectors follow - tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, - id: /^#([\w\-\*]+)(\b|$)/, - className: /^\.([\w\-\*]+)(\b|$)/, - pseudo: -/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, - attrPresence: /^\[([\w]+)\]/, - attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ - }, - - // for Selector.match and Element#match - assertions: { - tagName: function(element, matches) { - return matches[1].toUpperCase() == element.tagName.toUpperCase(); - }, - - className: function(element, matches) { - return Element.hasClassName(element, matches[1]); - }, - - id: function(element, matches) { - return element.id === matches[1]; - }, - - attrPresence: function(element, matches) { - return Element.hasAttribute(element, matches[1]); - }, - - attr: function(element, matches) { - var nodeValue = Element.readAttribute(element, matches[1]); - return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); - } - }, - - handlers: { - // UTILITY FUNCTIONS - // joins two collections - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - a.push(node); - return a; - }, - - // marks an array of nodes for counting - mark: function(nodes) { - var _true = Prototype.emptyFunction; - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = _true; - return nodes; - }, - - unmark: function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = undefined; - return nodes; - }, - - // mark each child node with its position (for nth calls) - // "ofType" flag indicates whether we're indexing for nth-of-type - // rather than nth-child - index: function(parentNode, reverse, ofType) { - parentNode._countedByPrototype = Prototype.emptyFunction; - if (reverse) { - for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { - var node = nodes[i]; - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - } else { - for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - }, - - // filters out duplicates and extends all nodes - unique: function(nodes) { - if (nodes.length == 0) return nodes; - var results = [], n; - for (var i = 0, l = nodes.length; i < l; i++) - if (!(n = nodes[i])._countedByPrototype) { - n._countedByPrototype = Prototype.emptyFunction; - results.push(Element.extend(n)); - } - return Selector.handlers.unmark(results); - }, - - // COMBINATOR FUNCTIONS - descendant: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName('*')); - return results; - }, - - child: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) { - for (var j = 0, child; child = node.childNodes[j]; j++) - if (child.nodeType == 1 && child.tagName != '!') results.push(child); - } - return results; - }, - - adjacent: function(nodes) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - var next = this.nextElementSibling(node); - if (next) results.push(next); - } - return results; - }, - - laterSibling: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, Element.nextSiblings(node)); - return results; - }, - - nextElementSibling: function(node) { - while (node = node.nextSibling) - if (node.nodeType == 1) return node; - return null; - }, - - previousElementSibling: function(node) { - while (node = node.previousSibling) - if (node.nodeType == 1) return node; - return null; - }, - - // TOKEN FUNCTIONS - tagName: function(nodes, root, tagName, combinator) { - var uTagName = tagName.toUpperCase(); - var results = [], h = Selector.handlers; - if (nodes) { - if (combinator) { - // fastlane for ordinary descendant combinators - if (combinator == "descendant") { - for (var i = 0, node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName(tagName)); - return results; - } else nodes = this[combinator](nodes); - if (tagName == "*") return nodes; - } - for (var i = 0, node; node = nodes[i]; i++) - if (node.tagName.toUpperCase() === uTagName) results.push(node); - return results; - } else return root.getElementsByTagName(tagName); - }, - - id: function(nodes, root, id, combinator) { - var targetNode = $(id), h = Selector.handlers; - if (!targetNode) return []; - if (!nodes && root == document) return [targetNode]; - if (nodes) { - if (combinator) { - if (combinator == 'child') { - for (var i = 0, node; node = nodes[i]; i++) - if (targetNode.parentNode == node) return [targetNode]; - } else if (combinator == 'descendant') { - for (var i = 0, node; node = nodes[i]; i++) - if (Element.descendantOf(targetNode, node)) return [targetNode]; - } else if (combinator == 'adjacent') { - for (var i = 0, node; node = nodes[i]; i++) - if (Selector.handlers.previousElementSibling(targetNode) == node) - return [targetNode]; - } else nodes = h[combinator](nodes); - } - for (var i = 0, node; node = nodes[i]; i++) - if (node == targetNode) return [targetNode]; - return []; - } - return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; - }, - - className: function(nodes, root, className, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - return Selector.handlers.byClassName(nodes, root, className); - }, - - byClassName: function(nodes, root, className) { - if (!nodes) nodes = Selector.handlers.descendant([root]); - var needle = ' ' + className + ' '; - for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { - nodeClassName = node.className; - if (nodeClassName.length == 0) continue; - if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) - results.push(node); - } - return results; - }, - - attrPresence: function(nodes, root, attr, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var results = []; - for (var i = 0, node; node = nodes[i]; i++) - if (Element.hasAttribute(node, attr)) results.push(node); - return results; - }, - - attr: function(nodes, root, attr, value, operator, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var handler = Selector.operators[operator], results = []; - for (var i = 0, node; node = nodes[i]; i++) { - var nodeValue = Element.readAttribute(node, attr); - if (nodeValue === null) continue; - if (handler(nodeValue, value)) results.push(node); - } - return results; - }, - - pseudo: function(nodes, name, value, root, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - if (!nodes) nodes = root.getElementsByTagName("*"); - return Selector.pseudos[name](nodes, value, root); - } - }, - - pseudos: { - 'first-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.previousElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'last-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.nextElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'only-child': function(nodes, value, root) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) - results.push(node); - return results; - }, - 'nth-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root); - }, - 'nth-last-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true); - }, - 'nth-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, false, true); - }, - 'nth-last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true, true); - }, - 'first-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, false, true); - }, - 'last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, true, true); - }, - 'only-of-type': function(nodes, formula, root) { - var p = Selector.pseudos; - return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); - }, - - // handles the an+b logic - getIndices: function(a, b, total) { - if (a == 0) return b > 0 ? [b] : []; - return $R(1, total).inject([], function(memo, i) { - if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); - return memo; - }); - }, - - // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type - nth: function(nodes, formula, root, reverse, ofType) { - if (nodes.length == 0) return []; - if (formula == 'even') formula = '2n+0'; - if (formula == 'odd') formula = '2n+1'; - var h = Selector.handlers, results = [], indexed = [], m; - h.mark(nodes); - for (var i = 0, node; node = nodes[i]; i++) { - if (!node.parentNode._countedByPrototype) { - h.index(node.parentNode, reverse, ofType); - indexed.push(node.parentNode); - } - } - if (formula.match(/^\d+$/)) { // just a number - formula = Number(formula); - for (var i = 0, node; node = nodes[i]; i++) - if (node.nodeIndex == formula) results.push(node); - } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b - if (m[1] == "-") m[1] = -1; - var a = m[1] ? Number(m[1]) : 1; - var b = m[2] ? Number(m[2]) : 0; - var indices = Selector.pseudos.getIndices(a, b, nodes.length); - for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { - for (var j = 0; j < l; j++) - if (node.nodeIndex == indices[j]) results.push(node); - } - } - h.unmark(nodes); - h.unmark(indexed); - return results; - }, - - 'empty': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - // IE treats comments as element nodes - if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; - results.push(node); - } - return results; - }, - - 'not': function(nodes, selector, root) { - var h = Selector.handlers, selectorType, m; - var exclusions = new Selector(selector).findElements(root); - h.mark(exclusions); - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node._countedByPrototype) results.push(node); - h.unmark(exclusions); - return results; - }, - - 'enabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node.disabled) results.push(node); - return results; - }, - - 'disabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.disabled) results.push(node); - return results; - }, - - 'checked': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.checked) results.push(node); - return results; - } - }, - - operators: { - '=': function(nv, v) { return nv == v; }, - '!=': function(nv, v) { return nv != v; }, - '^=': function(nv, v) { return nv.startsWith(v); }, - '$=': function(nv, v) { return nv.endsWith(v); }, - '*=': function(nv, v) { return nv.include(v); }, - '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, - '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); } - }, - - split: function(expression) { - var expressions = []; - expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { - expressions.push(m[1].strip()); - }); - return expressions; - }, - - matchElements: function(elements, expression) { - var matches = $$(expression), h = Selector.handlers; - h.mark(matches); - for (var i = 0, results = [], element; element = elements[i]; i++) - if (element._countedByPrototype) results.push(element); - h.unmark(matches); - return results; - }, - - findElement: function(elements, expression, index) { - if (Object.isNumber(expression)) { - index = expression; expression = false; - } - return Selector.matchElements(elements, expression || '*')[index || 0]; - }, - - findChildElements: function(element, expressions) { - expressions = Selector.split(expressions.join(',')); - var results = [], h = Selector.handlers; - for (var i = 0, l = expressions.length, selector; i < l; i++) { - selector = new Selector(expressions[i].strip()); - h.concat(results, selector.findElements(element)); - } - return (l > 1) ? h.unique(results) : results; - } -}); - -if (Prototype.Browser.IE) { - Object.extend(Selector.handlers, { - // IE returns comment nodes on getElementsByTagName("*"). - // Filter them out. - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - if (node.tagName !== "!") a.push(node); - return a; - }, - - // IE improperly serializes _countedByPrototype in (inner|outer)HTML. - unmark: function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node.removeAttribute('_countedByPrototype'); - return nodes; - } - }); -} - -function $$() { - return Selector.findChildElements(document, $A(arguments)); -} -var Form = { - reset: function(form) { - $(form).reset(); - return form; - }, - - serializeElements: function(elements, options) { - if (typeof options != 'object') options = { hash: !!options }; - else if (Object.isUndefined(options.hash)) options.hash = true; - var key, value, submitted = false, submit = options.submit; - - var data = elements.inject({ }, function(result, element) { - if (!element.disabled && element.name) { - key = element.name; value = $(element).getValue(); - if (value != null && (element.type != 'submit' || (!submitted && - submit !== false && (!submit || key == submit) && (submitted = true)))) { - if (key in result) { - // a key is already present; construct an array of values - if (!Object.isArray(result[key])) result[key] = [result[key]]; - result[key].push(value); - } - else result[key] = value; - } - } - return result; - }); - - return options.hash ? data : Object.toQueryString(data); - } -}; - -Form.Methods = { - serialize: function(form, options) { - return Form.serializeElements(Form.getElements(form), options); - }, - - getElements: function(form) { - return $A($(form).getElementsByTagName('*')).inject([], - function(elements, child) { - if (Form.Element.Serializers[child.tagName.toLowerCase()]) - elements.push(Element.extend(child)); - return elements; - } - ); - }, - - getInputs: function(form, typeName, name) { - form = $(form); - var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) return $A(inputs).map(Element.extend); - - for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { - var input = inputs[i]; - if ((typeName && input.type != typeName) || (name && input.name != name)) - continue; - matchingInputs.push(Element.extend(input)); - } - - return matchingInputs; - }, - - disable: function(form) { - form = $(form); - Form.getElements(form).invoke('disable'); - return form; - }, - - enable: function(form) { - form = $(form); - Form.getElements(form).invoke('enable'); - return form; - }, - - findFirstElement: function(form) { - var elements = $(form).getElements().findAll(function(element) { - return 'hidden' != element.type && !element.disabled; - }); - var firstByIndex = elements.findAll(function(element) { - return element.hasAttribute('tabIndex') && element.tabIndex >= 0; - }).sortBy(function(element) { return element.tabIndex }).first(); - - return firstByIndex ? firstByIndex : elements.find(function(element) { - return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); - }); - }, - - focusFirstElement: function(form) { - form = $(form); - form.findFirstElement().activate(); - return form; - }, - - request: function(form, options) { - form = $(form), options = Object.clone(options || { }); - - var params = options.parameters, action = form.readAttribute('action') || ''; - if (action.blank()) action = window.location.href; - options.parameters = form.serialize(true); - - if (params) { - if (Object.isString(params)) params = params.toQueryParams(); - Object.extend(options.parameters, params); - } - - if (form.hasAttribute('method') && !options.method) - options.method = form.method; - - return new Ajax.Request(action, options); - } -}; - -/*--------------------------------------------------------------------------*/ - -Form.Element = { - focus: function(element) { - $(element).focus(); - return element; - }, - - select: function(element) { - $(element).select(); - return element; - } -}; - -Form.Element.Methods = { - serialize: function(element) { - element = $(element); - if (!element.disabled && element.name) { - var value = element.getValue(); - if (value != undefined) { - var pair = { }; - pair[element.name] = value; - return Object.toQueryString(pair); - } - } - return ''; - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - return Form.Element.Serializers[method](element); - }, - - setValue: function(element, value) { - element = $(element); - var method = element.tagName.toLowerCase(); - Form.Element.Serializers[method](element, value); - return element; - }, - - clear: function(element) { - $(element).value = ''; - return element; - }, - - present: function(element) { - return $(element).value != ''; - }, - - activate: function(element) { - element = $(element); - try { - element.focus(); - if (element.select && (element.tagName.toLowerCase() != 'input' || - !['button', 'reset', 'submit'].include(element.type))) - element.select(); - } catch (e) { } - return element; - }, - - disable: function(element) { - element = $(element); - element.blur(); - element.disabled = true; - return element; - }, - - enable: function(element) { - element = $(element); - element.disabled = false; - return element; - } -}; - -/*--------------------------------------------------------------------------*/ - -var Field = Form.Element; -var $F = Form.Element.Methods.getValue; - -/*--------------------------------------------------------------------------*/ - -Form.Element.Serializers = { - input: function(element, value) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element, value); - default: - return Form.Element.Serializers.textarea(element, value); - } - }, - - inputSelector: function(element, value) { - if (Object.isUndefined(value)) return element.checked ? element.value : null; - else element.checked = !!value; - }, - - textarea: function(element, value) { - if (Object.isUndefined(value)) return element.value; - else element.value = value; - }, - - select: function(element, index) { - if (Object.isUndefined(index)) - return this[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - else { - var opt, value, single = !Object.isArray(index); - for (var i = 0, length = element.length; i < length; i++) { - opt = element.options[i]; - value = this.optionValue(opt); - if (single) { - if (value == index) { - opt.selected = true; - return; - } - } - else opt.selected = index.include(value); - } - } - }, - - selectOne: function(element) { - var index = element.selectedIndex; - return index >= 0 ? this.optionValue(element.options[index]) : null; - }, - - selectMany: function(element) { - var values, length = element.length; - if (!length) return null; - - for (var i = 0, values = []; i < length; i++) { - var opt = element.options[i]; - if (opt.selected) values.push(this.optionValue(opt)); - } - return values; - }, - - optionValue: function(opt) { - // extend element because hasAttribute may not be native - return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; - } -}; - -/*--------------------------------------------------------------------------*/ - -Abstract.TimedObserver = Class.create(PeriodicalExecuter, { - initialize: function($super, element, frequency, callback) { - $super(callback, frequency); - this.element = $(element); - this.lastValue = this.getValue(); - }, - - execute: function() { - var value = this.getValue(); - if (Object.isString(this.lastValue) && Object.isString(value) ? - this.lastValue != value : String(this.lastValue) != String(value)) { - this.callback(this.element, value); - this.lastValue = value; - } - } -}); - -Form.Element.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); - -/*--------------------------------------------------------------------------*/ - -Abstract.EventObserver = Class.create({ - initialize: function(element, callback) { - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - if (this.element.tagName.toLowerCase() == 'form') - this.registerFormCallbacks(); - else - this.registerCallback(this.element); - }, - - onElementEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - }, - - registerFormCallbacks: function() { - Form.getElements(this.element).each(this.registerCallback, this); - }, - - registerCallback: function(element) { - if (element.type) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - Event.observe(element, 'click', this.onElementEvent.bind(this)); - break; - default: - Event.observe(element, 'change', this.onElementEvent.bind(this)); - break; - } - } - } -}); - -Form.Element.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); -if (!window.Event) var Event = { }; - -Object.extend(Event, { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - KEY_HOME: 36, - KEY_END: 35, - KEY_PAGEUP: 33, - KEY_PAGEDOWN: 34, - KEY_INSERT: 45, - - cache: { }, - - relatedTarget: function(event) { - var element; - switch(event.type) { - case 'mouseover': element = event.fromElement; break; - case 'mouseout': element = event.toElement; break; - default: return null; - } - return Element.extend(element); - } -}); - -Event.Methods = (function() { - var isButton; - - if (Prototype.Browser.IE) { - var buttonMap = { 0: 1, 1: 4, 2: 2 }; - isButton = function(event, code) { - return event.button == buttonMap[code]; - }; - - } else if (Prototype.Browser.WebKit) { - isButton = function(event, code) { - switch (code) { - case 0: return event.which == 1 && !event.metaKey; - case 1: return event.which == 1 && event.metaKey; - default: return false; - } - }; - - } else { - isButton = function(event, code) { - return event.which ? (event.which === code + 1) : (event.button === code); - }; - } - - return { - isLeftClick: function(event) { return isButton(event, 0) }, - isMiddleClick: function(event) { return isButton(event, 1) }, - isRightClick: function(event) { return isButton(event, 2) }, - - element: function(event) { - var node = Event.extend(event).target; - return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node); - }, - - findElement: function(event, expression) { - var element = Event.element(event); - if (!expression) return element; - var elements = [element].concat(element.ancestors()); - return Selector.findElement(elements, expression, 0); - }, - - pointer: function(event) { - return { - x: event.pageX || (event.clientX + - (document.documentElement.scrollLeft || document.body.scrollLeft)), - y: event.pageY || (event.clientY + - (document.documentElement.scrollTop || document.body.scrollTop)) - }; - }, - - pointerX: function(event) { return Event.pointer(event).x }, - pointerY: function(event) { return Event.pointer(event).y }, - - stop: function(event) { - Event.extend(event); - event.preventDefault(); - event.stopPropagation(); - event.stopped = true; - } - }; -})(); - -Event.extend = (function() { - var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { - m[name] = Event.Methods[name].methodize(); - return m; - }); - - if (Prototype.Browser.IE) { - Object.extend(methods, { - stopPropagation: function() { this.cancelBubble = true }, - preventDefault: function() { this.returnValue = false }, - inspect: function() { return "[object Event]" } - }); - - return function(event) { - if (!event) return false; - if (event._extendedByPrototype) return event; - - event._extendedByPrototype = Prototype.emptyFunction; - var pointer = Event.pointer(event); - Object.extend(event, { - target: event.srcElement, - relatedTarget: Event.relatedTarget(event), - pageX: pointer.x, - pageY: pointer.y - }); - return Object.extend(event, methods); - }; - - } else { - Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__; - Object.extend(Event.prototype, methods); - return Prototype.K; - } -})(); - -Object.extend(Event, (function() { - var cache = Event.cache; - - function getEventID(element) { - if (element._prototypeEventID) return element._prototypeEventID[0]; - arguments.callee.id = arguments.callee.id || 1; - return element._prototypeEventID = [++arguments.callee.id]; - } - - function getDOMEventName(eventName) { - if (eventName && eventName.include(':')) return "dataavailable"; - return eventName; - } - - function getCacheForID(id) { - return cache[id] = cache[id] || { }; - } - - function getWrappersForEventName(id, eventName) { - var c = getCacheForID(id); - return c[eventName] = c[eventName] || []; - } - - function createWrapper(element, eventName, handler) { - var id = getEventID(element); - var c = getWrappersForEventName(id, eventName); - if (c.pluck("handler").include(handler)) return false; - - var wrapper = function(event) { - if (!Event || !Event.extend || - (event.eventName && event.eventName != eventName)) - return false; - - Event.extend(event); - handler.call(element, event); - }; - - wrapper.handler = handler; - c.push(wrapper); - return wrapper; - } - - function findWrapper(id, eventName, handler) { - var c = getWrappersForEventName(id, eventName); - return c.find(function(wrapper) { return wrapper.handler == handler }); - } - - function destroyWrapper(id, eventName, handler) { - var c = getCacheForID(id); - if (!c[eventName]) return false; - c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); - } - - function destroyCache() { - for (var id in cache) - for (var eventName in cache[id]) - cache[id][eventName] = null; - } - - if (window.attachEvent) { - window.attachEvent("onunload", destroyCache); - } - - return { - observe: function(element, eventName, handler) { - element = $(element); - var name = getDOMEventName(eventName); - - var wrapper = createWrapper(element, eventName, handler); - if (!wrapper) return element; - - if (element.addEventListener) { - element.addEventListener(name, wrapper, false); - } else { - element.attachEvent("on" + name, wrapper); - } - - return element; - }, - - stopObserving: function(element, eventName, handler) { - element = $(element); - var id = getEventID(element), name = getDOMEventName(eventName); - - if (!handler && eventName) { - getWrappersForEventName(id, eventName).each(function(wrapper) { - element.stopObserving(eventName, wrapper.handler); - }); - return element; - - } else if (!eventName) { - Object.keys(getCacheForID(id)).each(function(eventName) { - element.stopObserving(eventName); - }); - return element; - } - - var wrapper = findWrapper(id, eventName, handler); - if (!wrapper) return element; - - if (element.removeEventListener) { - element.removeEventListener(name, wrapper, false); - } else { - element.detachEvent("on" + name, wrapper); - } - - destroyWrapper(id, eventName, handler); - - return element; - }, - - fire: function(element, eventName, memo) { - element = $(element); - if (element == document && document.createEvent && !element.dispatchEvent) - element = document.documentElement; - - var event; - if (document.createEvent) { - event = document.createEvent("HTMLEvents"); - event.initEvent("dataavailable", true, true); - } else { - event = document.createEventObject(); - event.eventType = "ondataavailable"; - } - - event.eventName = eventName; - event.memo = memo || { }; - - if (document.createEvent) { - element.dispatchEvent(event); - } else { - element.fireEvent(event.eventType, event); - } - - return Event.extend(event); - } - }; -})()); - -Object.extend(Event, Event.Methods); - -Element.addMethods({ - fire: Event.fire, - observe: Event.observe, - stopObserving: Event.stopObserving -}); - -Object.extend(document, { - fire: Element.Methods.fire.methodize(), - observe: Element.Methods.observe.methodize(), - stopObserving: Element.Methods.stopObserving.methodize(), - loaded: false -}); - -(function() { - /* Support for the DOMContentLoaded event is based on work by Dan Webb, - Matthias Miller, Dean Edwards and John Resig. */ - - var timer; - - function fireContentLoadedEvent() { - if (document.loaded) return; - if (timer) window.clearInterval(timer); - document.fire("dom:loaded"); - document.loaded = true; - } - - if (document.addEventListener) { - if (Prototype.Browser.WebKit) { - timer = window.setInterval(function() { - if (/loaded|complete/.test(document.readyState)) - fireContentLoadedEvent(); - }, 0); - - Event.observe(window, "load", fireContentLoadedEvent); - - } else { - document.addEventListener("DOMContentLoaded", - fireContentLoadedEvent, false); - } - - } else { - document.write("