summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Legler <alex@a3li.li>2014-12-23 17:49:26 +0100
committerAlex Legler <alex@a3li.li>2014-12-23 17:49:26 +0100
commite352fff59842ca14fbfd81ee1c4a64297bb598c5 (patch)
tree153f268484aa5cc41cacf912bdce8c4847df222d /SemanticResultFormats/resources
downloadextensions-e352fff59842ca14fbfd81ee1c4a64297bb598c5.tar.gz
extensions-e352fff59842ca14fbfd81ee1c4a64297bb598c5.tar.bz2
extensions-e352fff59842ca14fbfd81ee1c4a64297bb598c5.zip
Add initial set of additional extensions
Diffstat (limited to 'SemanticResultFormats/resources')
-rw-r--r--SemanticResultFormats/resources/LICENSE3
-rw-r--r--SemanticResultFormats/resources/docs/jsduck.external.js37
-rw-r--r--SemanticResultFormats/resources/ext.srf.api.query.js274
-rw-r--r--SemanticResultFormats/resources/ext.srf.api.results.js267
-rw-r--r--SemanticResultFormats/resources/ext.srf.css47
-rw-r--r--SemanticResultFormats/resources/ext.srf.js130
-rw-r--r--SemanticResultFormats/resources/ext.srf.util.grid.css22
-rw-r--r--SemanticResultFormats/resources/ext.srf.util.grid.js242
-rw-r--r--SemanticResultFormats/resources/ext.srf.util.html.js62
-rw-r--r--SemanticResultFormats/resources/ext.srf.util.js364
-rw-r--r--SemanticResultFormats/resources/jquery/d3/d3.layout.cloud.js398
-rw-r--r--SemanticResultFormats/resources/jquery/d3/d3.v3.js7806
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/images/Sorting icons.psdbin0 -> 27490 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/images/back_disabled.pngbin0 -> 1361 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/images/back_enabled.pngbin0 -> 1379 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/images/back_enabled_hover.pngbin0 -> 1375 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/images/favicon.icobin0 -> 894 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/images/forward_disabled.pngbin0 -> 1363 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/images/forward_enabled.pngbin0 -> 1380 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/images/forward_enabled_hover.pngbin0 -> 1379 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/images/sort_asc.pngbin0 -> 1118 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/images/sort_asc_disabled.pngbin0 -> 1050 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/images/sort_both.pngbin0 -> 1136 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/images/sort_desc.pngbin0 -> 1127 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/images/sort_desc_disabled.pngbin0 -> 1045 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.css217
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.js108
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.css221
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.extras.js84
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.images.css29
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.js12099
-rw-r--r--SemanticResultFormats/resources/jquery/datatables/jquery.dataTables_themeroller.css244
-rw-r--r--SemanticResultFormats/resources/jquery/dygraphs/dygraph-combined.js2
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/blank.gifbin0 -> 43 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/closelabel.gifbin0 -> 979 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_close.pngbin0 -> 1517 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_loading.pngbin0 -> 10195 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_nav_left.pngbin0 -> 1446 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_nav_right.pngbin0 -> 1454 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_e.pngbin0 -> 107 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_n.pngbin0 -> 106 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_ne.pngbin0 -> 347 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_nw.pngbin0 -> 324 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_s.pngbin0 -> 111 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_se.pngbin0 -> 352 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_sw.pngbin0 -> 340 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_w.pngbin0 -> 103 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_title_left.pngbin0 -> 503 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_title_main.pngbin0 -> 96 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_title_over.pngbin0 -> 70 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancy_title_right.pngbin0 -> 506 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancybox-x.pngbin0 -> 203 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancybox-y.pngbin0 -> 176 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/fancybox.pngbin0 -> 15287 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.css359
-rw-r--r--SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.pack.js46
-rw-r--r--SemanticResultFormats/resources/jquery/flot/jquery.flot.js2605
-rw-r--r--SemanticResultFormats/resources/jquery/flot/jquery.flot.pie.js750
-rw-r--r--SemanticResultFormats/resources/jquery/flot/jquery.flot.selection.js344
-rw-r--r--SemanticResultFormats/resources/jquery/fullcalendar/GPL-LICENSE.txt278
-rw-r--r--SemanticResultFormats/resources/jquery/fullcalendar/MIT-LICENSE.txt20
-rw-r--r--SemanticResultFormats/resources/jquery/fullcalendar/changelog.txt322
-rw-r--r--SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.css618
-rw-r--r--SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.js5218
-rw-r--r--SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.min.js114
-rw-r--r--SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.print.css61
-rw-r--r--SemanticResultFormats/resources/jquery/fullcalendar/gcal.js112
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/Jplayer.swfbin0 -> 13748 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/add-on/jplayer.playlist.min.js34
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/add-on/jquery.jplayer.inspector.js338
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/jquery.jplayer.min.js107
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.css640
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.jpgbin0 -> 23189 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.seeking.gifbin0 -> 3284 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.video.play.pngbin0 -> 17692 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/README.morning.light.md29
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.css749
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.interface.pngbin0 -> 324 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.playlist.pngbin0 -> 275 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.pngbin0 -> 34557 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.seeking.gifbin0 -> 3284 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.video.play.pngbin0 -> 19197 bytes
-rw-r--r--SemanticResultFormats/resources/jquery/jqgrid/grid.locale-en.js169
-rw-r--r--SemanticResultFormats/resources/jquery/jqgrid/jquery.jqGrid.js516
-rw-r--r--SemanticResultFormats/resources/jquery/jqgrid/ui.jqgrid.css144
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/excanvas.js1438
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqPlot.Copyright29
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqPlot.MIT LICENSE21
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.BezierCurveRenderer.js313
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.barRenderer.js797
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.blockRenderer.js235
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.bubbleRenderer.js759
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisLabelRenderer.js203
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisTickRenderer.js243
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasOverlay.js865
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasTextRenderer.js449
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.categoryAxisRenderer.js673
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.ciParser.js116
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.cursor.js1108
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.dateAxisRenderer.js737
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.donutRenderer.js805
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.dragable.js225
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.enhancedLegendRenderer.js305
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.funnelRenderer.js943
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.highlighter.js465
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.json2.js475
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.logAxisRenderer.js529
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoAxisRenderer.js611
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoRenderer.js437
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.meterGaugeRenderer.js1030
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.mobile.js45
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.ohlcRenderer.js373
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.pieRenderer.js904
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.pointLabels.js379
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidAxisRenderer.js728
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidGridRenderer.js429
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidRenderer.js514
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jqplot.trendline.js223
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.css259
-rw-r--r--SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.js11381
-rw-r--r--SemanticResultFormats/resources/jquery/jquery.blockUI.js619
-rw-r--r--SemanticResultFormats/resources/jquery/jquery.dynamiccarousel.js526
-rw-r--r--SemanticResultFormats/resources/jquery/jquery.easing.js205
-rw-r--r--SemanticResultFormats/resources/jquery/jquery.jStorage.js1143
-rw-r--r--SemanticResultFormats/resources/jquery/jquery.jcarousel.js1057
-rw-r--r--SemanticResultFormats/resources/jquery/jquery.listmenu.js281
-rw-r--r--SemanticResultFormats/resources/jquery/jquery.listnav.js232
-rw-r--r--SemanticResultFormats/resources/jquery/jquery.pajinate.js313
-rw-r--r--SemanticResultFormats/resources/jquery/jquery.responsiveslides.js391
-rw-r--r--SemanticResultFormats/resources/jquery/jquery.sparkline.js3032
-rw-r--r--SemanticResultFormats/resources/jquery/jquery.tagcanvas.js1406
-rw-r--r--SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.css23
-rw-r--r--SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.css3
-rw-r--r--SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.js172
-rw-r--r--SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.js727
-rw-r--r--SemanticResultFormats/resources/widgets/ext.srf.widgets.optionslist.js157
-rw-r--r--SemanticResultFormats/resources/widgets/ext.srf.widgets.panel.js107
-rw-r--r--SemanticResultFormats/resources/widgets/ext.srf.widgets.parameters.js128
138 files changed, 75797 insertions, 0 deletions
diff --git a/SemanticResultFormats/resources/LICENSE b/SemanticResultFormats/resources/LICENSE
new file mode 100644
index 00000000..59113971
--- /dev/null
+++ b/SemanticResultFormats/resources/LICENSE
@@ -0,0 +1,3 @@
+See [1] the license for the specific language governing permissions and limitations under which each third party plug-in operates.
+
+[1] http://www.semantic-mediawiki.org/wiki/Help:Plug-ins \ No newline at end of file
diff --git a/SemanticResultFormats/resources/docs/jsduck.external.js b/SemanticResultFormats/resources/docs/jsduck.external.js
new file mode 100644
index 00000000..6d87218a
--- /dev/null
+++ b/SemanticResultFormats/resources/docs/jsduck.external.js
@@ -0,0 +1,37 @@
+/**
+ * @class jQuery
+ * @source <http://api.jquery.com/>
+ */
+
+/**
+ * @method ajax
+ * @source <http://api.jquery.com/jQuery.ajax/>
+ * @return {jqXHR}
+ */
+
+/**
+ * @class jQuery.Event
+ * @source <http://api.jquery.com/Types/#Event>
+ */
+
+/**
+ * @class jQuery.Promise
+ * @source <http://api.jquery.com/Types/#Promise>
+ */
+
+/**
+ * @class jQuery.Deferred
+ * @mixins jQuery.Promise
+ * @source <http://api.jquery.com/jQuery.Deferred/>
+ */
+
+/**
+ * @class jQuery.jqXHR
+ * @source <http://api.jquery.com/Types/#jqXHR>
+ * @alternateClassName jqXHR
+ */
+
+/**
+ * @class QUnit
+ * @source <http://api.qunitjs.com/>
+ */
diff --git a/SemanticResultFormats/resources/ext.srf.api.query.js b/SemanticResultFormats/resources/ext.srf.api.query.js
new file mode 100644
index 00000000..17a4fdbb
--- /dev/null
+++ b/SemanticResultFormats/resources/ext.srf.api.query.js
@@ -0,0 +1,274 @@
+/**
+ * SRF JavaScript for the api/query
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * Private methods and objects used within the class
+ *
+ * @since 1.9
+ */
+ var results = new srf.api.results();
+
+ /**
+ * Public API namespace declaration
+ *
+ * @since 1.9
+ * @type Object
+ */
+ srf.api = srf.api || {};
+
+ /**
+ * Base constructor for objects representing a api.query instance
+ *
+ * @since 1.9
+ */
+ srf.api.query = function() {};
+
+ /**
+ * Public methods to access information via the SMWAPI
+ *
+ * @since 1.9
+ * @type Object
+ */
+ srf.api.query.prototype = {
+
+ conditions: {
+
+ /**
+ * Builds a conditional statement
+ *
+ * For example
+ * operators ( ::, ::>, ::< etc.)
+ *
+ * @since 1.9
+ * @type Object
+ *
+ * @return array
+ */
+ build: function ( property, value, operator ){
+ return '[[' + property + ( operator || '::' ) + value + ']]';
+ }
+ },
+
+ printouts: {
+
+ /**
+ * Normalize printouts in order to get access via key reference
+ *
+ * e.g. |?Has location=location will be transformed into an
+ * array ["Has location", "location"]
+ *
+ * @since 1.9
+ * @type Object
+ *
+ * @return array
+ */
+ toList: function( printouts ){
+ var list = [];
+ var identifier = new RegExp( '[\\?&]' + '(.*?)' + '[=]' );
+
+ $.each( printouts, function( value, text ) {
+ // Split the text and find anything that is between ? and = otherwise
+ // split the string just after ?
+ var match = text.split( identifier );
+ if( match !== null ){
+ if ( match[0] === '' ){
+ // match ["", "Has lcoation", "location"]
+ list.push( [ match[1], match[2]] );
+ }else{
+ list.push( match[0].split( '?' )[1] );
+ }
+ }
+ } );
+ return list;
+ },
+
+ /**
+ * Find printout matches
+ *
+ * @since 1.9
+ * @type Object
+ */
+ search: {
+
+ /**
+ * Find printout that matches a specific identifier
+ *
+ * e.g. |?Has location=location
+ *
+ * search.identifier( [...], 'location' ) will result in "Has location"
+ *
+ * @since 1.9
+ * @type Object
+ * @type Object
+ *
+ * @return array
+ */
+ identifier: function( printouts, identifier ){
+ var property = '';
+ var regexS = '[\\?&]' + '(.*?)' + '=' + identifier;
+ var regex = new RegExp(regexS);
+
+ $.each( printouts , function( key, value ) {
+ if( value.match( regex ) !== null ){
+ property = value.match( regex )[1];
+ }
+ } );
+ return property;
+ },
+
+ /**
+ * Returns properties for a specific type where properties
+ * aren't marked with an identifier ( |?property=indentifier)
+ *
+ * SMWQUERY printouts, SMWAPI printrequests, ["_str","_txt"]
+ *
+ * For example
+ * type( printouts, printrequests, ["_str"] )
+ * result in ["Has location", "..."] that matches the type _str
+ *
+ * Filter all printout properties that are of type [...] and check against
+ * the printout list to indentify which of these printouts do not
+ * carry an additional identifier because those are not eligible
+ * to beused as filter properties
+ *
+ * @since 1.9
+ * @type Object
+ * @type Object
+ * @type Object
+ *
+ * @return array
+ */
+ type: function( printouts, printrequests, dataTypes ){
+ // Cache printouts, printrequests
+ var po = srf.api.query.prototype.printouts.toList( printouts ),
+ pr = srf.api.results.prototype.printrequests();
+ pr.toArray( printrequests );
+
+ // Normalize printouts to an amendable structure
+ function normalize(){
+ var matches = [];
+ // Match printouts against the list of available printrequests
+ $.each( po, function( index, property ) {
+ if ( typeof property === 'object' ) {
+ if ( $.inArray( pr.getTypeId( property[1] ), dataTypes ) > -1 ){
+ matches.push( property[0] );
+ }
+ } else {
+ if ( $.inArray( pr.getTypeId( property ), dataTypes ) > -1 ){
+ matches.push( property );
+ }
+ }
+ } );
+ return matches;
+ }
+
+ // Find those properties that are without an identifier
+ function withoutIdentifier( list ){
+ var matches = [];
+ $.each( list, function( index, property ) {
+ if ( $.inArray( property, po ) > -1 ) {
+ matches.push( property );
+ }
+ } );
+ return matches;
+ }
+
+ var record = withoutIdentifier( normalize() );
+ return record.length > 0 ? srf.api.util.prototype.array.unique( record ) : '';
+ }
+ }
+ },
+
+ /**
+ * Returns a concatenated query string
+ *
+ * @since 1.9
+ * @type Object
+ *
+ * @return string
+ */
+ toString: function( options ){
+
+ var printouts = '';
+ if ( options.printouts ){
+ $.each( options.printouts , function( key, value ) {
+ printouts = printouts + '|' + value;
+ } );
+ }
+
+ var parameters = '';
+ $.each( options.parameters , function( key, value ) {
+ parameters = parameters + '|' + key + '=' + value;
+ } );
+
+ var conditions = '';
+ if ( typeof options.conditions === 'object' ) {
+ $.each( options.conditions , function( key, value ) {
+ conditions = conditions + value;
+ } );
+ } else {
+ conditions = options.conditions;
+ }
+
+ return conditions + printouts + parameters;
+ },
+
+ /**
+ * Return results from the SMWAPI interface as callback
+ *
+ * @since 1.9
+ * @type Object
+ *
+ * @return array
+ */
+ fetch: function( query, callback, log ){
+
+ // Log data is only visible while in debug mode( &debug=true )
+ if ( log ){
+ var startDate = new Date();
+ srf.log( 'Query: ' + query );
+ }
+
+ $.ajax( {
+ url: mw.util.wikiScript( 'api' ),
+ dataType: 'json',
+ data: {
+ 'action': 'ask',
+ 'format': 'json',
+ 'query' : query
+ }
+ } )
+ .done( function ( data ) {
+ if ( log ){
+ srf.log( 'Hash: ' + data.query.meta.hash );
+ srf.log( 'Fetched: ' + ( new Date().getTime() - startDate.getTime() ) + ' ms ' + '( ' + data.query.meta.count + ' object )' );
+ }
+
+ // Return data to the callback
+ if ( typeof callback === 'function' ) {
+ callback.call( this, true, data );
+ }
+ return;
+ } )
+ .fail( function ( error ) {
+ if ( typeof callback === 'function' ) {
+ callback.call( this, false, error );
+ }
+ return;
+ } );
+ }
+ };
+
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/ext.srf.api.results.js b/SemanticResultFormats/resources/ext.srf.api.results.js
new file mode 100644
index 00000000..f6c1f04b
--- /dev/null
+++ b/SemanticResultFormats/resources/ext.srf.api.results.js
@@ -0,0 +1,267 @@
+/**
+ * SRF JavaScript for the api/results
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+/* global wgMonthNames:true */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ ////////////////////////// PRIVATE METHODS //////////////////////////
+
+ var timeLocales = {
+ monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
+ monthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
+ dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
+ dayNamesShort: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
+ amDesignator: 'AM',
+ pmDesignator: 'PM'
+ };
+
+ // Map wgMonthNames and create an indexed array
+ var monthNames = [];
+ $.map ( mw.config.get( 'wgMonthNames' ), function( value, key ) {
+ if( value !== '' ){
+ monthNames.push( value );
+ }
+ } );
+
+ ////////////////////////// PUBLIC METHODS /////////////////////////
+
+ /**
+ * API namespace declaration
+ *
+ * @since 1.9
+ * @type Object
+ */
+ srf.api = srf.api || {};
+
+ /**
+ * Base constructor for objects representing a api.results instance
+ *
+ * @since 1.9
+ */
+ srf.api.results = function() {};
+ srf.api.util = function() {};
+
+ /**
+ * Public to access results information retrieved through the SMWAPI
+ *
+ * @since 1.9
+ * @type Object
+ */
+ srf.api.util.prototype = {
+
+ /**
+ * Array helper functions
+ *
+ * @since 1.9
+ */
+ array:{
+ /**
+ * Array unique function
+ *
+ * $.unique only allows to be an array of DOM elements therefore
+ * this returns a nromal "array" with no duplicates
+ *
+ * @credits http://paulirish.com/2010/duck-punching-with-jquery/
+ *
+ * @since 1.9
+ */
+ unique: function( arr ){
+ if ( !!arr[0].nodeType ){
+ return $.unique.apply( this, arguments );
+ } else {
+ return $.grep(arr,function(v,k){ return $.inArray(v,arr) === k; } );
+ }
+ }
+ }
+ };
+
+ /**
+ * Public to access results information retrieved through the SMWAPI
+ *
+ * @since 1.9
+ * @type Object
+ */
+ srf.api.results.prototype = {
+
+ /**
+ * Collection related to printrequests and properties
+ *
+ * @since 1.9
+ */
+ printrequests: function( printrequests ){
+ var list = printrequests;
+
+ return {
+ list: list,
+
+ /**
+ * Returns a key reference array
+ *
+ * Transforms printrequest objects into an accessible flat array
+ * allowing a key reference
+ *
+ * Call as class instance via printrequests( [...] ).toArray()
+ * or as operational method via printrequests().toArray( [...] )
+ *
+ * @since 1.9
+ * @type Object
+ */
+ toArray: function ( printrequests ){
+ var tList = {};
+ printrequests = printrequests || list;
+
+ if ( printrequests !== undefined ){
+ $.map( printrequests, function( key, index ) {
+ tList[key.label] = { typeid: key.typeid, position: index, meta: key.meta };
+ } );
+ }
+ return list = tList;
+ },
+
+ /**
+ * Returns typeid for a property
+ *
+ * @since 1.9
+ * @type Object
+ */
+ getTypeId: function ( property ){
+ return list[property].typeid || null;
+ },
+
+ /**
+ * Returns some meta data for a property
+ *
+ * @since 1.9
+ * @type Object
+ */
+ getMetaData: function ( property ){
+ return list[property].meta || null;
+ },
+
+ /**
+ * Returns the position for a property
+ *
+ * Printouts in the result object are not sorted
+ * therefore this returns its position in accordance with the query
+ *
+ * @since 1.9
+ */
+ getPosition: function ( property ){
+ return list[property].position || null;
+ }
+ };
+ },
+
+ /**
+ * Collection related to data values
+ *
+ * @since 1.9
+ */
+ dataValues: {
+
+ /**
+ * Methods related to time data value
+ *
+ * @since 1.9
+ */
+ time: {
+
+ /**
+ * Returns normalized timestamp as JS date object
+ *
+ * @since 1.9
+ * @type Object
+ */
+ parseDate: function( d ) {
+ if ( typeof d === 'object') {
+ return d;
+ }
+ if ( typeof d === 'number' ) {
+ return new Date( d * 1000 );
+ }
+ if ( typeof d === 'string' ) {
+ if ( d.match(/^\d+(\.\d+)?$/) ) {
+ return new Date( parseFloat( d ) * 1000 );
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Create a new JavasScript date object based on the timestamp and return
+ * an ISO string
+ *
+ * @see SMWTimeValue::getISO8601Date()
+ *
+ * @since 1.9
+ * @type Object
+ */
+ getISO8601Date: function( timestamp ) {
+ var d = this.parseDate( timestamp );
+ return d !== null ? d.toISOString() : null;
+ },
+
+ /**
+ * Returns a formatted time (HH:MM:SS)
+ *
+ * @param string|Date time
+ * @return string
+ */
+ getTime: function( time ) {
+ var d = typeof time === 'object' ? time : this.parseDate( time );
+ return ( d.getHours() < 10 ? '0' + d.getHours() : d.getHours() ) +
+ ':' + ( d.getMinutes() < 10 ? '0' + d.getMinutes() : d.getMinutes() ) +
+ ':' + ( d.getSeconds() < 10 ? '0' + d.getSeconds() : d.getSeconds() );
+ },
+
+ /**
+ * Returns a formatted date
+ *
+ * @param string|Date
+ * @param string format
+ * @return string
+ */
+ getDate: function( date, format ) {
+ var d = typeof date === 'object' ? date : this.parseDate( date ),
+ formatDate = '';
+
+ switch( format ) {
+ case 'dmY':
+ formatDate = d.getDate() + '.' + ( '' + d.getMonth() + 1 ) + '.' + d.getFullYear();
+ break;
+ case 'Ymd':
+ formatDate = d.getFullYear() + '.' + ( '' + d.getMonth() + 1 ) + '.' + d.getDate();
+ break;
+ default:
+ formatDate = d.getDate() + ' ' + monthNames[d.getMonth()] + ' ' + d.getFullYear();
+ }
+
+ return formatDate;
+ },
+
+ /**
+ * Returns date
+ *
+ * @param string timestamp
+ * @param string format
+ * @return string
+ */
+ getMediaWikiDate: function( timestamp, format ) {
+ var date = this.parseDate( timestamp );
+ return this.getDate( date, format ) + ' ' + this.getTime( date );
+ }
+ }
+ }
+ };
+
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/ext.srf.css b/SemanticResultFormats/resources/ext.srf.css
new file mode 100644
index 00000000..3ca7c593
--- /dev/null
+++ b/SemanticResultFormats/resources/ext.srf.css
@@ -0,0 +1,47 @@
+/**
+ * CSS for SRF common objects
+ *
+ * @since 1.8
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+
+.srf-processing-text{
+ padding-left: 2.1em;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+.srf-spinner.text{
+ color: #666;
+ padding-left: 1.6em;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+/* Spinner for left side in-text*/
+.srf-spinner.mw-small-spinner {
+ background-position:left;
+ vertical-align: middle;
+ display:inline-block;
+ padding: 0px !important;
+}
+
+/* Sppiner for image center*/
+.srf-spinner-img.mw-small-spinner {
+ vertical-align: middle;
+ display:inline-block;
+ padding: 0px !important;
+}
+
+.srf-notification-content {
+ font-size: 0.8em;
+ color: #fff;
+ padding: 2px;
+ text-align: left;
+} \ No newline at end of file
diff --git a/SemanticResultFormats/resources/ext.srf.js b/SemanticResultFormats/resources/ext.srf.js
new file mode 100644
index 00000000..1244949a
--- /dev/null
+++ b/SemanticResultFormats/resources/ext.srf.js
@@ -0,0 +1,130 @@
+/**
+ * This file is part of the Semantic Result Formats Extension
+ * @see https://semantic-mediawiki.org/wiki/Srf
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ *
+ * @since 1.9
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2+
+ * @author Jeroen De Dauw <jeroendedauw at gmail dot com>
+ * @author mwjames
+ */
+
+/**
+ * Declares global srf instance and namespace
+ *
+ * @class srf
+ */
+var instance = ( function () {
+ 'use strict';
+
+ /*global console:true message:true */
+
+ var instance = {};
+
+ instance.log = function( message ) {
+ if ( typeof mediaWiki === 'undefined' ) {
+ if ( typeof console !== 'undefined' ) {
+ console.log( 'SRF: ', message );
+ }
+ } else {
+ return mediaWiki.log.call( mediaWiki.log, 'SRF: ', message );
+ }
+ };
+
+ instance.msg = function() {
+ if ( typeof mediaWiki === 'undefined' ) {
+ message = window.wgSRFMessages[arguments[0]];
+
+ for ( var i = arguments.length - 1; i > 0; i-- ) {
+ message = message.replace( '$' + i, arguments[i] );
+ }
+ return message;
+ } else {
+ return mediaWiki.msg.apply( mediaWiki.msg, arguments );
+ }
+ };
+
+ /**
+ * Declares utility namespace
+ */
+ instance.util = {};
+
+ /**
+ * Declares formats namespace
+ */
+ instance.formats = {};
+
+ /**
+ * Access settings array
+ *
+ * @since 1.9
+ *
+ * @return {mixed}
+ */
+ instance.settings = {
+
+ /**
+ * Returns list of available settings
+ *
+ * @since 1.9
+ *
+ * @return {Object}
+ */
+ getList: function() {
+ return mediaWiki.config.get( 'srf-config' ).settings;
+ },
+
+ /**
+ * Returns a specific settings value
+ *
+ * @since 1.9
+ *
+ * @param {string} key options to be selected
+ *
+ * @return {mixed}
+ */
+ get: function( key ) {
+ if( typeof key === 'string' ) {
+ return this.getList()[key];
+ }
+ return undefined;
+ }
+ };
+
+ /**
+ * Returns SRF version
+ *
+ * @since 1.9
+ *
+ * @return {string}
+ */
+ instance.version = function() {
+ return mediaWiki.config.get( 'srf-config' ).version;
+ };
+
+ // Alias
+ instance.Util = instance.util;
+
+ return instance;
+} )();
+
+// Assign namespace
+window.srf = window.semanticFormats = instance; \ No newline at end of file
diff --git a/SemanticResultFormats/resources/ext.srf.util.grid.css b/SemanticResultFormats/resources/ext.srf.util.grid.css
new file mode 100644
index 00000000..bb6df206
--- /dev/null
+++ b/SemanticResultFormats/resources/ext.srf.util.grid.css
@@ -0,0 +1,22 @@
+/**
+ * CSS for SRF gridview plugin
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Gridview
+ *
+ * @since 1.8
+ * @release 0.2
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+/* Changes have to comply with UI_BASE */
+.srf-gridview-query-link {
+ font-size:12px;
+ font-weight: normal;
+ margin-top:4px;
+ margin-right:3px;
+ color:#ddd;
+ float:right;
+} \ No newline at end of file
diff --git a/SemanticResultFormats/resources/ext.srf.util.grid.js b/SemanticResultFormats/resources/ext.srf.util.grid.js
new file mode 100644
index 00000000..b3d48303
--- /dev/null
+++ b/SemanticResultFormats/resources/ext.srf.util.grid.js
@@ -0,0 +1,242 @@
+/**
+ * JavaScript for SRF GridView plugin
+ * @see http://www.semantic-mediawiki.org/wiki/Help:Gridview
+ *
+ * @since 1.8
+ * @release 0.3
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( srf, $ ) {
+
+ "use strict";
+
+ /*global mw:true semanticFormats:true*/
+
+ ////////////////////////// PRIVATE METHODS //////////////////////////
+
+ var h = mw.html;
+ var UI_BASE = 'srf-gridview';
+
+ /**
+ * Add tab li element
+ * @var Object
+ */
+ function _addTabLink( tab ){
+ return '<li><a href="#' + tab.id + '">' + tab.msg +'</a></li>';
+ }
+
+ /**
+ * Add tab element
+ * @var Object
+ */
+ function _addTabElement( options ){
+ return options.context.after( h.element( 'div', {
+ 'id' : options.id,
+ 'class' : options.elemClass
+ }, new h.Raw( options.content )
+ ) );
+ }
+
+ /**
+ * Transform data into a structure like counter, series, data item, data value
+ * @var array
+ */
+ function _transformData( options ){
+ var gridData = [],
+ counter = 0;
+
+ // Data array
+ for ( var j = 0; j < options.data.length; ++j ) {
+ var ttSeries = options.series[j];
+ for ( var i = 0; i < options.data[j].length; ++i ) {
+ var row = { id: ++counter , series: ttSeries.label, item: options.data[j][i][0], value: options.data[j][i][1] };
+ gridData.push( row );
+ }
+ }
+ return gridData;
+ }
+
+ ////////////////////////// PUBLIC INTERFACE /////////////////////////
+
+ // Should be initialized but if it isn't create an object
+ srf.util = srf.util || {};
+
+ /**
+ * Constructor
+ * Class reference by using new srf.util.grid( options );
+ *
+ * @var Object
+ */
+ srf.util.grid = function( settings ) {
+
+ // Set general class and id identifier
+ var options = $.extend( {
+ 'tableID' : settings.id + '-grid',
+ 'pagerID' : settings.id + '-grid-pager',
+ 'baseClass' : UI_BASE,
+ 'tableClass': UI_BASE + '-table',
+ 'pageClass' : UI_BASE + '-table-pager',
+ 'queryClass': UI_BASE + '-query-link'
+ }, settings );
+
+ $.extend( this, options );
+
+ // Self-invoked init() for direct access to the class reference
+ this.init();
+ };
+
+ srf.util.grid.prototype = {
+ /**
+ * Initializes grid called by the constructor
+ * @var Object
+ */
+ init: function () {
+ var options = this;
+ return this.context.each( function() {
+
+ var obj = $( this ),
+ //options = this,
+ height = obj.height(),
+ width = options.widthBorder !== undefined ? obj.width() - options.widthBorder : obj.width() - 30,
+ tabs = [];
+
+ // Tabs definition
+ tabs.chart = _addTabLink( { id: options.id, msg: mw.msg( 'srf-ui-gridview-label-chart-tab' ) } );
+ tabs.data = _addTabLink( { id: options.id + '-data', msg: mw.msg( 'srf-ui-gridview-label-data-tab' ) } );
+ tabs.info = _addTabLink( { id: options.id + '-info', msg: mw.msg( 'srf-ui-gridview-label-info-tab' ) } );
+
+ // Add tab navigation
+ obj.prepend( '<ul>' + tabs.chart +
+ ( options.data.data !== undefined && options.data.data.length > 0 ? tabs.data : '' ) +
+ ( options.info !== undefined && options.info !== '' ? tabs.info : '' ) + '</ul>'
+ );
+
+ var containerContext = obj.find( '.container' );
+
+ // Add info tab element
+ if ( options.info !== undefined && options.info !== '' ){
+ _addTabElement( {
+ context: containerContext,
+ content: options.info,
+ id : options.id + '-info',
+ elemClass: options.baseClass + '-info-tab'
+ } );
+ }
+
+ // Add data tab element
+ if ( options.data.data !== undefined && options.data.data.length > 0 ){
+ _addTabElement( {
+ context: containerContext,
+ content: '',
+ id : options.id + '-data',
+ elemClass: options.baseClass + '-data-tab'
+ } );
+ }
+
+ // Init data table
+ var tableContext = obj.find( '#' + options.id + '-data');
+
+ tableContext
+ .prepend( '<table id="' + options.tableID + '" class="' + options.tableClass + '"></table>' )
+ .prepend( '<div id="' + options.pagerID + '" class="' + options.pagerClass + '"></div>' );
+ tableContext
+ .css( { width: width, height: height } );
+
+ // Create tabs ui
+ obj.tabs();
+
+ // Tabs height can vary (due to CSS) therefore after tabs instance was
+ // created get the height
+ var _tabs = obj.find( '.ui-tabs-nav' );
+
+ // Create Special:Ask query link [+]
+ if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'Ask' || options.data.sask === undefined ){
+ obj.find( '.' + options.queryClass )
+ .empty();
+ } else {
+ _tabs.prepend( '<span class="' + options.queryClass + '">' + options.data.sask + '</span>' );
+ obj.find( '.' + options.queryClass )
+ .find( 'a' )
+ .attr( 'title', mw.msg( 'ask' ) );
+ }
+
+ var gridContext = obj.find( '.' + options.tableClass ),
+ columnWidth = ( width / 2 ) - 5,
+ tableHeight = height - 100 - _tabs.outerHeight();
+
+ // Adopt data item output
+ var colModelItem = '';
+ if ( options.data.fcolumntypeid === '_dat' ) {
+ // Fetch default date display
+ var dateFormat = mw.user.options.get( 'date' );
+ if ( dateFormat.indexOf( 'ISO' ) >= 0 ){
+ dateFormat = "Y-m-d H:i:s";
+ } else {
+ dateFormat = 'd M Y';
+ }
+
+ colModelItem = {
+ name:'item',
+ index:'item',
+ width: columnWidth,
+ align:'center',
+ sorttype:'date',
+ formatter:'date',
+ formatoptions: { srcformat: 'U', newformat: dateFormat }
+ };
+ } else {
+ colModelItem = { name:'item', index:'item', width: columnWidth };
+ }
+
+ // Create grid instance
+ // @see http://www.trirand.com/jqgridwiki/doku.php
+ gridContext.jqGrid( {
+ datatype: 'local',
+ data: _transformData( { data: options.data.data, series: options.data.series } ),
+ colNames:[
+ 'id',
+ mw.msg( 'srf-ui-gridview-label-series' ),
+ mw.msg( 'srf-ui-gridview-label-item' ),
+ mw.msg( 'srf-ui-gridview-label-value' )
+ ],
+ colModel :[
+ { name:'id', index:'id', sorttype: 'int', hidden:true },
+ { name:'series', index:'series', width: 0 },
+ colModelItem,
+ { name:'value', index:'value', width: columnWidth, align:"right" }
+ ],
+ pager: '#' + options.pagerID ,
+ height: tableHeight,
+ rowList:[10,20,30,40,50],
+ ignoreCase: true,
+ grouping:true,
+ groupingView : {
+ groupField : ['series'],
+ groupColumnShow : [false]
+ },
+ sortname: 'item',
+ sortorder: 'asc',
+ viewrecords: true,
+ hidegrid: false
+ } );
+
+ // Init column search
+ gridContext.jqGrid( 'filterToolbar', {
+ stringResult: true,
+ searchOnEnter: false,
+ defaultSearch: "cn"
+ } );
+ } );
+ },
+
+ resize: function( ){
+ // Do something here
+ }
+ };
+
+} )( semanticFormats, jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/ext.srf.util.html.js b/SemanticResultFormats/resources/ext.srf.util.html.js
new file mode 100644
index 00000000..02aae331
--- /dev/null
+++ b/SemanticResultFormats/resources/ext.srf.util.html.js
@@ -0,0 +1,62 @@
+/**
+ * SRF JavaScript for srf.util namespace
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+/*global semanticFormats:true mediaWiki:true*/
+( function( $, mw, srf ) {
+ 'use strict';
+
+
+ ////////////////////////// PRIVATE OBJECTS //////////////////////////
+
+ var html = mw.html;
+
+ ////////////////////////// PUBLIC METHODS /////////////////////////
+
+ $.extend( srf.util.prototype, {
+
+ html:{
+
+ /**
+ * Returns a dropdown element
+ *
+ * e.g.
+ * options {
+ * list: ['...', '...'],
+ * id: 'printouts',
+ * selectClass: 'printouts',
+ * browser: 'firefox',
+ * disabled: 'disabled'
+ * }
+ *
+ * @since 1.9
+ */
+ dropdown: function( options ){
+ // @note The dropdown size behaves differently in some browsers
+ // therefore a css class is assigned for adjustments
+ var dropdown = '';
+ $.each( options.list, function( index, text ) {
+ if ( typeof text === 'object' ) {
+ text = text[0];
+ }
+ dropdown = dropdown + html.element( 'option', { 'value': index }, text );
+ } );
+
+ return html.element( 'div',{ 'class': 'select-wrap-' + options.browser || 'all' },
+ new html.Raw ( html.element( 'select', {'id': options.id, 'class': options.selectClass, 'disabled': options.disabled || false },
+ new html.Raw( html.element( 'option', { 'value': '' }, '' ) + dropdown ) )
+ )
+ );
+ }
+ }
+ } );
+
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/ext.srf.util.js b/SemanticResultFormats/resources/ext.srf.util.js
new file mode 100644
index 00000000..a9c687ca
--- /dev/null
+++ b/SemanticResultFormats/resources/ext.srf.util.js
@@ -0,0 +1,364 @@
+/*!
+ * This file is part of the Semantic Result Formats Extension
+ * @see https://www.semantic-mediawiki.org/wiki/SRF
+ *
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ *
+ * @since 1.8
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ ////////////////////////// PRIVATE METHODS //////////////////////////
+
+ var html = mw.html;
+
+ var _cacheTime = 1000 * 60 * 60 * 24; // 24 hours
+
+ var _CL_mwspinner = 'mw-small-spinner';
+ var _CL_srfIspinner = 'srf-spinner-img';
+ var _CL_srfspinner = 'srf-spinner';
+
+ ////////////////////////// PUBLIC METHODS /////////////////////////
+
+ /**
+ * Module for formats utilities namespace
+ * @since 1.8
+ * @type Object
+ */
+ srf.util = srf.util || {};
+
+ /**
+ * Constructor
+ * @var Object
+ */
+ srf.util = function( settings ) {
+ $.extend( this, settings );
+ };
+
+ srf.util.prototype = {
+ /**
+ * Get image url
+ * @since 1.8
+ * @param options
+ * @param callback
+ * @return string
+ */
+ getImageURL: function( options, callback ) {
+ var title = options.title,
+ cacheTime = options.cachetime;
+
+ // Get cache time
+ cacheTime = cacheTime === undefined ? _cacheTime : cacheTime;
+
+ // Get url from cache otherwise do an ajax call
+ var url = $.jStorage.get( title );
+
+ if ( url !== null ) {
+ if ( typeof callback === 'function' ) { // make sure the callback is a function
+ callback.call( this, url ); // brings the scope to the callback
+ }
+ return;
+ }
+
+ // Get url via ajax
+ $.getJSON(
+ mw.config.get( 'wgScriptPath' ) + '/api.php',
+ {
+ 'action': 'query',
+ 'format': 'json',
+ 'prop' : 'imageinfo',
+ 'iiprop': 'url',
+ 'titles': title
+ },
+ function( data ) {
+ if ( data.query && data.query.pages ) {
+ var pages = data.query.pages;
+ for ( var p in pages ) {
+ if ( pages.hasOwnProperty( p ) ) {
+ var info = pages[p].imageinfo;
+ for ( var i in info ) {
+ if ( info.hasOwnProperty( i ) ) {
+ $.jStorage.set( title , info[i].url, { TTL: cacheTime } );
+ if ( typeof callback === 'function' ) { // make sure the callback is a function
+ callback.call( this, info[i].url ); // brings the scope to the callback
+ }
+ return;
+ }
+ }
+ }
+ }
+ }
+ if ( typeof callback === 'function' ) { // make sure the callback is a function
+ callback.call( this, false ); // brings the scope to the callback
+ }
+ }
+ );
+ },
+
+ /**
+ * Get title url
+ * @since 1.8
+ * @param options
+ * @param callback
+ * @return string
+ */
+ getTitleURL: function( options, callback ) {
+ var title = options.title,
+ cacheTime = options.cachetime;
+
+ // Get cache time
+ cacheTime = cacheTime === undefined ? _cacheTime : cacheTime;
+
+ // Get url from cache otherwise do an ajax call
+ var url = $.jStorage.get( title );
+ if ( url !== null ) {
+ if ( typeof callback === 'function' ) { // make sure the callback is a function
+ callback.call( this, url ); // brings the scope to the callback
+ }
+ return;
+ }
+
+ // Get url via ajax
+ $.getJSON(
+ mw.config.get( 'wgScriptPath' ) + '/api.php',
+ {
+ 'action': 'query',
+ 'format': 'json',
+ 'prop' : 'info',
+ 'inprop': 'url',
+ 'titles': title
+ },
+ function( data ) {
+ if ( data.query && data.query.pages ) {
+ var pages = data.query.pages;
+ for ( var p in pages ) {
+ if ( pages.hasOwnProperty( p ) ) {
+ var info = pages[p];
+ $.jStorage.set( title, info.fullurl, { TTL: cacheTime } );
+ if ( typeof callback === 'function' ) { // make sure the callback is a function
+ callback.call( this, info.fullurl ); // brings the scope to the callback
+ }
+ return;
+ }
+ }
+ }
+ if ( typeof callback === 'function' ) { // make sure the callback is a function
+ callback.call( this, false ); // brings the scope to the callback
+ }
+ }
+ );
+ },
+
+ /**
+ * Get spinner for a local element
+ * @since 1.8
+ * @param options
+ * @return object
+ */
+ spinner: {
+ create: function( options ) {
+
+ // Select the object from its context and determine height and width
+ var obj = options.context.find( options.selector ),
+ h = mw.html,
+ width = obj.width(),
+ height = obj.height();
+
+ // Add spinner to target object
+ obj.after( h.element( 'span', { 'class' : _CL_srfIspinner + ' ' + _CL_mwspinner }, null ) );
+
+ // Adopt height and width to avoid clutter
+ options.context.find( '.' + _CL_srfIspinner + '.' + _CL_mwspinner )
+ .css( { width: width, height: height } )
+ .data ( 'spinner', obj ); // Attach the original object as data element
+ obj.remove(); // Could just hide the element instead of removing it
+
+ },
+ replace: function ( options ){
+ // Replace spinner and restore original instance
+ options.context.find( '.' + _CL_srfIspinner + '.' + _CL_mwspinner )
+ .replaceWith( options.context.find( '.' + _CL_srfIspinner ).data( 'spinner' ) ) ;
+ },
+ hide: function ( options ){
+ var c = options.length === undefined ? options.context : options;
+ c.find( '.' + _CL_srfspinner ).hide();
+ }
+ },
+
+ /**
+ * Convenience method to check if some options are supported
+ *
+ * @since 1.9
+ *
+ * @param {string} option
+ *
+ * @return boolean
+ */
+ assert: function( option ) {
+ switch ( option ){
+ case 'canvas':
+ // Checks if the current browser supports canvas
+ // @see http://goo.gl/9PYP3
+ return !!window.HTMLCanvasElement;
+ case 'svg':
+ // Checks if the current browser supports svg
+ return !!window.SVGSVGElement;
+ default:
+ return false;
+ }
+ },
+
+ /**
+ * Convenience method for growl-like notifications using the blockUI plugin
+ *
+ * @since 1.9
+ * @var options
+ * @return object
+ */
+ notification: {
+ create: function( options ) {
+ return $.blockUI( {
+ message: html.element( 'span', { 'class' : 'srf-notification-content' }, new html.Raw( options.content ) ),
+ fadeIn: 700,
+ fadeOut: 700,
+ timeout: 2000,
+ showOverlay: false,
+ centerY: false,
+ css: {
+ 'width': '235px',
+ 'line-height': '1.35',
+ 'z-index': '10000',
+ 'top': '10px',
+ 'left': '',
+ 'right': '15px',
+ 'padding': '0.25em 1em',
+ 'margin-bottom': '0.5em',
+ 'border': '0px solid #fff',
+ 'background-color': options.color || '#000',
+ 'opacity': '.6',
+ 'cursor': 'pointer',
+ '-webkit-border-radius': '5px',
+ '-moz-border-radius': '5px',
+ 'border-radius': '5px',
+ '-webkit-box-shadow': '0 2px 10px 0 rgba(0,0,0,0.125)',
+ '-moz-box-shadow': '0 2px 10px 0 rgba(0,0,0,0.125)',
+ 'box-shadow': '0 2px 10px 0 rgba(0,0,0,0.125)'
+ }
+ } );
+ }
+ },
+
+ /**
+ * Convenience method for ui-widget like error/info messages
+ *
+ * @since 1.9
+ * @var options
+ * @return object
+ */
+ message:{
+ set: function( options ){
+ var type = options.type === 'error' ? 'ui-state-error' : 'ui-state-highlight';
+ options.context.prepend( html.element( 'div', {
+ 'class': 'ui-widget' }, new html.Raw( html.element( 'div', {
+ 'class': type + ' ui-corner-all','style': 'padding-left: 0.5em' }, new html.Raw( html.element( 'p', { }, new html.Raw( html.element( 'span', { 'class': 'ui-icon ui-icon-alert', 'style': 'float: left; margin-right: 0.7em;' }, '' ) + options.message ) ) ) ) ) ) );
+ },
+
+ exception: function( options ){
+ this.set( $.extend( {}, { type: 'error' }, options ) );
+ throw new Error( options.message );
+ },
+
+ remove:function( context ){
+ context.children().fadeOut( 'slow' ).remove();
+ }
+ },
+
+ /**
+ *
+ *
+ *
+ */
+ image: {
+
+ /**
+ * Returns image information including thumbnail
+ *
+ * @since 1.9
+ *
+ * @param options
+ * @param callback
+ *
+ * @return object
+ */
+ imageInfo: function( options, callback ){
+ var isCached = true;
+
+ // Get cache otherwise do an Ajax call
+ if ( options.cache ) {
+ var imageInfo = $.jStorage.get( options.title + '-' + options.width );
+
+ if ( imageInfo !== null ) {
+ if ( typeof callback === 'function' ) {
+ callback.call( this, isCached, imageInfo );
+ }
+ return;
+ }
+ }
+
+ $.getJSON( mw.config.get( 'wgScriptPath' ) + '/api.php', {
+ 'action': 'query',
+ 'format': 'json',
+ 'prop' : 'imageinfo',
+ 'iiprop': 'url',
+ 'iiurlwidth': options.width,
+ 'iiurlheight': options.height,
+ 'titles': options.title
+ },
+ function( data ) {
+ if ( data.query && data.query.pages ) {
+ var pages = data.query.pages;
+ for ( var p in pages ) {
+ if ( pages.hasOwnProperty( p ) ) {
+ var info = pages[p];
+ if ( options.cache !== undefined ) {
+ $.jStorage.set( options.title + '-' + options.width , info, { TTL: options.cache } );
+ }
+ if ( typeof callback === 'function' ) {
+ callback.call( this, !isCached, info );
+ }
+ return;
+ }
+ }
+ }
+ if ( typeof callback === 'function' ) {
+ callback.call( this, !isCached, false );
+ }
+ }
+ );
+ }
+
+ }
+ };
+
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/d3/d3.layout.cloud.js b/SemanticResultFormats/resources/jquery/d3/d3.layout.cloud.js
new file mode 100644
index 00000000..511bdb77
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/d3/d3.layout.cloud.js
@@ -0,0 +1,398 @@
+// Word cloud layout by Jason Davies, http://www.jasondavies.com/word-cloud/
+// Algorithm due to Jonathan Feinberg, http://static.mrfeinberg.com/bv_ch03.pdf
+// @author: mwjames, 2012-08, added href as construtor field
+(function(exports) {
+ function cloud() {
+ var size = [256, 256],
+ text = cloudText,
+ href = cloudhref,
+ font = cloudFont,
+ fontSize = cloudFontSize,
+ rotate = cloudRotate,
+ padding = cloudPadding,
+ spiral = archimedeanSpiral,
+ words = [],
+ timeInterval = Infinity,
+ event = d3.dispatch("word", "end"),
+ timer = null,
+ cloud = {};
+
+ cloud.start = function() {
+ var board = zeroArray((size[0] >> 5) * size[1]),
+ bounds = null,
+ n = words.length,
+ i = -1,
+ tags = [],
+ data = words.map(function(d, i) {
+ return {
+ text: text.call(this, d, i),
+ href: href.call(this, d, i),
+ font: font.call(this, d, i),
+ rotate: rotate.call(this, d, i),
+ size: ~~fontSize.call(this, d, i),
+ padding: cloudPadding.call(this, d, i)
+ };
+ }).sort(function(a, b) { return b.size - a.size; });
+
+ if (timer) clearInterval(timer);
+ timer = setInterval(step, 0);
+ step();
+
+ return cloud;
+
+ function step() {
+ var start = +new Date,
+ d;
+ while (+new Date - start < timeInterval && ++i < n && timer) {
+ d = data[i];
+ d.x = (size[0] * (Math.random() + .5)) >> 1;
+ d.y = (size[1] * (Math.random() + .5)) >> 1;
+ cloudSprite(d, data, i);
+ if (place(board, d, bounds)) {
+ tags.push(d);
+ event.word(d);
+ if (bounds) cloudBounds(bounds, d);
+ else bounds = [{x: d.x + d.x0, y: d.y + d.y0}, {x: d.x + d.x1, y: d.y + d.y1}];
+ // Temporary hack
+ d.x -= size[0] >> 1;
+ d.y -= size[1] >> 1;
+ }
+ }
+ if (i >= n) {
+ cloud.stop();
+ event.end(tags, bounds);
+ }
+ }
+ }
+
+ cloud.stop = function() {
+ if (timer) {
+ clearInterval(timer);
+ timer = null;
+ }
+ return cloud;
+ };
+
+ cloud.timeInterval = function(x) {
+ if (!arguments.length) return timeInterval;
+ timeInterval = x == null ? Infinity : x;
+ return cloud;
+ };
+
+ function place(board, tag, bounds) {
+ var perimeter = [{x: 0, y: 0}, {x: size[0], y: size[1]}],
+ startX = tag.x,
+ startY = tag.y,
+ maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]),
+ s = spiral(size),
+ dt = Math.random() < .5 ? 1 : -1,
+ t = -dt,
+ dxdy,
+ dx,
+ dy;
+
+ while (dxdy = s(t += dt)) {
+ dx = ~~dxdy[0];
+ dy = ~~dxdy[1];
+
+ if (Math.min(dx, dy) > maxDelta) break;
+
+ tag.x = startX + dx;
+ tag.y = startY + dy;
+
+ if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 ||
+ tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue;
+ // TODO only check for collisions within current bounds.
+ if (!bounds || !cloudCollide(tag, board, size[0])) {
+ if (!bounds || collideRects(tag, bounds)) {
+ var sprite = tag.sprite,
+ w = tag.width >> 5,
+ sw = size[0] >> 5,
+ lx = tag.x - (w << 4),
+ sx = lx & 0x7f,
+ msx = 32 - sx,
+ h = tag.y1 - tag.y0,
+ x = (tag.y + tag.y0) * sw + (lx >> 5),
+ last;
+ for (var j = 0; j < h; j++) {
+ last = 0;
+ for (var i = 0; i <= w; i++) {
+ board[x + i] |= (last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0);
+ }
+ x += sw;
+ }
+ delete tag.sprite;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ cloud.words = function(x) {
+ if (!arguments.length) return words;
+ words = x;
+ return cloud;
+ };
+
+ cloud.size = function(x) {
+ if (!arguments.length) return size;
+ size = [+x[0], +x[1]];
+ return cloud;
+ };
+
+ cloud.font = function(x) {
+ if (!arguments.length) return font;
+ font = d3.functor(x);
+ return cloud;
+ };
+
+ cloud.rotate = function(x) {
+ if (!arguments.length) return rotate;
+ rotate = d3.functor(x);
+ return cloud;
+ };
+
+ cloud.text = function(x) {
+ if (!arguments.length) return text;
+ text = d3.functor(x);
+ return cloud;
+ };
+
+ cloud.href = function(x) {
+ if (!arguments.length) return href;
+ text = d3.functor(x);
+ return cloud;
+ };
+
+ cloud.spiral = function(x) {
+ if (!arguments.length) return spiral;
+ spiral = spirals[x + ""] || x;
+ return cloud;
+ };
+
+ cloud.fontSize = function(x) {
+ if (!arguments.length) return fontSize;
+ fontSize = d3.functor(x);
+ return cloud;
+ };
+
+ cloud.padding = function(x) {
+ if (!arguments.length) return padding;
+ padding = d3.functor(x);
+ return cloud;
+ };
+
+ return d3.rebind(cloud, event, "on");
+ }
+
+ function cloudText(d) {
+ return d.text;
+ }
+
+ function cloudhref(d) {
+ return d.href;
+ }
+
+ function cloudFont() {
+ return "serif";
+ }
+
+ function cloudFontSize(d) {
+ return Math.sqrt(d.value);
+ }
+
+ function cloudRotate() {
+ return (~~(Math.random() * 6) - 3) * 30;
+ }
+
+ function cloudPadding() {
+ return 1;
+ }
+
+ // Fetches a monochrome sprite bitmap for the specified text.
+ // Load in batches for speed.
+ function cloudSprite(d, data, di) {
+ if (d.sprite) return;
+ c.clearRect(0, 0, (cw << 5) / ratio, ch / ratio);
+ var x = 0,
+ y = 0,
+ maxh = 0,
+ n = data.length;
+ di--;
+ while (++di < n) {
+ d = data[di];
+ c.save();
+ c.font = ~~((d.size + 1) / ratio) + "px " + d.font;
+ var w = c.measureText(d.text + "m").width * ratio,
+ h = d.size << 1;
+ if (d.rotate) {
+ var sr = Math.sin(d.rotate * cloudRadians),
+ cr = Math.cos(d.rotate * cloudRadians),
+ wcr = w * cr,
+ wsr = w * sr,
+ hcr = h * cr,
+ hsr = h * sr;
+ w = (Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f) >> 5 << 5;
+ h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr));
+ } else {
+ w = (w + 0x1f) >> 5 << 5;
+ }
+ if (h > maxh) maxh = h;
+ if (x + w >= (cw << 5)) {
+ x = 0;
+ y += maxh;
+ maxh = 0;
+ }
+ if (y + h >= ch) break;
+ c.translate((x + (w >> 1)) / ratio, (y + (h >> 1)) / ratio);
+ if (d.rotate) c.rotate(d.rotate * cloudRadians);
+ c.fillText(d.text, 0, 0);
+ c.restore();
+ d.width = w;
+ d.height = h;
+ d.xoff = x;
+ d.yoff = y;
+ d.x1 = w >> 1;
+ d.y1 = h >> 1;
+ d.x0 = -d.x1;
+ d.y0 = -d.y1;
+ x += w;
+ }
+ var pixels = c.getImageData(0, 0, (cw << 5) / ratio, ch / ratio).data,
+ sprite = [];
+ while (--di >= 0) {
+ d = data[di];
+ var w = d.width,
+ w32 = w >> 5,
+ h = d.y1 - d.y0,
+ p = d.padding;
+ // Zero the buffer
+ for (var i = 0; i < h * w32; i++) sprite[i] = 0;
+ x = d.xoff;
+ if (x == null) return;
+ y = d.yoff;
+ var seen = 0,
+ seenRow = -1;
+ for (var j = 0; j < h; j++) {
+ for (var i = 0; i < w; i++) {
+ var k = w32 * j + (i >> 5),
+ m = pixels[((y + j) * (cw << 5) + (x + i)) << 2] ? 1 << (31 - (i % 32)) : 0;
+ if (p) {
+ if (j) sprite[k - w32] |= m;
+ if (j < w - 1) sprite[k + w32] |= m;
+ m |= (m << 1) | (m >> 1);
+ }
+ sprite[k] |= m;
+ seen |= m;
+ }
+ if (seen) seenRow = j;
+ else {
+ d.y0++;
+ h--;
+ j--;
+ y++;
+ }
+ }
+ d.y1 = d.y0 + seenRow;
+ d.sprite = sprite.slice(0, (d.y1 - d.y0) * w32);
+ }
+ }
+
+ // Use mask-based collision detection.
+ function cloudCollide(tag, board, sw) {
+ sw >>= 5;
+ var sprite = tag.sprite,
+ w = tag.width >> 5,
+ lx = tag.x - (w << 4),
+ sx = lx & 0x7f,
+ msx = 32 - sx,
+ h = tag.y1 - tag.y0,
+ x = (tag.y + tag.y0) * sw + (lx >> 5),
+ last;
+ for (var j = 0; j < h; j++) {
+ last = 0;
+ for (var i = 0; i <= w; i++) {
+ if (((last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0))
+ & board[x + i]) return true;
+ }
+ x += sw;
+ }
+ return false;
+ }
+
+ function cloudBounds(bounds, d) {
+ var b0 = bounds[0],
+ b1 = bounds[1];
+ if (d.x + d.x0 < b0.x) b0.x = d.x + d.x0;
+ if (d.y + d.y0 < b0.y) b0.y = d.y + d.y0;
+ if (d.x + d.x1 > b1.x) b1.x = d.x + d.x1;
+ if (d.y + d.y1 > b1.y) b1.y = d.y + d.y1;
+ }
+
+ function collideRects(a, b) {
+ return a.x + a.x1 > b[0].x && a.x + a.x0 < b[1].x && a.y + a.y1 > b[0].y && a.y + a.y0 < b[1].y;
+ }
+
+ function archimedeanSpiral(size) {
+ var e = size[0] / size[1];
+ return function(t) {
+ return [e * (t *= .1) * Math.cos(t), t * Math.sin(t)];
+ };
+ }
+
+ function rectangularSpiral(size) {
+ var dy = 4,
+ dx = dy * size[0] / size[1],
+ x = 0,
+ y = 0;
+ return function(t) {
+ var sign = t < 0 ? -1 : 1;
+ // See triangular numbers: T_n = n * (n + 1) / 2.
+ switch ((Math.sqrt(1 + 4 * sign * t) - sign) & 3) {
+ case 0: x += dx; break;
+ case 1: y += dy; break;
+ case 2: x -= dx; break;
+ default: y -= dy; break;
+ }
+ return [x, y];
+ };
+ }
+
+ // TODO reuse arrays?
+ function zeroArray(n) {
+ var a = [],
+ i = -1;
+ while (++i < n) a[i] = 0;
+ return a;
+ }
+
+ var cloudRadians = Math.PI / 180,
+ cw = 1 << 11 >> 5,
+ ch = 1 << 11,
+ canvas,
+ ratio = 1;
+
+ if (typeof document !== "undefined") {
+ canvas = document.createElement("canvas");
+ canvas.width = 1;
+ canvas.height = 1;
+ ratio = Math.sqrt(canvas.getContext("2d").getImageData(0, 0, 1, 1).data.length >> 2);
+ canvas.width = (cw << 5) / ratio;
+ canvas.height = ch / ratio;
+ } else {
+ // node-canvas support
+ var Canvas = require("canvas");
+ canvas = new Canvas(cw << 5, ch);
+ }
+
+ var c = canvas.getContext("2d"),
+ spirals = {
+ archimedean: archimedeanSpiral,
+ rectangular: rectangularSpiral
+ };
+ c.fillStyle = "red";
+ c.textAlign = "center";
+
+ exports.cloud = cloud;
+})(typeof exports === "undefined" ? d3.layout || (d3.layout = {}) : exports);
diff --git a/SemanticResultFormats/resources/jquery/d3/d3.v3.js b/SemanticResultFormats/resources/jquery/d3/d3.v3.js
new file mode 100644
index 00000000..2d9c0ef9
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/d3/d3.v3.js
@@ -0,0 +1,7806 @@
+(function() {
+ var d3_format_decimalPoint = ".", d3_format_thousandsSeparator = ",", d3_format_grouping = [ 3, 3 ];
+ if (!Date.now) Date.now = function() {
+ return +new Date();
+ };
+ try {
+ document.createElement("div").style.setProperty("opacity", 0, "");
+ } catch (error) {
+ var d3_style_prototype = CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty;
+ d3_style_prototype.setProperty = function(name, value, priority) {
+ d3_style_setProperty.call(this, name, value + "", priority);
+ };
+ }
+ d3 = {
+ version: "3.0.4"
+ };
+ var π = Math.PI, ε = 1e-6, d3_radians = π / 180, d3_degrees = 180 / π;
+ function d3_target(d) {
+ return d.target;
+ }
+ function d3_source(d) {
+ return d.source;
+ }
+ function d3_class(ctor, properties) {
+ try {
+ for (var key in properties) {
+ Object.defineProperty(ctor.prototype, key, {
+ value: properties[key],
+ enumerable: false
+ });
+ }
+ } catch (e) {
+ ctor.prototype = properties;
+ }
+ }
+ var d3_array = d3_arraySlice;
+ function d3_arrayCopy(pseudoarray) {
+ var i = -1, n = pseudoarray.length, array = [];
+ while (++i < n) array.push(pseudoarray[i]);
+ return array;
+ }
+ function d3_arraySlice(pseudoarray) {
+ return Array.prototype.slice.call(pseudoarray);
+ }
+ try {
+ d3_array(document.documentElement.childNodes)[0].nodeType;
+ } catch (e) {
+ d3_array = d3_arrayCopy;
+ }
+ var d3_arraySubclass = [].__proto__ ? function(array, prototype) {
+ array.__proto__ = prototype;
+ } : function(array, prototype) {
+ for (var property in prototype) array[property] = prototype[property];
+ };
+ d3.map = function(object) {
+ var map = new d3_Map();
+ for (var key in object) map.set(key, object[key]);
+ return map;
+ };
+ function d3_Map() {}
+ d3_class(d3_Map, {
+ has: function(key) {
+ return d3_map_prefix + key in this;
+ },
+ get: function(key) {
+ return this[d3_map_prefix + key];
+ },
+ set: function(key, value) {
+ return this[d3_map_prefix + key] = value;
+ },
+ remove: function(key) {
+ key = d3_map_prefix + key;
+ return key in this && delete this[key];
+ },
+ keys: function() {
+ var keys = [];
+ this.forEach(function(key) {
+ keys.push(key);
+ });
+ return keys;
+ },
+ values: function() {
+ var values = [];
+ this.forEach(function(key, value) {
+ values.push(value);
+ });
+ return values;
+ },
+ entries: function() {
+ var entries = [];
+ this.forEach(function(key, value) {
+ entries.push({
+ key: key,
+ value: value
+ });
+ });
+ return entries;
+ },
+ forEach: function(f) {
+ for (var key in this) {
+ if (key.charCodeAt(0) === d3_map_prefixCode) {
+ f.call(this, key.substring(1), this[key]);
+ }
+ }
+ }
+ });
+ var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0);
+ function d3_identity(d) {
+ return d;
+ }
+ function d3_true() {
+ return true;
+ }
+ function d3_functor(v) {
+ return typeof v === "function" ? v : function() {
+ return v;
+ };
+ }
+ d3.functor = d3_functor;
+ d3.rebind = function(target, source) {
+ var i = 1, n = arguments.length, method;
+ while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
+ return target;
+ };
+ function d3_rebind(target, source, method) {
+ return function() {
+ var value = method.apply(source, arguments);
+ return arguments.length ? target : value;
+ };
+ }
+ d3.ascending = function(a, b) {
+ return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
+ };
+ d3.descending = function(a, b) {
+ return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
+ };
+ d3.mean = function(array, f) {
+ var n = array.length, a, m = 0, i = -1, j = 0;
+ if (arguments.length === 1) {
+ while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j;
+ } else {
+ while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j;
+ }
+ return j ? m : undefined;
+ };
+ d3.median = function(array, f) {
+ if (arguments.length > 1) array = array.map(f);
+ array = array.filter(d3_number);
+ return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined;
+ };
+ d3.min = function(array, f) {
+ var i = -1, n = array.length, a, b;
+ if (arguments.length === 1) {
+ while (++i < n && ((a = array[i]) == null || a != a)) a = undefined;
+ while (++i < n) if ((b = array[i]) != null && a > b) a = b;
+ } else {
+ while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
+ }
+ return a;
+ };
+ d3.max = function(array, f) {
+ var i = -1, n = array.length, a, b;
+ if (arguments.length === 1) {
+ while (++i < n && ((a = array[i]) == null || a != a)) a = undefined;
+ while (++i < n) if ((b = array[i]) != null && b > a) a = b;
+ } else {
+ while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;
+ }
+ return a;
+ };
+ d3.extent = function(array, f) {
+ var i = -1, n = array.length, a, b, c;
+ if (arguments.length === 1) {
+ while (++i < n && ((a = c = array[i]) == null || a != a)) a = c = undefined;
+ while (++i < n) if ((b = array[i]) != null) {
+ if (a > b) a = b;
+ if (c < b) c = b;
+ }
+ } else {
+ while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
+ if (a > b) a = b;
+ if (c < b) c = b;
+ }
+ }
+ return [ a, c ];
+ };
+ d3.random = {
+ normal: function(µ, σ) {
+ var n = arguments.length;
+ if (n < 2) σ = 1;
+ if (n < 1) µ = 0;
+ return function() {
+ var x, y, r;
+ do {
+ x = Math.random() * 2 - 1;
+ y = Math.random() * 2 - 1;
+ r = x * x + y * y;
+ } while (!r || r > 1);
+ return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r);
+ };
+ },
+ logNormal: function(µ, σ) {
+ var n = arguments.length;
+ if (n < 2) σ = 1;
+ if (n < 1) µ = 0;
+ var random = d3.random.normal();
+ return function() {
+ return Math.exp(µ + σ * random());
+ };
+ },
+ irwinHall: function(m) {
+ return function() {
+ for (var s = 0, j = 0; j < m; j++) s += Math.random();
+ return s / m;
+ };
+ }
+ };
+ function d3_number(x) {
+ return x != null && !isNaN(x);
+ }
+ d3.sum = function(array, f) {
+ var s = 0, n = array.length, a, i = -1;
+ if (arguments.length === 1) {
+ while (++i < n) if (!isNaN(a = +array[i])) s += a;
+ } else {
+ while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a;
+ }
+ return s;
+ };
+ d3.quantile = function(values, p) {
+ var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h;
+ return e ? v + e * (values[h] - v) : v;
+ };
+ d3.shuffle = function(array) {
+ var m = array.length, t, i;
+ while (m) {
+ i = Math.random() * m-- | 0;
+ t = array[m], array[m] = array[i], array[i] = t;
+ }
+ return array;
+ };
+ d3.transpose = function(matrix) {
+ return d3.zip.apply(d3, matrix);
+ };
+ d3.zip = function() {
+ if (!(n = arguments.length)) return [];
+ for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) {
+ for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) {
+ zip[j] = arguments[j][i];
+ }
+ }
+ return zips;
+ };
+ function d3_zipLength(d) {
+ return d.length;
+ }
+ d3.bisector = function(f) {
+ return {
+ left: function(a, x, lo, hi) {
+ if (arguments.length < 3) lo = 0;
+ if (arguments.length < 4) hi = a.length;
+ while (lo < hi) {
+ var mid = lo + hi >>> 1;
+ if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid;
+ }
+ return lo;
+ },
+ right: function(a, x, lo, hi) {
+ if (arguments.length < 3) lo = 0;
+ if (arguments.length < 4) hi = a.length;
+ while (lo < hi) {
+ var mid = lo + hi >>> 1;
+ if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1;
+ }
+ return lo;
+ }
+ };
+ };
+ var d3_bisector = d3.bisector(function(d) {
+ return d;
+ });
+ d3.bisectLeft = d3_bisector.left;
+ d3.bisect = d3.bisectRight = d3_bisector.right;
+ d3.nest = function() {
+ var nest = {}, keys = [], sortKeys = [], sortValues, rollup;
+ function map(array, depth) {
+ if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array;
+ var i = -1, n = array.length, key = keys[depth++], keyValue, object, valuesByKey = new d3_Map(), values, o = {};
+ while (++i < n) {
+ if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
+ values.push(object);
+ } else {
+ valuesByKey.set(keyValue, [ object ]);
+ }
+ }
+ valuesByKey.forEach(function(keyValue, values) {
+ o[keyValue] = map(values, depth);
+ });
+ return o;
+ }
+ function entries(map, depth) {
+ if (depth >= keys.length) return map;
+ var a = [], sortKey = sortKeys[depth++], key;
+ for (key in map) {
+ a.push({
+ key: key,
+ values: entries(map[key], depth)
+ });
+ }
+ if (sortKey) a.sort(function(a, b) {
+ return sortKey(a.key, b.key);
+ });
+ return a;
+ }
+ nest.map = function(array) {
+ return map(array, 0);
+ };
+ nest.entries = function(array) {
+ return entries(map(array, 0), 0);
+ };
+ nest.key = function(d) {
+ keys.push(d);
+ return nest;
+ };
+ nest.sortKeys = function(order) {
+ sortKeys[keys.length - 1] = order;
+ return nest;
+ };
+ nest.sortValues = function(order) {
+ sortValues = order;
+ return nest;
+ };
+ nest.rollup = function(f) {
+ rollup = f;
+ return nest;
+ };
+ return nest;
+ };
+ d3.keys = function(map) {
+ var keys = [];
+ for (var key in map) keys.push(key);
+ return keys;
+ };
+ d3.values = function(map) {
+ var values = [];
+ for (var key in map) values.push(map[key]);
+ return values;
+ };
+ d3.entries = function(map) {
+ var entries = [];
+ for (var key in map) entries.push({
+ key: key,
+ value: map[key]
+ });
+ return entries;
+ };
+ d3.permute = function(array, indexes) {
+ var permutes = [], i = -1, n = indexes.length;
+ while (++i < n) permutes[i] = array[indexes[i]];
+ return permutes;
+ };
+ d3.merge = function(arrays) {
+ return Array.prototype.concat.apply([], arrays);
+ };
+ function d3_collapse(s) {
+ return s.trim().replace(/\s+/g, " ");
+ }
+ d3.range = function(start, stop, step) {
+ if (arguments.length < 3) {
+ step = 1;
+ if (arguments.length < 2) {
+ stop = start;
+ start = 0;
+ }
+ }
+ if ((stop - start) / step === Infinity) throw new Error("infinite range");
+ var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j;
+ start *= k, stop *= k, step *= k;
+ if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k);
+ return range;
+ };
+ function d3_range_integerScale(x) {
+ var k = 1;
+ while (x * k % 1) k *= 10;
+ return k;
+ }
+ d3.requote = function(s) {
+ return s.replace(d3_requote_re, "\\$&");
+ };
+ var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
+ d3.round = function(x, n) {
+ return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x);
+ };
+ d3.xhr = function(url, mimeType, callback) {
+ var xhr = {}, dispatch = d3.dispatch("progress", "load", "error"), headers = {}, response = d3_identity, request = new (window.XDomainRequest && /^(http(s)?:)?\/\//.test(url) ? XDomainRequest : XMLHttpRequest)();
+ "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() {
+ request.readyState > 3 && respond();
+ };
+ function respond() {
+ var s = request.status;
+ !s && request.responseText || s >= 200 && s < 300 || s === 304 ? dispatch.load.call(xhr, response.call(xhr, request)) : dispatch.error.call(xhr, request);
+ }
+ request.onprogress = function(event) {
+ var o = d3.event;
+ d3.event = event;
+ try {
+ dispatch.progress.call(xhr, request);
+ } finally {
+ d3.event = o;
+ }
+ };
+ xhr.header = function(name, value) {
+ name = (name + "").toLowerCase();
+ if (arguments.length < 2) return headers[name];
+ if (value == null) delete headers[name]; else headers[name] = value + "";
+ return xhr;
+ };
+ xhr.mimeType = function(value) {
+ if (!arguments.length) return mimeType;
+ mimeType = value == null ? null : value + "";
+ return xhr;
+ };
+ xhr.response = function(value) {
+ response = value;
+ return xhr;
+ };
+ [ "get", "post" ].forEach(function(method) {
+ xhr[method] = function() {
+ return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments)));
+ };
+ });
+ xhr.send = function(method, data, callback) {
+ if (arguments.length === 2 && typeof data === "function") callback = data, data = null;
+ request.open(method, url, true);
+ if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*";
+ if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]);
+ if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType);
+ if (callback != null) xhr.on("error", callback).on("load", function(request) {
+ callback(null, request);
+ });
+ request.send(data == null ? null : data);
+ return xhr;
+ };
+ xhr.abort = function() {
+ request.abort();
+ return xhr;
+ };
+ d3.rebind(xhr, dispatch, "on");
+ if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType,
+ mimeType = null;
+ return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback));
+ };
+ function d3_xhr_fixCallback(callback) {
+ return callback.length === 1 ? function(error, request) {
+ callback(error == null ? request : null);
+ } : callback;
+ }
+ d3.text = function() {
+ return d3.xhr.apply(d3, arguments).response(d3_text);
+ };
+ function d3_text(request) {
+ return request.responseText;
+ }
+ d3.json = function(url, callback) {
+ return d3.xhr(url, "application/json", callback).response(d3_json);
+ };
+ function d3_json(request) {
+ return JSON.parse(request.responseText);
+ }
+ d3.html = function(url, callback) {
+ return d3.xhr(url, "text/html", callback).response(d3_html);
+ };
+ function d3_html(request) {
+ var range = document.createRange();
+ range.selectNode(document.body);
+ return range.createContextualFragment(request.responseText);
+ }
+ d3.xml = function() {
+ return d3.xhr.apply(d3, arguments).response(d3_xml);
+ };
+ function d3_xml(request) {
+ return request.responseXML;
+ }
+ var d3_nsPrefix = {
+ svg: "http://www.w3.org/2000/svg",
+ xhtml: "http://www.w3.org/1999/xhtml",
+ xlink: "http://www.w3.org/1999/xlink",
+ xml: "http://www.w3.org/XML/1998/namespace",
+ xmlns: "http://www.w3.org/2000/xmlns/"
+ };
+ d3.ns = {
+ prefix: d3_nsPrefix,
+ qualify: function(name) {
+ var i = name.indexOf(":"), prefix = name;
+ if (i >= 0) {
+ prefix = name.substring(0, i);
+ name = name.substring(i + 1);
+ }
+ return d3_nsPrefix.hasOwnProperty(prefix) ? {
+ space: d3_nsPrefix[prefix],
+ local: name
+ } : name;
+ }
+ };
+ d3.dispatch = function() {
+ var dispatch = new d3_dispatch(), i = -1, n = arguments.length;
+ while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
+ return dispatch;
+ };
+ function d3_dispatch() {}
+ d3_dispatch.prototype.on = function(type, listener) {
+ var i = type.indexOf("."), name = "";
+ if (i > 0) {
+ name = type.substring(i + 1);
+ type = type.substring(0, i);
+ }
+ return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener);
+ };
+ function d3_dispatch_event(dispatch) {
+ var listeners = [], listenerByName = new d3_Map();
+ function event() {
+ var z = listeners, i = -1, n = z.length, l;
+ while (++i < n) if (l = z[i].on) l.apply(this, arguments);
+ return dispatch;
+ }
+ event.on = function(name, listener) {
+ var l = listenerByName.get(name), i;
+ if (arguments.length < 2) return l && l.on;
+ if (l) {
+ l.on = null;
+ listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
+ listenerByName.remove(name);
+ }
+ if (listener) listeners.push(listenerByName.set(name, {
+ on: listener
+ }));
+ return dispatch;
+ };
+ return event;
+ }
+ d3.format = function(specifier) {
+ var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", basePrefix = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false;
+ if (precision) precision = +precision.substring(1);
+ if (zfill || fill === "0" && align === "=") {
+ zfill = fill = "0";
+ align = "=";
+ if (comma) width -= Math.floor((width - 1) / 4);
+ }
+ switch (type) {
+ case "n":
+ comma = true;
+ type = "g";
+ break;
+
+ case "%":
+ scale = 100;
+ suffix = "%";
+ type = "f";
+ break;
+
+ case "p":
+ scale = 100;
+ suffix = "%";
+ type = "r";
+ break;
+
+ case "b":
+ case "o":
+ case "x":
+ case "X":
+ if (basePrefix) basePrefix = "0" + type.toLowerCase();
+
+ case "c":
+ case "d":
+ integer = true;
+ precision = 0;
+ break;
+
+ case "s":
+ scale = -1;
+ type = "r";
+ break;
+ }
+ if (basePrefix === "#") basePrefix = "";
+ if (type == "r" && !precision) type = "g";
+ type = d3_format_types.get(type) || d3_format_typeDefault;
+ var zcomma = zfill && comma;
+ return function(value) {
+ if (integer && value % 1) return "";
+ var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign;
+ if (scale < 0) {
+ var prefix = d3.formatPrefix(value, precision);
+ value = prefix.scale(value);
+ suffix = prefix.symbol;
+ } else {
+ value *= scale;
+ }
+ value = type(value, precision);
+ if (!zfill && comma) value = d3_format_group(value);
+ var length = basePrefix.length + value.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : "";
+ if (zcomma) value = d3_format_group(padding + value);
+ if (d3_format_decimalPoint) value.replace(".", d3_format_decimalPoint);
+ negative += basePrefix;
+ return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + suffix;
+ };
+ };
+ var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/;
+ var d3_format_types = d3.map({
+ b: function(x) {
+ return x.toString(2);
+ },
+ c: function(x) {
+ return String.fromCharCode(x);
+ },
+ o: function(x) {
+ return x.toString(8);
+ },
+ x: function(x) {
+ return x.toString(16);
+ },
+ X: function(x) {
+ return x.toString(16).toUpperCase();
+ },
+ g: function(x, p) {
+ return x.toPrecision(p);
+ },
+ e: function(x, p) {
+ return x.toExponential(p);
+ },
+ f: function(x, p) {
+ return x.toFixed(p);
+ },
+ r: function(x, p) {
+ return d3.round(x, p = d3_format_precision(x, p)).toFixed(Math.max(0, Math.min(20, p)));
+ }
+ });
+ function d3_format_precision(x, p) {
+ return p - (x ? 1 + Math.floor(Math.log(x + Math.pow(10, 1 + Math.floor(Math.log(x) / Math.LN10) - p)) / Math.LN10) : 1);
+ }
+ function d3_format_typeDefault(x) {
+ return x + "";
+ }
+ var d3_format_group = d3_identity;
+ if (d3_format_grouping) {
+ var d3_format_groupingLength = d3_format_grouping.length;
+ d3_format_group = function(value) {
+ var i = value.lastIndexOf("."), f = i >= 0 ? "." + value.substring(i + 1) : (i = value.length,
+ ""), t = [], j = 0, g = d3_format_grouping[0];
+ while (i > 0 && g > 0) {
+ t.push(value.substring(i -= g, i + g));
+ g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength];
+ }
+ return t.reverse().join(d3_format_thousandsSeparator || "") + f;
+ };
+ }
+ var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "μ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix);
+ d3.formatPrefix = function(value, precision) {
+ var i = 0;
+ if (value) {
+ if (value < 0) value *= -1;
+ if (precision) value = d3.round(value, d3_format_precision(value, precision));
+ i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
+ i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3));
+ }
+ return d3_formatPrefixes[8 + i / 3];
+ };
+ function d3_formatPrefix(d, i) {
+ var k = Math.pow(10, Math.abs(8 - i) * 3);
+ return {
+ scale: i > 8 ? function(d) {
+ return d / k;
+ } : function(d) {
+ return d * k;
+ },
+ symbol: d
+ };
+ }
+ var d3_ease_default = function() {
+ return d3_identity;
+ };
+ var d3_ease = d3.map({
+ linear: d3_ease_default,
+ poly: d3_ease_poly,
+ quad: function() {
+ return d3_ease_quad;
+ },
+ cubic: function() {
+ return d3_ease_cubic;
+ },
+ sin: function() {
+ return d3_ease_sin;
+ },
+ exp: function() {
+ return d3_ease_exp;
+ },
+ circle: function() {
+ return d3_ease_circle;
+ },
+ elastic: d3_ease_elastic,
+ back: d3_ease_back,
+ bounce: function() {
+ return d3_ease_bounce;
+ }
+ });
+ var d3_ease_mode = d3.map({
+ "in": d3_identity,
+ out: d3_ease_reverse,
+ "in-out": d3_ease_reflect,
+ "out-in": function(f) {
+ return d3_ease_reflect(d3_ease_reverse(f));
+ }
+ });
+ d3.ease = function(name) {
+ var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in";
+ t = d3_ease.get(t) || d3_ease_default;
+ m = d3_ease_mode.get(m) || d3_identity;
+ return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1))));
+ };
+ function d3_ease_clamp(f) {
+ return function(t) {
+ return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
+ };
+ }
+ function d3_ease_reverse(f) {
+ return function(t) {
+ return 1 - f(1 - t);
+ };
+ }
+ function d3_ease_reflect(f) {
+ return function(t) {
+ return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t));
+ };
+ }
+ function d3_ease_quad(t) {
+ return t * t;
+ }
+ function d3_ease_cubic(t) {
+ return t * t * t;
+ }
+ function d3_ease_cubicInOut(t) {
+ if (t <= 0) return 0;
+ if (t >= 1) return 1;
+ var t2 = t * t, t3 = t2 * t;
+ return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
+ }
+ function d3_ease_poly(e) {
+ return function(t) {
+ return Math.pow(t, e);
+ };
+ }
+ function d3_ease_sin(t) {
+ return 1 - Math.cos(t * π / 2);
+ }
+ function d3_ease_exp(t) {
+ return Math.pow(2, 10 * (t - 1));
+ }
+ function d3_ease_circle(t) {
+ return 1 - Math.sqrt(1 - t * t);
+ }
+ function d3_ease_elastic(a, p) {
+ var s;
+ if (arguments.length < 2) p = .45;
+ if (arguments.length) s = p / (2 * π) * Math.asin(1 / a); else a = 1, s = p / 4;
+ return function(t) {
+ return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * π / p);
+ };
+ }
+ function d3_ease_back(s) {
+ if (!s) s = 1.70158;
+ return function(t) {
+ return t * t * ((s + 1) * t - s);
+ };
+ }
+ function d3_ease_bounce(t) {
+ return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
+ }
+ d3.event = null;
+ function d3_eventCancel() {
+ d3.event.stopPropagation();
+ d3.event.preventDefault();
+ }
+ function d3_eventSource() {
+ var e = d3.event, s;
+ while (s = e.sourceEvent) e = s;
+ return e;
+ }
+ function d3_eventDispatch(target) {
+ var dispatch = new d3_dispatch(), i = 0, n = arguments.length;
+ while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
+ dispatch.of = function(thiz, argumentz) {
+ return function(e1) {
+ try {
+ var e0 = e1.sourceEvent = d3.event;
+ e1.target = target;
+ d3.event = e1;
+ dispatch[e1.type].apply(thiz, argumentz);
+ } finally {
+ d3.event = e0;
+ }
+ };
+ };
+ return dispatch;
+ }
+ d3.transform = function(string) {
+ var g = document.createElementNS(d3.ns.prefix.svg, "g");
+ return (d3.transform = function(string) {
+ g.setAttribute("transform", string);
+ var t = g.transform.baseVal.consolidate();
+ return new d3_transform(t ? t.matrix : d3_transformIdentity);
+ })(string);
+ };
+ function d3_transform(m) {
+ var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0;
+ if (r0[0] * r1[1] < r1[0] * r0[1]) {
+ r0[0] *= -1;
+ r0[1] *= -1;
+ kx *= -1;
+ kz *= -1;
+ }
+ this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees;
+ this.translate = [ m.e, m.f ];
+ this.scale = [ kx, ky ];
+ this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0;
+ }
+ d3_transform.prototype.toString = function() {
+ return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")";
+ };
+ function d3_transformDot(a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+ }
+ function d3_transformNormalize(a) {
+ var k = Math.sqrt(d3_transformDot(a, a));
+ if (k) {
+ a[0] /= k;
+ a[1] /= k;
+ }
+ return k;
+ }
+ function d3_transformCombine(a, b, k) {
+ a[0] += k * b[0];
+ a[1] += k * b[1];
+ return a;
+ }
+ var d3_transformIdentity = {
+ a: 1,
+ b: 0,
+ c: 0,
+ d: 1,
+ e: 0,
+ f: 0
+ };
+ d3.interpolate = function(a, b) {
+ var i = d3.interpolators.length, f;
+ while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ;
+ return f;
+ };
+ d3.interpolateNumber = function(a, b) {
+ b -= a;
+ return function(t) {
+ return a + b * t;
+ };
+ };
+ d3.interpolateRound = function(a, b) {
+ b -= a;
+ return function(t) {
+ return Math.round(a + b * t);
+ };
+ };
+ d3.interpolateString = function(a, b) {
+ var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o;
+ d3_interpolate_number.lastIndex = 0;
+ for (i = 0; m = d3_interpolate_number.exec(b); ++i) {
+ if (m.index) s.push(b.substring(s0, s1 = m.index));
+ q.push({
+ i: s.length,
+ x: m[0]
+ });
+ s.push(null);
+ s0 = d3_interpolate_number.lastIndex;
+ }
+ if (s0 < b.length) s.push(b.substring(s0));
+ for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) {
+ o = q[i];
+ if (o.x == m[0]) {
+ if (o.i) {
+ if (s[o.i + 1] == null) {
+ s[o.i - 1] += o.x;
+ s.splice(o.i, 1);
+ for (j = i + 1; j < n; ++j) q[j].i--;
+ } else {
+ s[o.i - 1] += o.x + s[o.i + 1];
+ s.splice(o.i, 2);
+ for (j = i + 1; j < n; ++j) q[j].i -= 2;
+ }
+ } else {
+ if (s[o.i + 1] == null) {
+ s[o.i] = o.x;
+ } else {
+ s[o.i] = o.x + s[o.i + 1];
+ s.splice(o.i + 1, 1);
+ for (j = i + 1; j < n; ++j) q[j].i--;
+ }
+ }
+ q.splice(i, 1);
+ n--;
+ i--;
+ } else {
+ o.x = d3.interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
+ }
+ }
+ while (i < n) {
+ o = q.pop();
+ if (s[o.i + 1] == null) {
+ s[o.i] = o.x;
+ } else {
+ s[o.i] = o.x + s[o.i + 1];
+ s.splice(o.i + 1, 1);
+ }
+ n--;
+ }
+ if (s.length === 1) {
+ return s[0] == null ? q[0].x : function() {
+ return b;
+ };
+ }
+ return function(t) {
+ for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t);
+ return s.join("");
+ };
+ };
+ d3.interpolateTransform = function(a, b) {
+ var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale;
+ if (ta[0] != tb[0] || ta[1] != tb[1]) {
+ s.push("translate(", null, ",", null, ")");
+ q.push({
+ i: 1,
+ x: d3.interpolateNumber(ta[0], tb[0])
+ }, {
+ i: 3,
+ x: d3.interpolateNumber(ta[1], tb[1])
+ });
+ } else if (tb[0] || tb[1]) {
+ s.push("translate(" + tb + ")");
+ } else {
+ s.push("");
+ }
+ if (ra != rb) {
+ if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360;
+ q.push({
+ i: s.push(s.pop() + "rotate(", null, ")") - 2,
+ x: d3.interpolateNumber(ra, rb)
+ });
+ } else if (rb) {
+ s.push(s.pop() + "rotate(" + rb + ")");
+ }
+ if (wa != wb) {
+ q.push({
+ i: s.push(s.pop() + "skewX(", null, ")") - 2,
+ x: d3.interpolateNumber(wa, wb)
+ });
+ } else if (wb) {
+ s.push(s.pop() + "skewX(" + wb + ")");
+ }
+ if (ka[0] != kb[0] || ka[1] != kb[1]) {
+ n = s.push(s.pop() + "scale(", null, ",", null, ")");
+ q.push({
+ i: n - 4,
+ x: d3.interpolateNumber(ka[0], kb[0])
+ }, {
+ i: n - 2,
+ x: d3.interpolateNumber(ka[1], kb[1])
+ });
+ } else if (kb[0] != 1 || kb[1] != 1) {
+ s.push(s.pop() + "scale(" + kb + ")");
+ }
+ n = q.length;
+ return function(t) {
+ var i = -1, o;
+ while (++i < n) s[(o = q[i]).i] = o.x(t);
+ return s.join("");
+ };
+ };
+ d3.interpolateRgb = function(a, b) {
+ a = d3.rgb(a);
+ b = d3.rgb(b);
+ var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab;
+ return function(t) {
+ return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t));
+ };
+ };
+ d3.interpolateHsl = function(a, b) {
+ a = d3.hsl(a);
+ b = d3.hsl(b);
+ var h0 = a.h, s0 = a.s, l0 = a.l, h1 = b.h - h0, s1 = b.s - s0, l1 = b.l - l0;
+ if (h1 > 180) h1 -= 360; else if (h1 < -180) h1 += 360;
+ return function(t) {
+ return d3_hsl_rgb(h0 + h1 * t, s0 + s1 * t, l0 + l1 * t) + "";
+ };
+ };
+ d3.interpolateLab = function(a, b) {
+ a = d3.lab(a);
+ b = d3.lab(b);
+ var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab;
+ return function(t) {
+ return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + "";
+ };
+ };
+ d3.interpolateHcl = function(a, b) {
+ a = d3.hcl(a);
+ b = d3.hcl(b);
+ var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al;
+ if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;
+ return function(t) {
+ return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + "";
+ };
+ };
+ d3.interpolateArray = function(a, b) {
+ var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i;
+ for (i = 0; i < n0; ++i) x.push(d3.interpolate(a[i], b[i]));
+ for (;i < na; ++i) c[i] = a[i];
+ for (;i < nb; ++i) c[i] = b[i];
+ return function(t) {
+ for (i = 0; i < n0; ++i) c[i] = x[i](t);
+ return c;
+ };
+ };
+ d3.interpolateObject = function(a, b) {
+ var i = {}, c = {}, k;
+ for (k in a) {
+ if (k in b) {
+ i[k] = d3_interpolateByName(k)(a[k], b[k]);
+ } else {
+ c[k] = a[k];
+ }
+ }
+ for (k in b) {
+ if (!(k in a)) {
+ c[k] = b[k];
+ }
+ }
+ return function(t) {
+ for (k in i) c[k] = i[k](t);
+ return c;
+ };
+ };
+ var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
+ function d3_interpolateByName(name) {
+ return name == "transform" ? d3.interpolateTransform : d3.interpolate;
+ }
+ d3.interpolators = [ d3.interpolateObject, function(a, b) {
+ return b instanceof Array && d3.interpolateArray(a, b);
+ }, function(a, b) {
+ return (typeof a === "string" || typeof b === "string") && d3.interpolateString(a + "", b + "");
+ }, function(a, b) {
+ return (typeof b === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Color) && d3.interpolateRgb(a, b);
+ }, function(a, b) {
+ return !isNaN(a = +a) && !isNaN(b = +b) && d3.interpolateNumber(a, b);
+ } ];
+ function d3_uninterpolateNumber(a, b) {
+ b = b - (a = +a) ? 1 / (b - a) : 0;
+ return function(x) {
+ return (x - a) * b;
+ };
+ }
+ function d3_uninterpolateClamp(a, b) {
+ b = b - (a = +a) ? 1 / (b - a) : 0;
+ return function(x) {
+ return Math.max(0, Math.min(1, (x - a) * b));
+ };
+ }
+ function d3_Color() {}
+ d3_Color.prototype.toString = function() {
+ return this.rgb() + "";
+ };
+ d3.rgb = function(r, g, b) {
+ return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b);
+ };
+ function d3_rgb(r, g, b) {
+ return new d3_Rgb(r, g, b);
+ }
+ function d3_Rgb(r, g, b) {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ }
+ var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color();
+ d3_rgbPrototype.brighter = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ var r = this.r, g = this.g, b = this.b, i = 30;
+ if (!r && !g && !b) return d3_rgb(i, i, i);
+ if (r && r < i) r = i;
+ if (g && g < i) g = i;
+ if (b && b < i) b = i;
+ return d3_rgb(Math.min(255, Math.floor(r / k)), Math.min(255, Math.floor(g / k)), Math.min(255, Math.floor(b / k)));
+ };
+ d3_rgbPrototype.darker = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_rgb(Math.floor(k * this.r), Math.floor(k * this.g), Math.floor(k * this.b));
+ };
+ d3_rgbPrototype.hsl = function() {
+ return d3_rgb_hsl(this.r, this.g, this.b);
+ };
+ d3_rgbPrototype.toString = function() {
+ return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
+ };
+ function d3_rgb_hex(v) {
+ return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16);
+ }
+ function d3_rgb_parse(format, rgb, hsl) {
+ var r = 0, g = 0, b = 0, m1, m2, name;
+ m1 = /([a-z]+)\((.*)\)/i.exec(format);
+ if (m1) {
+ m2 = m1[2].split(",");
+ switch (m1[1]) {
+ case "hsl":
+ {
+ return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100);
+ }
+
+ case "rgb":
+ {
+ return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2]));
+ }
+ }
+ }
+ if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b);
+ if (format != null && format.charAt(0) === "#") {
+ if (format.length === 4) {
+ r = format.charAt(1);
+ r += r;
+ g = format.charAt(2);
+ g += g;
+ b = format.charAt(3);
+ b += b;
+ } else if (format.length === 7) {
+ r = format.substring(1, 3);
+ g = format.substring(3, 5);
+ b = format.substring(5, 7);
+ }
+ r = parseInt(r, 16);
+ g = parseInt(g, 16);
+ b = parseInt(b, 16);
+ }
+ return rgb(r, g, b);
+ }
+ function d3_rgb_hsl(r, g, b) {
+ var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2;
+ if (d) {
+ s = l < .5 ? d / (max + min) : d / (2 - max - min);
+ if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4;
+ h *= 60;
+ } else {
+ s = h = 0;
+ }
+ return d3_hsl(h, s, l);
+ }
+ function d3_rgb_lab(r, g, b) {
+ r = d3_rgb_xyz(r);
+ g = d3_rgb_xyz(g);
+ b = d3_rgb_xyz(b);
+ var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z);
+ return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
+ }
+ function d3_rgb_xyz(r) {
+ return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4);
+ }
+ function d3_rgb_parseNumber(c) {
+ var f = parseFloat(c);
+ return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
+ }
+ var d3_rgb_names = d3.map({
+ aliceblue: "#f0f8ff",
+ antiquewhite: "#faebd7",
+ aqua: "#00ffff",
+ aquamarine: "#7fffd4",
+ azure: "#f0ffff",
+ beige: "#f5f5dc",
+ bisque: "#ffe4c4",
+ black: "#000000",
+ blanchedalmond: "#ffebcd",
+ blue: "#0000ff",
+ blueviolet: "#8a2be2",
+ brown: "#a52a2a",
+ burlywood: "#deb887",
+ cadetblue: "#5f9ea0",
+ chartreuse: "#7fff00",
+ chocolate: "#d2691e",
+ coral: "#ff7f50",
+ cornflowerblue: "#6495ed",
+ cornsilk: "#fff8dc",
+ crimson: "#dc143c",
+ cyan: "#00ffff",
+ darkblue: "#00008b",
+ darkcyan: "#008b8b",
+ darkgoldenrod: "#b8860b",
+ darkgray: "#a9a9a9",
+ darkgreen: "#006400",
+ darkgrey: "#a9a9a9",
+ darkkhaki: "#bdb76b",
+ darkmagenta: "#8b008b",
+ darkolivegreen: "#556b2f",
+ darkorange: "#ff8c00",
+ darkorchid: "#9932cc",
+ darkred: "#8b0000",
+ darksalmon: "#e9967a",
+ darkseagreen: "#8fbc8f",
+ darkslateblue: "#483d8b",
+ darkslategray: "#2f4f4f",
+ darkslategrey: "#2f4f4f",
+ darkturquoise: "#00ced1",
+ darkviolet: "#9400d3",
+ deeppink: "#ff1493",
+ deepskyblue: "#00bfff",
+ dimgray: "#696969",
+ dimgrey: "#696969",
+ dodgerblue: "#1e90ff",
+ firebrick: "#b22222",
+ floralwhite: "#fffaf0",
+ forestgreen: "#228b22",
+ fuchsia: "#ff00ff",
+ gainsboro: "#dcdcdc",
+ ghostwhite: "#f8f8ff",
+ gold: "#ffd700",
+ goldenrod: "#daa520",
+ gray: "#808080",
+ green: "#008000",
+ greenyellow: "#adff2f",
+ grey: "#808080",
+ honeydew: "#f0fff0",
+ hotpink: "#ff69b4",
+ indianred: "#cd5c5c",
+ indigo: "#4b0082",
+ ivory: "#fffff0",
+ khaki: "#f0e68c",
+ lavender: "#e6e6fa",
+ lavenderblush: "#fff0f5",
+ lawngreen: "#7cfc00",
+ lemonchiffon: "#fffacd",
+ lightblue: "#add8e6",
+ lightcoral: "#f08080",
+ lightcyan: "#e0ffff",
+ lightgoldenrodyellow: "#fafad2",
+ lightgray: "#d3d3d3",
+ lightgreen: "#90ee90",
+ lightgrey: "#d3d3d3",
+ lightpink: "#ffb6c1",
+ lightsalmon: "#ffa07a",
+ lightseagreen: "#20b2aa",
+ lightskyblue: "#87cefa",
+ lightslategray: "#778899",
+ lightslategrey: "#778899",
+ lightsteelblue: "#b0c4de",
+ lightyellow: "#ffffe0",
+ lime: "#00ff00",
+ limegreen: "#32cd32",
+ linen: "#faf0e6",
+ magenta: "#ff00ff",
+ maroon: "#800000",
+ mediumaquamarine: "#66cdaa",
+ mediumblue: "#0000cd",
+ mediumorchid: "#ba55d3",
+ mediumpurple: "#9370db",
+ mediumseagreen: "#3cb371",
+ mediumslateblue: "#7b68ee",
+ mediumspringgreen: "#00fa9a",
+ mediumturquoise: "#48d1cc",
+ mediumvioletred: "#c71585",
+ midnightblue: "#191970",
+ mintcream: "#f5fffa",
+ mistyrose: "#ffe4e1",
+ moccasin: "#ffe4b5",
+ navajowhite: "#ffdead",
+ navy: "#000080",
+ oldlace: "#fdf5e6",
+ olive: "#808000",
+ olivedrab: "#6b8e23",
+ orange: "#ffa500",
+ orangered: "#ff4500",
+ orchid: "#da70d6",
+ palegoldenrod: "#eee8aa",
+ palegreen: "#98fb98",
+ paleturquoise: "#afeeee",
+ palevioletred: "#db7093",
+ papayawhip: "#ffefd5",
+ peachpuff: "#ffdab9",
+ peru: "#cd853f",
+ pink: "#ffc0cb",
+ plum: "#dda0dd",
+ powderblue: "#b0e0e6",
+ purple: "#800080",
+ red: "#ff0000",
+ rosybrown: "#bc8f8f",
+ royalblue: "#4169e1",
+ saddlebrown: "#8b4513",
+ salmon: "#fa8072",
+ sandybrown: "#f4a460",
+ seagreen: "#2e8b57",
+ seashell: "#fff5ee",
+ sienna: "#a0522d",
+ silver: "#c0c0c0",
+ skyblue: "#87ceeb",
+ slateblue: "#6a5acd",
+ slategray: "#708090",
+ slategrey: "#708090",
+ snow: "#fffafa",
+ springgreen: "#00ff7f",
+ steelblue: "#4682b4",
+ tan: "#d2b48c",
+ teal: "#008080",
+ thistle: "#d8bfd8",
+ tomato: "#ff6347",
+ turquoise: "#40e0d0",
+ violet: "#ee82ee",
+ wheat: "#f5deb3",
+ white: "#ffffff",
+ whitesmoke: "#f5f5f5",
+ yellow: "#ffff00",
+ yellowgreen: "#9acd32"
+ });
+ d3_rgb_names.forEach(function(key, value) {
+ d3_rgb_names.set(key, d3_rgb_parse(value, d3_rgb, d3_hsl_rgb));
+ });
+ d3.hsl = function(h, s, l) {
+ return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l);
+ };
+ function d3_hsl(h, s, l) {
+ return new d3_Hsl(h, s, l);
+ }
+ function d3_Hsl(h, s, l) {
+ this.h = h;
+ this.s = s;
+ this.l = l;
+ }
+ var d3_hslPrototype = d3_Hsl.prototype = new d3_Color();
+ d3_hslPrototype.brighter = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_hsl(this.h, this.s, this.l / k);
+ };
+ d3_hslPrototype.darker = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_hsl(this.h, this.s, k * this.l);
+ };
+ d3_hslPrototype.rgb = function() {
+ return d3_hsl_rgb(this.h, this.s, this.l);
+ };
+ function d3_hsl_rgb(h, s, l) {
+ var m1, m2;
+ h = h % 360;
+ if (h < 0) h += 360;
+ s = s < 0 ? 0 : s > 1 ? 1 : s;
+ l = l < 0 ? 0 : l > 1 ? 1 : l;
+ m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
+ m1 = 2 * l - m2;
+ function v(h) {
+ if (h > 360) h -= 360; else if (h < 0) h += 360;
+ if (h < 60) return m1 + (m2 - m1) * h / 60;
+ if (h < 180) return m2;
+ if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
+ return m1;
+ }
+ function vv(h) {
+ return Math.round(v(h) * 255);
+ }
+ return d3_rgb(vv(h + 120), vv(h), vv(h - 120));
+ }
+ d3.hcl = function(h, c, l) {
+ return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l);
+ };
+ function d3_hcl(h, c, l) {
+ return new d3_Hcl(h, c, l);
+ }
+ function d3_Hcl(h, c, l) {
+ this.h = h;
+ this.c = c;
+ this.l = l;
+ }
+ var d3_hclPrototype = d3_Hcl.prototype = new d3_Color();
+ d3_hclPrototype.brighter = function(k) {
+ return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)));
+ };
+ d3_hclPrototype.darker = function(k) {
+ return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)));
+ };
+ d3_hclPrototype.rgb = function() {
+ return d3_hcl_lab(this.h, this.c, this.l).rgb();
+ };
+ function d3_hcl_lab(h, c, l) {
+ return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);
+ }
+ d3.lab = function(l, a, b) {
+ return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b);
+ };
+ function d3_lab(l, a, b) {
+ return new d3_Lab(l, a, b);
+ }
+ function d3_Lab(l, a, b) {
+ this.l = l;
+ this.a = a;
+ this.b = b;
+ }
+ var d3_lab_K = 18;
+ var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883;
+ var d3_labPrototype = d3_Lab.prototype = new d3_Color();
+ d3_labPrototype.brighter = function(k) {
+ return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
+ };
+ d3_labPrototype.darker = function(k) {
+ return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
+ };
+ d3_labPrototype.rgb = function() {
+ return d3_lab_rgb(this.l, this.a, this.b);
+ };
+ function d3_lab_rgb(l, a, b) {
+ var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
+ x = d3_lab_xyz(x) * d3_lab_X;
+ y = d3_lab_xyz(y) * d3_lab_Y;
+ z = d3_lab_xyz(z) * d3_lab_Z;
+ return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z));
+ }
+ function d3_lab_hcl(l, a, b) {
+ return d3_hcl(Math.atan2(b, a) / π * 180, Math.sqrt(a * a + b * b), l);
+ }
+ function d3_lab_xyz(x) {
+ return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
+ }
+ function d3_xyz_lab(x) {
+ return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
+ }
+ function d3_xyz_rgb(r) {
+ return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055));
+ }
+ function d3_selection(groups) {
+ d3_arraySubclass(groups, d3_selectionPrototype);
+ return groups;
+ }
+ var d3_select = function(s, n) {
+ return n.querySelector(s);
+ }, d3_selectAll = function(s, n) {
+ return n.querySelectorAll(s);
+ }, d3_selectRoot = document.documentElement, d3_selectMatcher = d3_selectRoot.matchesSelector || d3_selectRoot.webkitMatchesSelector || d3_selectRoot.mozMatchesSelector || d3_selectRoot.msMatchesSelector || d3_selectRoot.oMatchesSelector, d3_selectMatches = function(n, s) {
+ return d3_selectMatcher.call(n, s);
+ };
+ if (typeof Sizzle === "function") {
+ d3_select = function(s, n) {
+ return Sizzle(s, n)[0] || null;
+ };
+ d3_selectAll = function(s, n) {
+ return Sizzle.uniqueSort(Sizzle(s, n));
+ };
+ d3_selectMatches = Sizzle.matchesSelector;
+ }
+ var d3_selectionPrototype = [];
+ d3.selection = function() {
+ return d3_selectionRoot;
+ };
+ d3.selection.prototype = d3_selectionPrototype;
+ d3_selectionPrototype.select = function(selector) {
+ var subgroups = [], subgroup, subnode, group, node;
+ if (typeof selector !== "function") selector = d3_selection_selector(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = (group = this[j]).parentNode;
+ for (var i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroup.push(subnode = selector.call(node, node.__data__, i));
+ if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_selection_selector(selector) {
+ return function() {
+ return d3_select(selector, this);
+ };
+ }
+ d3_selectionPrototype.selectAll = function(selector) {
+ var subgroups = [], subgroup, node;
+ if (typeof selector !== "function") selector = d3_selection_selectorAll(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i)));
+ subgroup.parentNode = node;
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_selection_selectorAll(selector) {
+ return function() {
+ return d3_selectAll(selector, this);
+ };
+ }
+ d3_selectionPrototype.attr = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") {
+ var node = this.node();
+ name = d3.ns.qualify(name);
+ return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name);
+ }
+ for (value in name) this.each(d3_selection_attr(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_attr(name, value));
+ };
+ function d3_selection_attr(name, value) {
+ name = d3.ns.qualify(name);
+ function attrNull() {
+ this.removeAttribute(name);
+ }
+ function attrNullNS() {
+ this.removeAttributeNS(name.space, name.local);
+ }
+ function attrConstant() {
+ this.setAttribute(name, value);
+ }
+ function attrConstantNS() {
+ this.setAttributeNS(name.space, name.local, value);
+ }
+ function attrFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.removeAttribute(name); else this.setAttribute(name, x);
+ }
+ function attrFunctionNS() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x);
+ }
+ return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant;
+ }
+ d3_selectionPrototype.classed = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") {
+ var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1;
+ if (value = node.classList) {
+ while (++i < n) if (!value.contains(name[i])) return false;
+ } else {
+ value = node.className;
+ if (value.baseVal != null) value = value.baseVal;
+ while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;
+ }
+ return true;
+ }
+ for (value in name) this.each(d3_selection_classed(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_classed(name, value));
+ };
+ function d3_selection_classedRe(name) {
+ return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g");
+ }
+ function d3_selection_classed(name, value) {
+ name = name.trim().split(/\s+/).map(d3_selection_classedName);
+ var n = name.length;
+ function classedConstant() {
+ var i = -1;
+ while (++i < n) name[i](this, value);
+ }
+ function classedFunction() {
+ var i = -1, x = value.apply(this, arguments);
+ while (++i < n) name[i](this, x);
+ }
+ return typeof value === "function" ? classedFunction : classedConstant;
+ }
+ function d3_selection_classedName(name) {
+ var re = d3_selection_classedRe(name);
+ return function(node, value) {
+ if (c = node.classList) return value ? c.add(name) : c.remove(name);
+ var c = node.className, cb = c.baseVal != null, cv = cb ? c.baseVal : c;
+ if (value) {
+ re.lastIndex = 0;
+ if (!re.test(cv)) {
+ cv = d3_collapse(cv + " " + name);
+ if (cb) c.baseVal = cv; else node.className = cv;
+ }
+ } else if (cv) {
+ cv = d3_collapse(cv.replace(re, " "));
+ if (cb) c.baseVal = cv; else node.className = cv;
+ }
+ };
+ }
+ d3_selectionPrototype.style = function(name, value, priority) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof name !== "string") {
+ if (n < 2) value = "";
+ for (priority in name) this.each(d3_selection_style(priority, name[priority], value));
+ return this;
+ }
+ if (n < 2) return getComputedStyle(this.node(), null).getPropertyValue(name);
+ priority = "";
+ }
+ return this.each(d3_selection_style(name, value, priority));
+ };
+ function d3_selection_style(name, value, priority) {
+ function styleNull() {
+ this.style.removeProperty(name);
+ }
+ function styleConstant() {
+ this.style.setProperty(name, value, priority);
+ }
+ function styleFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority);
+ }
+ return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant;
+ }
+ d3_selectionPrototype.property = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") return this.node()[name];
+ for (value in name) this.each(d3_selection_property(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_property(name, value));
+ };
+ function d3_selection_property(name, value) {
+ function propertyNull() {
+ delete this[name];
+ }
+ function propertyConstant() {
+ this[name] = value;
+ }
+ function propertyFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) delete this[name]; else this[name] = x;
+ }
+ return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant;
+ }
+ d3_selectionPrototype.text = function(value) {
+ return arguments.length ? this.each(typeof value === "function" ? function() {
+ var v = value.apply(this, arguments);
+ this.textContent = v == null ? "" : v;
+ } : value == null ? function() {
+ this.textContent = "";
+ } : function() {
+ this.textContent = value;
+ }) : this.node().textContent;
+ };
+ d3_selectionPrototype.html = function(value) {
+ return arguments.length ? this.each(typeof value === "function" ? function() {
+ var v = value.apply(this, arguments);
+ this.innerHTML = v == null ? "" : v;
+ } : value == null ? function() {
+ this.innerHTML = "";
+ } : function() {
+ this.innerHTML = value;
+ }) : this.node().innerHTML;
+ };
+ d3_selectionPrototype.append = function(name) {
+ name = d3.ns.qualify(name);
+ function append() {
+ return this.appendChild(document.createElementNS(this.namespaceURI, name));
+ }
+ function appendNS() {
+ return this.appendChild(document.createElementNS(name.space, name.local));
+ }
+ return this.select(name.local ? appendNS : append);
+ };
+ d3_selectionPrototype.insert = function(name, before) {
+ name = d3.ns.qualify(name);
+ function insert() {
+ return this.insertBefore(document.createElementNS(this.namespaceURI, name), d3_select(before, this));
+ }
+ function insertNS() {
+ return this.insertBefore(document.createElementNS(name.space, name.local), d3_select(before, this));
+ }
+ return this.select(name.local ? insertNS : insert);
+ };
+ d3_selectionPrototype.remove = function() {
+ return this.each(function() {
+ var parent = this.parentNode;
+ if (parent) parent.removeChild(this);
+ });
+ };
+ d3_selectionPrototype.data = function(value, key) {
+ var i = -1, n = this.length, group, node;
+ if (!arguments.length) {
+ value = new Array(n = (group = this[0]).length);
+ while (++i < n) {
+ if (node = group[i]) {
+ value[i] = node.__data__;
+ }
+ }
+ return value;
+ }
+ function bind(group, groupData) {
+ var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData;
+ if (key) {
+ var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue;
+ for (i = -1; ++i < n; ) {
+ keyValue = key.call(node = group[i], node.__data__, i);
+ if (nodeByKeyValue.has(keyValue)) {
+ exitNodes[i] = node;
+ } else {
+ nodeByKeyValue.set(keyValue, node);
+ }
+ keyValues.push(keyValue);
+ }
+ for (i = -1; ++i < m; ) {
+ keyValue = key.call(groupData, nodeData = groupData[i], i);
+ if (node = nodeByKeyValue.get(keyValue)) {
+ updateNodes[i] = node;
+ node.__data__ = nodeData;
+ } else if (!dataByKeyValue.has(keyValue)) {
+ enterNodes[i] = d3_selection_dataNode(nodeData);
+ }
+ dataByKeyValue.set(keyValue, nodeData);
+ nodeByKeyValue.remove(keyValue);
+ }
+ for (i = -1; ++i < n; ) {
+ if (nodeByKeyValue.has(keyValues[i])) {
+ exitNodes[i] = group[i];
+ }
+ }
+ } else {
+ for (i = -1; ++i < n0; ) {
+ node = group[i];
+ nodeData = groupData[i];
+ if (node) {
+ node.__data__ = nodeData;
+ updateNodes[i] = node;
+ } else {
+ enterNodes[i] = d3_selection_dataNode(nodeData);
+ }
+ }
+ for (;i < m; ++i) {
+ enterNodes[i] = d3_selection_dataNode(groupData[i]);
+ }
+ for (;i < n; ++i) {
+ exitNodes[i] = group[i];
+ }
+ }
+ enterNodes.update = updateNodes;
+ enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode;
+ enter.push(enterNodes);
+ update.push(updateNodes);
+ exit.push(exitNodes);
+ }
+ var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]);
+ if (typeof value === "function") {
+ while (++i < n) {
+ bind(group = this[i], value.call(group, group.parentNode.__data__, i));
+ }
+ } else {
+ while (++i < n) {
+ bind(group = this[i], value);
+ }
+ }
+ update.enter = function() {
+ return enter;
+ };
+ update.exit = function() {
+ return exit;
+ };
+ return update;
+ };
+ function d3_selection_dataNode(data) {
+ return {
+ __data__: data
+ };
+ }
+ d3_selectionPrototype.datum = function(value) {
+ return arguments.length ? this.property("__data__", value) : this.property("__data__");
+ };
+ d3_selectionPrototype.filter = function(filter) {
+ var subgroups = [], subgroup, group, node;
+ if (typeof filter !== "function") filter = d3_selection_filter(filter);
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = (group = this[j]).parentNode;
+ for (var i = 0, n = group.length; i < n; i++) {
+ if ((node = group[i]) && filter.call(node, node.__data__, i)) {
+ subgroup.push(node);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_selection_filter(selector) {
+ return function() {
+ return d3_selectMatches(this, selector);
+ };
+ }
+ d3_selectionPrototype.order = function() {
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) {
+ if (node = group[i]) {
+ if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
+ next = node;
+ }
+ }
+ }
+ return this;
+ };
+ d3_selectionPrototype.sort = function(comparator) {
+ comparator = d3_selection_sortComparator.apply(this, arguments);
+ for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator);
+ return this.order();
+ };
+ function d3_selection_sortComparator(comparator) {
+ if (!arguments.length) comparator = d3.ascending;
+ return function(a, b) {
+ return comparator(a && a.__data__, b && b.__data__);
+ };
+ }
+ d3_selectionPrototype.on = function(type, listener, capture) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof type !== "string") {
+ if (n < 2) listener = false;
+ for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
+ return this;
+ }
+ if (n < 2) return (n = this.node()["__on" + type]) && n._;
+ capture = false;
+ }
+ return this.each(d3_selection_on(type, listener, capture));
+ };
+ function d3_selection_on(type, listener, capture) {
+ var name = "__on" + type, i = type.indexOf(".");
+ if (i > 0) type = type.substring(0, i);
+ function onRemove() {
+ var wrapper = this[name];
+ if (wrapper) {
+ this.removeEventListener(type, wrapper, wrapper.$);
+ delete this[name];
+ }
+ }
+ function onAdd() {
+ var node = this, args = d3_array(arguments);
+ onRemove.call(this);
+ this.addEventListener(type, this[name] = wrapper, wrapper.$ = capture);
+ wrapper._ = listener;
+ function wrapper(e) {
+ var o = d3.event;
+ d3.event = e;
+ args[0] = node.__data__;
+ try {
+ listener.apply(node, args);
+ } finally {
+ d3.event = o;
+ }
+ }
+ }
+ return listener ? onAdd : onRemove;
+ }
+ d3_selectionPrototype.each = function(callback) {
+ return d3_selection_each(this, function(node, i, j) {
+ callback.call(node, node.__data__, i, j);
+ });
+ };
+ function d3_selection_each(groups, callback) {
+ for (var j = 0, m = groups.length; j < m; j++) {
+ for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
+ if (node = group[i]) callback(node, i, j);
+ }
+ }
+ return groups;
+ }
+ d3_selectionPrototype.call = function(callback) {
+ var args = d3_array(arguments);
+ callback.apply(args[0] = this, args);
+ return this;
+ };
+ d3_selectionPrototype.empty = function() {
+ return !this.node();
+ };
+ d3_selectionPrototype.node = function() {
+ for (var j = 0, m = this.length; j < m; j++) {
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ var node = group[i];
+ if (node) return node;
+ }
+ }
+ return null;
+ };
+ d3_selectionPrototype.transition = function() {
+ var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = Object.create(d3_transitionInherit);
+ transition.time = Date.now();
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) d3_transitionNode(node, i, id, transition);
+ subgroup.push(node);
+ }
+ }
+ return d3_transition(subgroups, id);
+ };
+ var d3_selectionRoot = d3_selection([ [ document ] ]);
+ d3_selectionRoot[0].parentNode = d3_selectRoot;
+ d3.select = function(selector) {
+ return typeof selector === "string" ? d3_selectionRoot.select(selector) : d3_selection([ [ selector ] ]);
+ };
+ d3.selectAll = function(selector) {
+ return typeof selector === "string" ? d3_selectionRoot.selectAll(selector) : d3_selection([ d3_array(selector) ]);
+ };
+ function d3_selection_enter(selection) {
+ d3_arraySubclass(selection, d3_selection_enterPrototype);
+ return selection;
+ }
+ var d3_selection_enterPrototype = [];
+ d3.selection.enter = d3_selection_enter;
+ d3.selection.enter.prototype = d3_selection_enterPrototype;
+ d3_selection_enterPrototype.append = d3_selectionPrototype.append;
+ d3_selection_enterPrototype.insert = d3_selectionPrototype.insert;
+ d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
+ d3_selection_enterPrototype.node = d3_selectionPrototype.node;
+ d3_selection_enterPrototype.select = function(selector) {
+ var subgroups = [], subgroup, subnode, upgroup, group, node;
+ for (var j = -1, m = this.length; ++j < m; ) {
+ upgroup = (group = this[j]).update;
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = group.parentNode;
+ for (var i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i));
+ subnode.__data__ = node.__data__;
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_transition(groups, id) {
+ d3_arraySubclass(groups, d3_transitionPrototype);
+ groups.id = id;
+ return groups;
+ }
+ var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit = {
+ ease: d3_ease_cubicInOut,
+ delay: 0,
+ duration: 250
+ };
+ d3_transitionPrototype.call = d3_selectionPrototype.call;
+ d3_transitionPrototype.empty = d3_selectionPrototype.empty;
+ d3_transitionPrototype.node = d3_selectionPrototype.node;
+ d3.transition = function(selection) {
+ return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition();
+ };
+ d3.transition.prototype = d3_transitionPrototype;
+ function d3_transitionNode(node, i, id, inherit) {
+ var lock = node.__transition__ || (node.__transition__ = {
+ active: 0,
+ count: 0
+ }), transition = lock[id];
+ if (!transition) {
+ var time = inherit.time;
+ transition = lock[id] = {
+ tween: new d3_Map(),
+ event: d3.dispatch("start", "end"),
+ time: time,
+ ease: inherit.ease,
+ delay: inherit.delay,
+ duration: inherit.duration
+ };
+ ++lock.count;
+ d3.timer(function(elapsed) {
+ var d = node.__data__, ease = transition.ease, event = transition.event, delay = transition.delay, duration = transition.duration, tweened = [];
+ return delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time), 1;
+ function start(elapsed) {
+ if (lock.active > id) return stop();
+ lock.active = id;
+ event.start.call(node, d, i);
+ transition.tween.forEach(function(key, value) {
+ if (value = value.call(node, d, i)) {
+ tweened.push(value);
+ }
+ });
+ if (!tick(elapsed)) d3.timer(tick, 0, time);
+ return 1;
+ }
+ function tick(elapsed) {
+ if (lock.active !== id) return stop();
+ var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length;
+ while (n > 0) {
+ tweened[--n].call(node, e);
+ }
+ if (t >= 1) {
+ stop();
+ event.end.call(node, d, i);
+ return 1;
+ }
+ }
+ function stop() {
+ if (--lock.count) delete lock[id]; else delete node.__transition__;
+ return 1;
+ }
+ }, 0, time);
+ return transition;
+ }
+ }
+ d3_transitionPrototype.select = function(selector) {
+ var id = this.id, subgroups = [], subgroup, subnode, node;
+ if (typeof selector !== "function") selector = d3_selection_selector(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i))) {
+ if ("__data__" in node) subnode.__data__ = node.__data__;
+ d3_transitionNode(subnode, i, id, node.__transition__[id]);
+ subgroup.push(subnode);
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
+ return d3_transition(subgroups, id);
+ };
+ d3_transitionPrototype.selectAll = function(selector) {
+ var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition;
+ if (typeof selector !== "function") selector = d3_selection_selectorAll(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ transition = node.__transition__[id];
+ subnodes = selector.call(node, node.__data__, i);
+ subgroups.push(subgroup = []);
+ for (var k = -1, o = subnodes.length; ++k < o; ) {
+ d3_transitionNode(subnode = subnodes[k], k, id, transition);
+ subgroup.push(subnode);
+ }
+ }
+ }
+ }
+ return d3_transition(subgroups, id);
+ };
+ d3_transitionPrototype.filter = function(filter) {
+ var subgroups = [], subgroup, group, node;
+ if (typeof filter !== "function") filter = d3_selection_filter(filter);
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ if ((node = group[i]) && filter.call(node, node.__data__, i)) {
+ subgroup.push(node);
+ }
+ }
+ }
+ return d3_transition(subgroups, this.id, this.time).ease(this.ease());
+ };
+ d3_transitionPrototype.attr = function(nameNS, value) {
+ if (arguments.length < 2) {
+ for (value in nameNS) this.attr(value, nameNS[value]);
+ return this;
+ }
+ var interpolate = d3_interpolateByName(nameNS), name = d3.ns.qualify(nameNS);
+ function attrNull() {
+ this.removeAttribute(name);
+ }
+ function attrNullNS() {
+ this.removeAttributeNS(name.space, name.local);
+ }
+ return d3_transition_tween(this, "attr." + nameNS, value, function(b) {
+ function attrString() {
+ var a = this.getAttribute(name), i;
+ return a !== b && (i = interpolate(a, b), function(t) {
+ this.setAttribute(name, i(t));
+ });
+ }
+ function attrStringNS() {
+ var a = this.getAttributeNS(name.space, name.local), i;
+ return a !== b && (i = interpolate(a, b), function(t) {
+ this.setAttributeNS(name.space, name.local, i(t));
+ });
+ }
+ return b == null ? name.local ? attrNullNS : attrNull : (b += "", name.local ? attrStringNS : attrString);
+ });
+ };
+ d3_transitionPrototype.attrTween = function(nameNS, tween) {
+ var name = d3.ns.qualify(nameNS);
+ function attrTween(d, i) {
+ var f = tween.call(this, d, i, this.getAttribute(name));
+ return f && function(t) {
+ this.setAttribute(name, f(t));
+ };
+ }
+ function attrTweenNS(d, i) {
+ var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
+ return f && function(t) {
+ this.setAttributeNS(name.space, name.local, f(t));
+ };
+ }
+ return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
+ };
+ d3_transitionPrototype.style = function(name, value, priority) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof name !== "string") {
+ if (n < 2) value = "";
+ for (priority in name) this.style(priority, name[priority], value);
+ return this;
+ }
+ priority = "";
+ }
+ var interpolate = d3_interpolateByName(name);
+ function styleNull() {
+ this.style.removeProperty(name);
+ }
+ return d3_transition_tween(this, "style." + name, value, function(b) {
+ function styleString() {
+ var a = getComputedStyle(this, null).getPropertyValue(name), i;
+ return a !== b && (i = interpolate(a, b), function(t) {
+ this.style.setProperty(name, i(t), priority);
+ });
+ }
+ return b == null ? styleNull : (b += "", styleString);
+ });
+ };
+ d3_transitionPrototype.styleTween = function(name, tween, priority) {
+ if (arguments.length < 3) priority = "";
+ return this.tween("style." + name, function(d, i) {
+ var f = tween.call(this, d, i, getComputedStyle(this, null).getPropertyValue(name));
+ return f && function(t) {
+ this.style.setProperty(name, f(t), priority);
+ };
+ });
+ };
+ d3_transitionPrototype.text = function(value) {
+ return d3_transition_tween(this, "text", value, d3_transition_text);
+ };
+ function d3_transition_text(b) {
+ if (b == null) b = "";
+ return function() {
+ this.textContent = b;
+ };
+ }
+ d3_transitionPrototype.remove = function() {
+ return this.each("end.transition", function() {
+ var p;
+ if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this);
+ });
+ };
+ d3_transitionPrototype.ease = function(value) {
+ var id = this.id;
+ if (arguments.length < 1) return this.node().__transition__[id].ease;
+ if (typeof value !== "function") value = d3.ease.apply(d3, arguments);
+ return d3_selection_each(this, function(node) {
+ node.__transition__[id].ease = value;
+ });
+ };
+ d3_transitionPrototype.delay = function(value) {
+ var id = this.id;
+ return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
+ node.__transition__[id].delay = value.call(node, node.__data__, i, j) | 0;
+ } : (value |= 0, function(node) {
+ node.__transition__[id].delay = value;
+ }));
+ };
+ d3_transitionPrototype.duration = function(value) {
+ var id = this.id;
+ return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
+ node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j) | 0);
+ } : (value = Math.max(1, value | 0), function(node) {
+ node.__transition__[id].duration = value;
+ }));
+ };
+ d3_transitionPrototype.each = function(type, listener) {
+ var id = this.id;
+ if (arguments.length < 2) {
+ var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId;
+ d3_transitionInheritId = id;
+ d3_selection_each(this, function(node, i, j) {
+ d3_transitionInherit = node.__transition__[id];
+ type.call(node, node.__data__, i, j);
+ });
+ d3_transitionInherit = inherit;
+ d3_transitionInheritId = inheritId;
+ } else {
+ d3_selection_each(this, function(node) {
+ node.__transition__[id].event.on(type, listener);
+ });
+ }
+ return this;
+ };
+ d3_transitionPrototype.transition = function() {
+ var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node, transition;
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ if (node = group[i]) {
+ transition = Object.create(node.__transition__[id0]);
+ transition.delay += transition.duration;
+ d3_transitionNode(node, i, id1, transition);
+ }
+ subgroup.push(node);
+ }
+ }
+ return d3_transition(subgroups, id1);
+ };
+ d3_transitionPrototype.tween = function(name, tween) {
+ var id = this.id;
+ if (arguments.length < 2) return this.node().__transition__[id].tween.get(name);
+ return d3_selection_each(this, tween == null ? function(node) {
+ node.__transition__[id].tween.remove(name);
+ } : function(node) {
+ node.__transition__[id].tween.set(name, tween);
+ });
+ };
+ function d3_transition_tween(groups, name, value, tween) {
+ var id = groups.id;
+ return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) {
+ node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j)));
+ } : (value = tween(value), function(node) {
+ node.__transition__[id].tween.set(name, value);
+ }));
+ }
+ var d3_timer_id = 0, d3_timer_byId = {}, d3_timer_queue = null, d3_timer_interval, d3_timer_timeout;
+ d3.timer = function(callback, delay, then) {
+ if (arguments.length < 3) {
+ if (arguments.length < 2) delay = 0; else if (!isFinite(delay)) return;
+ then = Date.now();
+ }
+ var timer = d3_timer_byId[callback.id];
+ if (timer && timer.callback === callback) {
+ timer.then = then;
+ timer.delay = delay;
+ } else d3_timer_byId[callback.id = ++d3_timer_id] = d3_timer_queue = {
+ callback: callback,
+ then: then,
+ delay: delay,
+ next: d3_timer_queue
+ };
+ if (!d3_timer_interval) {
+ d3_timer_timeout = clearTimeout(d3_timer_timeout);
+ d3_timer_interval = 1;
+ d3_timer_frame(d3_timer_step);
+ }
+ };
+ function d3_timer_step() {
+ var elapsed, now = Date.now(), t1 = d3_timer_queue;
+ while (t1) {
+ elapsed = now - t1.then;
+ if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed);
+ t1 = t1.next;
+ }
+ var delay = d3_timer_flush() - now;
+ if (delay > 24) {
+ if (isFinite(delay)) {
+ clearTimeout(d3_timer_timeout);
+ d3_timer_timeout = setTimeout(d3_timer_step, delay);
+ }
+ d3_timer_interval = 0;
+ } else {
+ d3_timer_interval = 1;
+ d3_timer_frame(d3_timer_step);
+ }
+ }
+ d3.timer.flush = function() {
+ var elapsed, now = Date.now(), t1 = d3_timer_queue;
+ while (t1) {
+ elapsed = now - t1.then;
+ if (!t1.delay) t1.flush = t1.callback(elapsed);
+ t1 = t1.next;
+ }
+ d3_timer_flush();
+ };
+ function d3_timer_flush() {
+ var t0 = null, t1 = d3_timer_queue, then = Infinity;
+ while (t1) {
+ if (t1.flush) {
+ delete d3_timer_byId[t1.callback.id];
+ t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next;
+ } else {
+ then = Math.min(then, t1.then + t1.delay);
+ t1 = (t0 = t1).next;
+ }
+ }
+ return then;
+ }
+ var d3_timer_frame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
+ setTimeout(callback, 17);
+ };
+ d3.mouse = function(container) {
+ return d3_mousePoint(container, d3_eventSource());
+ };
+ var d3_mouse_bug44083 = /WebKit/.test(navigator.userAgent) ? -1 : 0;
+ function d3_mousePoint(container, e) {
+ var svg = container.ownerSVGElement || container;
+ if (svg.createSVGPoint) {
+ var point = svg.createSVGPoint();
+ if (d3_mouse_bug44083 < 0 && (window.scrollX || window.scrollY)) {
+ svg = d3.select(document.body).append("svg").style("position", "absolute").style("top", 0).style("left", 0);
+ var ctm = svg[0][0].getScreenCTM();
+ d3_mouse_bug44083 = !(ctm.f || ctm.e);
+ svg.remove();
+ }
+ if (d3_mouse_bug44083) {
+ point.x = e.pageX;
+ point.y = e.pageY;
+ } else {
+ point.x = e.clientX;
+ point.y = e.clientY;
+ }
+ point = point.matrixTransform(container.getScreenCTM().inverse());
+ return [ point.x, point.y ];
+ }
+ var rect = container.getBoundingClientRect();
+ return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ];
+ }
+ d3.touches = function(container, touches) {
+ if (arguments.length < 2) touches = d3_eventSource().touches;
+ return touches ? d3_array(touches).map(function(touch) {
+ var point = d3_mousePoint(container, touch);
+ point.identifier = touch.identifier;
+ return point;
+ }) : [];
+ };
+ function d3_noop() {}
+ d3.scale = {};
+ function d3_scaleExtent(domain) {
+ var start = domain[0], stop = domain[domain.length - 1];
+ return start < stop ? [ start, stop ] : [ stop, start ];
+ }
+ function d3_scaleRange(scale) {
+ return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
+ }
+ function d3_scale_nice(domain, nice) {
+ var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx;
+ if (x1 < x0) {
+ dx = i0, i0 = i1, i1 = dx;
+ dx = x0, x0 = x1, x1 = dx;
+ }
+ if (nice = nice(x1 - x0)) {
+ domain[i0] = nice.floor(x0);
+ domain[i1] = nice.ceil(x1);
+ }
+ return domain;
+ }
+ function d3_scale_niceDefault() {
+ return Math;
+ }
+ d3.scale.linear = function() {
+ return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3.interpolate, false);
+ };
+ function d3_scale_linear(domain, range, interpolate, clamp) {
+ var output, input;
+ function rescale() {
+ var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber;
+ output = linear(domain, range, uninterpolate, interpolate);
+ input = linear(range, domain, uninterpolate, d3.interpolate);
+ return scale;
+ }
+ function scale(x) {
+ return output(x);
+ }
+ scale.invert = function(y) {
+ return input(y);
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ domain = x.map(Number);
+ return rescale();
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ return rescale();
+ };
+ scale.rangeRound = function(x) {
+ return scale.range(x).interpolate(d3.interpolateRound);
+ };
+ scale.clamp = function(x) {
+ if (!arguments.length) return clamp;
+ clamp = x;
+ return rescale();
+ };
+ scale.interpolate = function(x) {
+ if (!arguments.length) return interpolate;
+ interpolate = x;
+ return rescale();
+ };
+ scale.ticks = function(m) {
+ return d3_scale_linearTicks(domain, m);
+ };
+ scale.tickFormat = function(m) {
+ return d3_scale_linearTickFormat(domain, m);
+ };
+ scale.nice = function() {
+ d3_scale_nice(domain, d3_scale_linearNice);
+ return rescale();
+ };
+ scale.copy = function() {
+ return d3_scale_linear(domain, range, interpolate, clamp);
+ };
+ return rescale();
+ }
+ function d3_scale_linearRebind(scale, linear) {
+ return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
+ }
+ function d3_scale_linearNice(dx) {
+ dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1);
+ return dx && {
+ floor: function(x) {
+ return Math.floor(x / dx) * dx;
+ },
+ ceil: function(x) {
+ return Math.ceil(x / dx) * dx;
+ }
+ };
+ }
+ function d3_scale_linearTickRange(domain, m) {
+ var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step;
+ if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2;
+ extent[0] = Math.ceil(extent[0] / step) * step;
+ extent[1] = Math.floor(extent[1] / step) * step + step * .5;
+ extent[2] = step;
+ return extent;
+ }
+ function d3_scale_linearTicks(domain, m) {
+ return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
+ }
+ function d3_scale_linearTickFormat(domain, m) {
+ return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f");
+ }
+ function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
+ var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]);
+ return function(x) {
+ return i(u(x));
+ };
+ }
+ function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
+ var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1;
+ if (domain[k] < domain[0]) {
+ domain = domain.slice().reverse();
+ range = range.slice().reverse();
+ }
+ while (++j <= k) {
+ u.push(uninterpolate(domain[j - 1], domain[j]));
+ i.push(interpolate(range[j - 1], range[j]));
+ }
+ return function(x) {
+ var j = d3.bisect(domain, x, 1, k) - 1;
+ return i[j](u[j](x));
+ };
+ }
+ d3.scale.log = function() {
+ return d3_scale_log(d3.scale.linear(), d3_scale_logp);
+ };
+ function d3_scale_log(linear, log) {
+ var pow = log.pow;
+ function scale(x) {
+ return linear(log(x));
+ }
+ scale.invert = function(x) {
+ return pow(linear.invert(x));
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return linear.domain().map(pow);
+ log = x[0] < 0 ? d3_scale_logn : d3_scale_logp;
+ pow = log.pow;
+ linear.domain(x.map(log));
+ return scale;
+ };
+ scale.nice = function() {
+ linear.domain(d3_scale_nice(linear.domain(), d3_scale_niceDefault));
+ return scale;
+ };
+ scale.ticks = function() {
+ var extent = d3_scaleExtent(linear.domain()), ticks = [];
+ if (extent.every(isFinite)) {
+ var i = Math.floor(extent[0]), j = Math.ceil(extent[1]), u = pow(extent[0]), v = pow(extent[1]);
+ if (log === d3_scale_logn) {
+ ticks.push(pow(i));
+ for (;i++ < j; ) for (var k = 9; k > 0; k--) ticks.push(pow(i) * k);
+ } else {
+ for (;i < j; i++) for (var k = 1; k < 10; k++) ticks.push(pow(i) * k);
+ ticks.push(pow(i));
+ }
+ for (i = 0; ticks[i] < u; i++) {}
+ for (j = ticks.length; ticks[j - 1] > v; j--) {}
+ ticks = ticks.slice(i, j);
+ }
+ return ticks;
+ };
+ scale.tickFormat = function(n, format) {
+ if (arguments.length < 2) format = d3_scale_logFormat;
+ if (!arguments.length) return format;
+ var k = Math.max(.1, n / scale.ticks().length), f = log === d3_scale_logn ? (e = -1e-12,
+ Math.floor) : (e = 1e-12, Math.ceil), e;
+ return function(d) {
+ return d / pow(f(log(d) + e)) <= k ? format(d) : "";
+ };
+ };
+ scale.copy = function() {
+ return d3_scale_log(linear.copy(), log);
+ };
+ return d3_scale_linearRebind(scale, linear);
+ }
+ var d3_scale_logFormat = d3.format(".0e");
+ function d3_scale_logp(x) {
+ return Math.log(x < 0 ? 0 : x) / Math.LN10;
+ }
+ function d3_scale_logn(x) {
+ return -Math.log(x > 0 ? 0 : -x) / Math.LN10;
+ }
+ d3_scale_logp.pow = function(x) {
+ return Math.pow(10, x);
+ };
+ d3_scale_logn.pow = function(x) {
+ return -Math.pow(10, -x);
+ };
+ d3.scale.pow = function() {
+ return d3_scale_pow(d3.scale.linear(), 1);
+ };
+ function d3_scale_pow(linear, exponent) {
+ var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent);
+ function scale(x) {
+ return linear(powp(x));
+ }
+ scale.invert = function(x) {
+ return powb(linear.invert(x));
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return linear.domain().map(powb);
+ linear.domain(x.map(powp));
+ return scale;
+ };
+ scale.ticks = function(m) {
+ return d3_scale_linearTicks(scale.domain(), m);
+ };
+ scale.tickFormat = function(m) {
+ return d3_scale_linearTickFormat(scale.domain(), m);
+ };
+ scale.nice = function() {
+ return scale.domain(d3_scale_nice(scale.domain(), d3_scale_linearNice));
+ };
+ scale.exponent = function(x) {
+ if (!arguments.length) return exponent;
+ var domain = scale.domain();
+ powp = d3_scale_powPow(exponent = x);
+ powb = d3_scale_powPow(1 / exponent);
+ return scale.domain(domain);
+ };
+ scale.copy = function() {
+ return d3_scale_pow(linear.copy(), exponent);
+ };
+ return d3_scale_linearRebind(scale, linear);
+ }
+ function d3_scale_powPow(e) {
+ return function(x) {
+ return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e);
+ };
+ }
+ d3.scale.sqrt = function() {
+ return d3.scale.pow().exponent(.5);
+ };
+ d3.scale.ordinal = function() {
+ return d3_scale_ordinal([], {
+ t: "range",
+ a: [ [] ]
+ });
+ };
+ function d3_scale_ordinal(domain, ranger) {
+ var index, range, rangeBand;
+ function scale(x) {
+ return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length];
+ }
+ function steps(start, step) {
+ return d3.range(domain.length).map(function(i) {
+ return start + step * i;
+ });
+ }
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ domain = [];
+ index = new d3_Map();
+ var i = -1, n = x.length, xi;
+ while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi));
+ return scale[ranger.t].apply(scale, ranger.a);
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ rangeBand = 0;
+ ranger = {
+ t: "range",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangePoints = function(x, padding) {
+ if (arguments.length < 2) padding = 0;
+ var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding);
+ range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step);
+ rangeBand = 0;
+ ranger = {
+ t: "rangePoints",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangeBands = function(x, padding, outerPadding) {
+ if (arguments.length < 2) padding = 0;
+ if (arguments.length < 3) outerPadding = padding;
+ var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding);
+ range = steps(start + step * outerPadding, step);
+ if (reverse) range.reverse();
+ rangeBand = step * (1 - padding);
+ ranger = {
+ t: "rangeBands",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangeRoundBands = function(x, padding, outerPadding) {
+ if (arguments.length < 2) padding = 0;
+ if (arguments.length < 3) outerPadding = padding;
+ var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step;
+ range = steps(start + Math.round(error / 2), step);
+ if (reverse) range.reverse();
+ rangeBand = Math.round(step * (1 - padding));
+ ranger = {
+ t: "rangeRoundBands",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangeBand = function() {
+ return rangeBand;
+ };
+ scale.rangeExtent = function() {
+ return d3_scaleExtent(ranger.a[0]);
+ };
+ scale.copy = function() {
+ return d3_scale_ordinal(domain, ranger);
+ };
+ return scale.domain(domain);
+ }
+ d3.scale.category10 = function() {
+ return d3.scale.ordinal().range(d3_category10);
+ };
+ d3.scale.category20 = function() {
+ return d3.scale.ordinal().range(d3_category20);
+ };
+ d3.scale.category20b = function() {
+ return d3.scale.ordinal().range(d3_category20b);
+ };
+ d3.scale.category20c = function() {
+ return d3.scale.ordinal().range(d3_category20c);
+ };
+ var d3_category10 = [ "#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf" ];
+ var d3_category20 = [ "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5", "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf", "#9edae5" ];
+ var d3_category20b = [ "#393b79", "#5254a3", "#6b6ecf", "#9c9ede", "#637939", "#8ca252", "#b5cf6b", "#cedb9c", "#8c6d31", "#bd9e39", "#e7ba52", "#e7cb94", "#843c39", "#ad494a", "#d6616b", "#e7969c", "#7b4173", "#a55194", "#ce6dbd", "#de9ed6" ];
+ var d3_category20c = [ "#3182bd", "#6baed6", "#9ecae1", "#c6dbef", "#e6550d", "#fd8d3c", "#fdae6b", "#fdd0a2", "#31a354", "#74c476", "#a1d99b", "#c7e9c0", "#756bb1", "#9e9ac8", "#bcbddc", "#dadaeb", "#636363", "#969696", "#bdbdbd", "#d9d9d9" ];
+ d3.scale.quantile = function() {
+ return d3_scale_quantile([], []);
+ };
+ function d3_scale_quantile(domain, range) {
+ var thresholds;
+ function rescale() {
+ var k = 0, q = range.length;
+ thresholds = [];
+ while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
+ return scale;
+ }
+ function scale(x) {
+ if (isNaN(x = +x)) return NaN;
+ return range[d3.bisect(thresholds, x)];
+ }
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ domain = x.filter(function(d) {
+ return !isNaN(d);
+ }).sort(d3.ascending);
+ return rescale();
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ return rescale();
+ };
+ scale.quantiles = function() {
+ return thresholds;
+ };
+ scale.copy = function() {
+ return d3_scale_quantile(domain, range);
+ };
+ return rescale();
+ }
+ d3.scale.quantize = function() {
+ return d3_scale_quantize(0, 1, [ 0, 1 ]);
+ };
+ function d3_scale_quantize(x0, x1, range) {
+ var kx, i;
+ function scale(x) {
+ return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
+ }
+ function rescale() {
+ kx = range.length / (x1 - x0);
+ i = range.length - 1;
+ return scale;
+ }
+ scale.domain = function(x) {
+ if (!arguments.length) return [ x0, x1 ];
+ x0 = +x[0];
+ x1 = +x[x.length - 1];
+ return rescale();
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ return rescale();
+ };
+ scale.copy = function() {
+ return d3_scale_quantize(x0, x1, range);
+ };
+ return rescale();
+ }
+ d3.scale.threshold = function() {
+ return d3_scale_threshold([ .5 ], [ 0, 1 ]);
+ };
+ function d3_scale_threshold(domain, range) {
+ function scale(x) {
+ return range[d3.bisect(domain, x)];
+ }
+ scale.domain = function(_) {
+ if (!arguments.length) return domain;
+ domain = _;
+ return scale;
+ };
+ scale.range = function(_) {
+ if (!arguments.length) return range;
+ range = _;
+ return scale;
+ };
+ scale.copy = function() {
+ return d3_scale_threshold(domain, range);
+ };
+ return scale;
+ }
+ d3.scale.identity = function() {
+ return d3_scale_identity([ 0, 1 ]);
+ };
+ function d3_scale_identity(domain) {
+ function identity(x) {
+ return +x;
+ }
+ identity.invert = identity;
+ identity.domain = identity.range = function(x) {
+ if (!arguments.length) return domain;
+ domain = x.map(identity);
+ return identity;
+ };
+ identity.ticks = function(m) {
+ return d3_scale_linearTicks(domain, m);
+ };
+ identity.tickFormat = function(m) {
+ return d3_scale_linearTickFormat(domain, m);
+ };
+ identity.copy = function() {
+ return d3_scale_identity(domain);
+ };
+ return identity;
+ }
+ d3.svg = {};
+ d3.svg.arc = function() {
+ var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
+ function arc() {
+ var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0,
+ a0 = a1, a1 = da), a1 - a0), df = da < π ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1);
+ return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z";
+ }
+ arc.innerRadius = function(v) {
+ if (!arguments.length) return innerRadius;
+ innerRadius = d3_functor(v);
+ return arc;
+ };
+ arc.outerRadius = function(v) {
+ if (!arguments.length) return outerRadius;
+ outerRadius = d3_functor(v);
+ return arc;
+ };
+ arc.startAngle = function(v) {
+ if (!arguments.length) return startAngle;
+ startAngle = d3_functor(v);
+ return arc;
+ };
+ arc.endAngle = function(v) {
+ if (!arguments.length) return endAngle;
+ endAngle = d3_functor(v);
+ return arc;
+ };
+ arc.centroid = function() {
+ var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset;
+ return [ Math.cos(a) * r, Math.sin(a) * r ];
+ };
+ return arc;
+ };
+ var d3_svg_arcOffset = -π / 2, d3_svg_arcMax = 2 * π - 1e-6;
+ function d3_svg_arcInnerRadius(d) {
+ return d.innerRadius;
+ }
+ function d3_svg_arcOuterRadius(d) {
+ return d.outerRadius;
+ }
+ function d3_svg_arcStartAngle(d) {
+ return d.startAngle;
+ }
+ function d3_svg_arcEndAngle(d) {
+ return d.endAngle;
+ }
+ function d3_svg_line(projection) {
+ var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7;
+ function line(data) {
+ var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y);
+ function segment() {
+ segments.push("M", interpolate(projection(points), tension));
+ }
+ while (++i < n) {
+ if (defined.call(this, d = data[i], i)) {
+ points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]);
+ } else if (points.length) {
+ segment();
+ points = [];
+ }
+ }
+ if (points.length) segment();
+ return segments.length ? segments.join("") : null;
+ }
+ line.x = function(_) {
+ if (!arguments.length) return x;
+ x = _;
+ return line;
+ };
+ line.y = function(_) {
+ if (!arguments.length) return y;
+ y = _;
+ return line;
+ };
+ line.defined = function(_) {
+ if (!arguments.length) return defined;
+ defined = _;
+ return line;
+ };
+ line.interpolate = function(_) {
+ if (!arguments.length) return interpolateKey;
+ if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
+ return line;
+ };
+ line.tension = function(_) {
+ if (!arguments.length) return tension;
+ tension = _;
+ return line;
+ };
+ return line;
+ }
+ d3.svg.line = function() {
+ return d3_svg_line(d3_identity);
+ };
+ function d3_svg_lineX(d) {
+ return d[0];
+ }
+ function d3_svg_lineY(d) {
+ return d[1];
+ }
+ var d3_svg_lineInterpolators = d3.map({
+ linear: d3_svg_lineLinear,
+ "linear-closed": d3_svg_lineLinearClosed,
+ "step-before": d3_svg_lineStepBefore,
+ "step-after": d3_svg_lineStepAfter,
+ basis: d3_svg_lineBasis,
+ "basis-open": d3_svg_lineBasisOpen,
+ "basis-closed": d3_svg_lineBasisClosed,
+ bundle: d3_svg_lineBundle,
+ cardinal: d3_svg_lineCardinal,
+ "cardinal-open": d3_svg_lineCardinalOpen,
+ "cardinal-closed": d3_svg_lineCardinalClosed,
+ monotone: d3_svg_lineMonotone
+ });
+ d3_svg_lineInterpolators.forEach(function(key, value) {
+ value.key = key;
+ value.closed = /-closed$/.test(key);
+ });
+ function d3_svg_lineLinear(points) {
+ return points.join("L");
+ }
+ function d3_svg_lineLinearClosed(points) {
+ return d3_svg_lineLinear(points) + "Z";
+ }
+ function d3_svg_lineStepBefore(points) {
+ var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
+ while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]);
+ return path.join("");
+ }
+ function d3_svg_lineStepAfter(points) {
+ var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
+ while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]);
+ return path.join("");
+ }
+ function d3_svg_lineCardinalOpen(points, tension) {
+ return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension));
+ }
+ function d3_svg_lineCardinalClosed(points, tension) {
+ return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]),
+ points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension));
+ }
+ function d3_svg_lineCardinal(points, tension) {
+ return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension));
+ }
+ function d3_svg_lineHermite(points, tangents) {
+ if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) {
+ return d3_svg_lineLinear(points);
+ }
+ var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1;
+ if (quad) {
+ path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1];
+ p0 = points[1];
+ pi = 2;
+ }
+ if (tangents.length > 1) {
+ t = tangents[1];
+ p = points[pi];
+ pi++;
+ path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
+ for (var i = 2; i < tangents.length; i++, pi++) {
+ p = points[pi];
+ t = tangents[i];
+ path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
+ }
+ }
+ if (quad) {
+ var lp = points[pi];
+ path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1];
+ }
+ return path;
+ }
+ function d3_svg_lineCardinalTangents(points, tension) {
+ var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length;
+ while (++i < n) {
+ p0 = p1;
+ p1 = p2;
+ p2 = points[i];
+ tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]);
+ }
+ return tangents;
+ }
+ function d3_svg_lineBasis(points) {
+ if (points.length < 3) return d3_svg_lineLinear(points);
+ var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0 ];
+ d3_svg_lineBasisBezier(path, px, py);
+ while (++i < n) {
+ pi = points[i];
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ i = -1;
+ while (++i < 2) {
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ return path.join("");
+ }
+ function d3_svg_lineBasisOpen(points) {
+ if (points.length < 4) return d3_svg_lineLinear(points);
+ var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ];
+ while (++i < 3) {
+ pi = points[i];
+ px.push(pi[0]);
+ py.push(pi[1]);
+ }
+ path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py));
+ --i;
+ while (++i < n) {
+ pi = points[i];
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ return path.join("");
+ }
+ function d3_svg_lineBasisClosed(points) {
+ var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = [];
+ while (++i < 4) {
+ pi = points[i % n];
+ px.push(pi[0]);
+ py.push(pi[1]);
+ }
+ path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
+ --i;
+ while (++i < m) {
+ pi = points[i % n];
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ return path.join("");
+ }
+ function d3_svg_lineBundle(points, tension) {
+ var n = points.length - 1;
+ if (n) {
+ var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t;
+ while (++i <= n) {
+ p = points[i];
+ t = i / n;
+ p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx);
+ p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy);
+ }
+ }
+ return d3_svg_lineBasis(points);
+ }
+ function d3_svg_lineDot4(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+ }
+ var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ];
+ function d3_svg_lineBasisBezier(path, x, y) {
+ path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y));
+ }
+ function d3_svg_lineSlope(p0, p1) {
+ return (p1[1] - p0[1]) / (p1[0] - p0[0]);
+ }
+ function d3_svg_lineFiniteDifferences(points) {
+ var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1);
+ while (++i < j) {
+ m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2;
+ }
+ m[i] = d;
+ return m;
+ }
+ function d3_svg_lineMonotoneTangents(points) {
+ var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1;
+ while (++i < j) {
+ d = d3_svg_lineSlope(points[i], points[i + 1]);
+ if (Math.abs(d) < 1e-6) {
+ m[i] = m[i + 1] = 0;
+ } else {
+ a = m[i] / d;
+ b = m[i + 1] / d;
+ s = a * a + b * b;
+ if (s > 9) {
+ s = d * 3 / Math.sqrt(s);
+ m[i] = s * a;
+ m[i + 1] = s * b;
+ }
+ }
+ }
+ i = -1;
+ while (++i <= j) {
+ s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i]));
+ tangents.push([ s || 0, m[i] * s || 0 ]);
+ }
+ return tangents;
+ }
+ function d3_svg_lineMonotone(points) {
+ return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points));
+ }
+ d3.svg.line.radial = function() {
+ var line = d3_svg_line(d3_svg_lineRadial);
+ line.radius = line.x, delete line.x;
+ line.angle = line.y, delete line.y;
+ return line;
+ };
+ function d3_svg_lineRadial(points) {
+ var point, i = -1, n = points.length, r, a;
+ while (++i < n) {
+ point = points[i];
+ r = point[0];
+ a = point[1] + d3_svg_arcOffset;
+ point[0] = r * Math.cos(a);
+ point[1] = r * Math.sin(a);
+ }
+ return points;
+ }
+ function d3_svg_area(projection) {
+ var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7;
+ function area(data) {
+ var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() {
+ return x;
+ } : d3_functor(x1), fy1 = y0 === y1 ? function() {
+ return y;
+ } : d3_functor(y1), x, y;
+ function segment() {
+ segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z");
+ }
+ while (++i < n) {
+ if (defined.call(this, d = data[i], i)) {
+ points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]);
+ points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]);
+ } else if (points0.length) {
+ segment();
+ points0 = [];
+ points1 = [];
+ }
+ }
+ if (points0.length) segment();
+ return segments.length ? segments.join("") : null;
+ }
+ area.x = function(_) {
+ if (!arguments.length) return x1;
+ x0 = x1 = _;
+ return area;
+ };
+ area.x0 = function(_) {
+ if (!arguments.length) return x0;
+ x0 = _;
+ return area;
+ };
+ area.x1 = function(_) {
+ if (!arguments.length) return x1;
+ x1 = _;
+ return area;
+ };
+ area.y = function(_) {
+ if (!arguments.length) return y1;
+ y0 = y1 = _;
+ return area;
+ };
+ area.y0 = function(_) {
+ if (!arguments.length) return y0;
+ y0 = _;
+ return area;
+ };
+ area.y1 = function(_) {
+ if (!arguments.length) return y1;
+ y1 = _;
+ return area;
+ };
+ area.defined = function(_) {
+ if (!arguments.length) return defined;
+ defined = _;
+ return area;
+ };
+ area.interpolate = function(_) {
+ if (!arguments.length) return interpolateKey;
+ if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
+ interpolateReverse = interpolate.reverse || interpolate;
+ L = interpolate.closed ? "M" : "L";
+ return area;
+ };
+ area.tension = function(_) {
+ if (!arguments.length) return tension;
+ tension = _;
+ return area;
+ };
+ return area;
+ }
+ d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter;
+ d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore;
+ d3.svg.area = function() {
+ return d3_svg_area(d3_identity);
+ };
+ d3.svg.area.radial = function() {
+ var area = d3_svg_area(d3_svg_lineRadial);
+ area.radius = area.x, delete area.x;
+ area.innerRadius = area.x0, delete area.x0;
+ area.outerRadius = area.x1, delete area.x1;
+ area.angle = area.y, delete area.y;
+ area.startAngle = area.y0, delete area.y0;
+ area.endAngle = area.y1, delete area.y1;
+ return area;
+ };
+ d3.svg.chord = function() {
+ var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
+ function chord(d, i) {
+ var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i);
+ return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z";
+ }
+ function subgroup(self, f, d, i) {
+ var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset;
+ return {
+ r: r,
+ a0: a0,
+ a1: a1,
+ p0: [ r * Math.cos(a0), r * Math.sin(a0) ],
+ p1: [ r * Math.cos(a1), r * Math.sin(a1) ]
+ };
+ }
+ function equals(a, b) {
+ return a.a0 == b.a0 && a.a1 == b.a1;
+ }
+ function arc(r, p, a) {
+ return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p;
+ }
+ function curve(r0, p0, r1, p1) {
+ return "Q 0,0 " + p1;
+ }
+ chord.radius = function(v) {
+ if (!arguments.length) return radius;
+ radius = d3_functor(v);
+ return chord;
+ };
+ chord.source = function(v) {
+ if (!arguments.length) return source;
+ source = d3_functor(v);
+ return chord;
+ };
+ chord.target = function(v) {
+ if (!arguments.length) return target;
+ target = d3_functor(v);
+ return chord;
+ };
+ chord.startAngle = function(v) {
+ if (!arguments.length) return startAngle;
+ startAngle = d3_functor(v);
+ return chord;
+ };
+ chord.endAngle = function(v) {
+ if (!arguments.length) return endAngle;
+ endAngle = d3_functor(v);
+ return chord;
+ };
+ return chord;
+ };
+ function d3_svg_chordRadius(d) {
+ return d.radius;
+ }
+ d3.svg.diagonal = function() {
+ var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection;
+ function diagonal(d, i) {
+ var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, {
+ x: p0.x,
+ y: m
+ }, {
+ x: p3.x,
+ y: m
+ }, p3 ];
+ p = p.map(projection);
+ return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3];
+ }
+ diagonal.source = function(x) {
+ if (!arguments.length) return source;
+ source = d3_functor(x);
+ return diagonal;
+ };
+ diagonal.target = function(x) {
+ if (!arguments.length) return target;
+ target = d3_functor(x);
+ return diagonal;
+ };
+ diagonal.projection = function(x) {
+ if (!arguments.length) return projection;
+ projection = x;
+ return diagonal;
+ };
+ return diagonal;
+ };
+ function d3_svg_diagonalProjection(d) {
+ return [ d.x, d.y ];
+ }
+ d3.svg.diagonal.radial = function() {
+ var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection;
+ diagonal.projection = function(x) {
+ return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection;
+ };
+ return diagonal;
+ };
+ function d3_svg_diagonalRadialProjection(projection) {
+ return function() {
+ var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset;
+ return [ r * Math.cos(a), r * Math.sin(a) ];
+ };
+ }
+ d3.svg.symbol = function() {
+ var type = d3_svg_symbolType, size = d3_svg_symbolSize;
+ function symbol(d, i) {
+ return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i));
+ }
+ symbol.type = function(x) {
+ if (!arguments.length) return type;
+ type = d3_functor(x);
+ return symbol;
+ };
+ symbol.size = function(x) {
+ if (!arguments.length) return size;
+ size = d3_functor(x);
+ return symbol;
+ };
+ return symbol;
+ };
+ function d3_svg_symbolSize() {
+ return 64;
+ }
+ function d3_svg_symbolType() {
+ return "circle";
+ }
+ function d3_svg_symbolCircle(size) {
+ var r = Math.sqrt(size / π);
+ return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z";
+ }
+ var d3_svg_symbols = d3.map({
+ circle: d3_svg_symbolCircle,
+ cross: function(size) {
+ var r = Math.sqrt(size / 5) / 2;
+ return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z";
+ },
+ diamond: function(size) {
+ var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30;
+ return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z";
+ },
+ square: function(size) {
+ var r = Math.sqrt(size) / 2;
+ return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z";
+ },
+ "triangle-down": function(size) {
+ var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
+ return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z";
+ },
+ "triangle-up": function(size) {
+ var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
+ return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z";
+ }
+ });
+ d3.svg.symbolTypes = d3_svg_symbols.keys();
+ var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians);
+ d3.svg.axis = function() {
+ var scale = d3.scale.linear(), orient = "bottom", tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0;
+ function axis(g) {
+ g.each(function() {
+ var g = d3.select(this);
+ var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_;
+ var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", "g").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1);
+ var tick = g.selectAll("g").data(ticks, String), tickEnter = tick.enter().insert("g", "path").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform;
+ var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = d3.transition(path);
+ var scale1 = scale.copy(), scale0 = this.__chart__ || scale1;
+ this.__chart__ = scale1;
+ path.enter().append("path").attr("class", "domain");
+ tickEnter.append("line").attr("class", "tick");
+ tickEnter.append("text");
+ var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text");
+ switch (orient) {
+ case "bottom":
+ {
+ tickTransform = d3_svg_axisX;
+ subtickEnter.attr("y2", tickMinorSize);
+ subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize);
+ lineEnter.attr("y2", tickMajorSize);
+ textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding);
+ lineUpdate.attr("x2", 0).attr("y2", tickMajorSize);
+ textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding);
+ text.attr("dy", ".71em").style("text-anchor", "middle");
+ pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize);
+ break;
+ }
+
+ case "top":
+ {
+ tickTransform = d3_svg_axisX;
+ subtickEnter.attr("y2", -tickMinorSize);
+ subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize);
+ lineEnter.attr("y2", -tickMajorSize);
+ textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding));
+ lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize);
+ textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding));
+ text.attr("dy", "0em").style("text-anchor", "middle");
+ pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize);
+ break;
+ }
+
+ case "left":
+ {
+ tickTransform = d3_svg_axisY;
+ subtickEnter.attr("x2", -tickMinorSize);
+ subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0);
+ lineEnter.attr("x2", -tickMajorSize);
+ textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding));
+ lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0);
+ textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0);
+ text.attr("dy", ".32em").style("text-anchor", "end");
+ pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize);
+ break;
+ }
+
+ case "right":
+ {
+ tickTransform = d3_svg_axisY;
+ subtickEnter.attr("x2", tickMinorSize);
+ subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0);
+ lineEnter.attr("x2", tickMajorSize);
+ textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding);
+ lineUpdate.attr("x2", tickMajorSize).attr("y2", 0);
+ textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0);
+ text.attr("dy", ".32em").style("text-anchor", "start");
+ pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize);
+ break;
+ }
+ }
+ if (scale.ticks) {
+ tickEnter.call(tickTransform, scale0);
+ tickUpdate.call(tickTransform, scale1);
+ tickExit.call(tickTransform, scale1);
+ subtickEnter.call(tickTransform, scale0);
+ subtickUpdate.call(tickTransform, scale1);
+ subtickExit.call(tickTransform, scale1);
+ } else {
+ var dx = scale1.rangeBand() / 2, x = function(d) {
+ return scale1(d) + dx;
+ };
+ tickEnter.call(tickTransform, x);
+ tickUpdate.call(tickTransform, x);
+ }
+ });
+ }
+ axis.scale = function(x) {
+ if (!arguments.length) return scale;
+ scale = x;
+ return axis;
+ };
+ axis.orient = function(x) {
+ if (!arguments.length) return orient;
+ orient = x;
+ return axis;
+ };
+ axis.ticks = function() {
+ if (!arguments.length) return tickArguments_;
+ tickArguments_ = arguments;
+ return axis;
+ };
+ axis.tickValues = function(x) {
+ if (!arguments.length) return tickValues;
+ tickValues = x;
+ return axis;
+ };
+ axis.tickFormat = function(x) {
+ if (!arguments.length) return tickFormat_;
+ tickFormat_ = x;
+ return axis;
+ };
+ axis.tickSize = function(x, y) {
+ if (!arguments.length) return tickMajorSize;
+ var n = arguments.length - 1;
+ tickMajorSize = +x;
+ tickMinorSize = n > 1 ? +y : tickMajorSize;
+ tickEndSize = n > 0 ? +arguments[n] : tickMajorSize;
+ return axis;
+ };
+ axis.tickPadding = function(x) {
+ if (!arguments.length) return tickPadding;
+ tickPadding = +x;
+ return axis;
+ };
+ axis.tickSubdivide = function(x) {
+ if (!arguments.length) return tickSubdivide;
+ tickSubdivide = +x;
+ return axis;
+ };
+ return axis;
+ };
+ function d3_svg_axisX(selection, x) {
+ selection.attr("transform", function(d) {
+ return "translate(" + x(d) + ",0)";
+ });
+ }
+ function d3_svg_axisY(selection, y) {
+ selection.attr("transform", function(d) {
+ return "translate(0," + y(d) + ")";
+ });
+ }
+ function d3_svg_axisSubdivide(scale, ticks, m) {
+ subticks = [];
+ if (m && ticks.length > 1) {
+ var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v;
+ while (++i < n) {
+ for (j = m; --j > 0; ) {
+ if ((v = +ticks[i] - j * d) >= extent[0]) {
+ subticks.push(v);
+ }
+ }
+ }
+ for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) {
+ subticks.push(v);
+ }
+ }
+ return subticks;
+ }
+ d3.svg.brush = function() {
+ var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], extentDomain;
+ function brush(g) {
+ g.each(function() {
+ var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]), fg = g.selectAll(".extent").data([ 0 ]), tz = g.selectAll(".resize").data(resizes, String), e;
+ g.style("pointer-events", "all").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart);
+ bg.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair");
+ fg.enter().append("rect").attr("class", "extent").style("cursor", "move");
+ tz.enter().append("g").attr("class", function(d) {
+ return "resize " + d;
+ }).style("cursor", function(d) {
+ return d3_svg_brushCursor[d];
+ }).append("rect").attr("x", function(d) {
+ return /[ew]$/.test(d) ? -3 : null;
+ }).attr("y", function(d) {
+ return /^[ns]/.test(d) ? -3 : null;
+ }).attr("width", 6).attr("height", 6).style("visibility", "hidden");
+ tz.style("display", brush.empty() ? "none" : null);
+ tz.exit().remove();
+ if (x) {
+ e = d3_scaleRange(x);
+ bg.attr("x", e[0]).attr("width", e[1] - e[0]);
+ redrawX(g);
+ }
+ if (y) {
+ e = d3_scaleRange(y);
+ bg.attr("y", e[0]).attr("height", e[1] - e[0]);
+ redrawY(g);
+ }
+ redraw(g);
+ });
+ }
+ function redraw(g) {
+ g.selectAll(".resize").attr("transform", function(d) {
+ return "translate(" + extent[+/e$/.test(d)][0] + "," + extent[+/^s/.test(d)][1] + ")";
+ });
+ }
+ function redrawX(g) {
+ g.select(".extent").attr("x", extent[0][0]);
+ g.selectAll(".extent,.n>rect,.s>rect").attr("width", extent[1][0] - extent[0][0]);
+ }
+ function redrawY(g) {
+ g.select(".extent").attr("y", extent[0][1]);
+ g.selectAll(".extent,.e>rect,.w>rect").attr("height", extent[1][1] - extent[0][1]);
+ }
+ function brushstart() {
+ var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), center, origin = mouse(), offset;
+ var w = d3.select(window).on("mousemove.brush", brushmove).on("mouseup.brush", brushend).on("touchmove.brush", brushmove).on("touchend.brush", brushend).on("keydown.brush", keydown).on("keyup.brush", keyup);
+ if (dragging) {
+ origin[0] = extent[0][0] - origin[0];
+ origin[1] = extent[0][1] - origin[1];
+ } else if (resizing) {
+ var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing);
+ offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ];
+ origin[0] = extent[ex][0];
+ origin[1] = extent[ey][1];
+ } else if (d3.event.altKey) center = origin.slice();
+ g.style("pointer-events", "none").selectAll(".resize").style("display", null);
+ d3.select("body").style("cursor", eventTarget.style("cursor"));
+ event_({
+ type: "brushstart"
+ });
+ brushmove();
+ d3_eventCancel();
+ function mouse() {
+ var touches = d3.event.changedTouches;
+ return touches ? d3.touches(target, touches)[0] : d3.mouse(target);
+ }
+ function keydown() {
+ if (d3.event.keyCode == 32) {
+ if (!dragging) {
+ center = null;
+ origin[0] -= extent[1][0];
+ origin[1] -= extent[1][1];
+ dragging = 2;
+ }
+ d3_eventCancel();
+ }
+ }
+ function keyup() {
+ if (d3.event.keyCode == 32 && dragging == 2) {
+ origin[0] += extent[1][0];
+ origin[1] += extent[1][1];
+ dragging = 0;
+ d3_eventCancel();
+ }
+ }
+ function brushmove() {
+ var point = mouse(), moved = false;
+ if (offset) {
+ point[0] += offset[0];
+ point[1] += offset[1];
+ }
+ if (!dragging) {
+ if (d3.event.altKey) {
+ if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ];
+ origin[0] = extent[+(point[0] < center[0])][0];
+ origin[1] = extent[+(point[1] < center[1])][1];
+ } else center = null;
+ }
+ if (resizingX && move1(point, x, 0)) {
+ redrawX(g);
+ moved = true;
+ }
+ if (resizingY && move1(point, y, 1)) {
+ redrawY(g);
+ moved = true;
+ }
+ if (moved) {
+ redraw(g);
+ event_({
+ type: "brush",
+ mode: dragging ? "move" : "resize"
+ });
+ }
+ }
+ function move1(point, scale, i) {
+ var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], size = extent[1][i] - extent[0][i], min, max;
+ if (dragging) {
+ r0 -= position;
+ r1 -= size + position;
+ }
+ min = Math.max(r0, Math.min(r1, point[i]));
+ if (dragging) {
+ max = (min += position) + size;
+ } else {
+ if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min));
+ if (position < min) {
+ max = min;
+ min = position;
+ } else {
+ max = position;
+ }
+ }
+ if (extent[0][i] !== min || extent[1][i] !== max) {
+ extentDomain = null;
+ extent[0][i] = min;
+ extent[1][i] = max;
+ return true;
+ }
+ }
+ function brushend() {
+ brushmove();
+ g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null);
+ d3.select("body").style("cursor", null);
+ w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null);
+ event_({
+ type: "brushend"
+ });
+ d3_eventCancel();
+ }
+ }
+ brush.x = function(z) {
+ if (!arguments.length) return x;
+ x = z;
+ resizes = d3_svg_brushResizes[!x << 1 | !y];
+ return brush;
+ };
+ brush.y = function(z) {
+ if (!arguments.length) return y;
+ y = z;
+ resizes = d3_svg_brushResizes[!x << 1 | !y];
+ return brush;
+ };
+ brush.extent = function(z) {
+ var x0, x1, y0, y1, t;
+ if (!arguments.length) {
+ z = extentDomain || extent;
+ if (x) {
+ x0 = z[0][0], x1 = z[1][0];
+ if (!extentDomain) {
+ x0 = extent[0][0], x1 = extent[1][0];
+ if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1);
+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
+ }
+ }
+ if (y) {
+ y0 = z[0][1], y1 = z[1][1];
+ if (!extentDomain) {
+ y0 = extent[0][1], y1 = extent[1][1];
+ if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1);
+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
+ }
+ }
+ return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ];
+ }
+ extentDomain = [ [ 0, 0 ], [ 0, 0 ] ];
+ if (x) {
+ x0 = z[0], x1 = z[1];
+ if (y) x0 = x0[0], x1 = x1[0];
+ extentDomain[0][0] = x0, extentDomain[1][0] = x1;
+ if (x.invert) x0 = x(x0), x1 = x(x1);
+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
+ extent[0][0] = x0 | 0, extent[1][0] = x1 | 0;
+ }
+ if (y) {
+ y0 = z[0], y1 = z[1];
+ if (x) y0 = y0[1], y1 = y1[1];
+ extentDomain[0][1] = y0, extentDomain[1][1] = y1;
+ if (y.invert) y0 = y(y0), y1 = y(y1);
+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
+ extent[0][1] = y0 | 0, extent[1][1] = y1 | 0;
+ }
+ return brush;
+ };
+ brush.clear = function() {
+ extentDomain = null;
+ extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0;
+ return brush;
+ };
+ brush.empty = function() {
+ return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][1];
+ };
+ return d3.rebind(brush, event, "on");
+ };
+ var d3_svg_brushCursor = {
+ n: "ns-resize",
+ e: "ew-resize",
+ s: "ns-resize",
+ w: "ew-resize",
+ nw: "nwse-resize",
+ ne: "nesw-resize",
+ se: "nwse-resize",
+ sw: "nesw-resize"
+ };
+ var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ];
+ d3.behavior = {};
+ d3.behavior.drag = function() {
+ var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null;
+ function drag() {
+ this.on("mousedown.drag", mousedown).on("touchstart.drag", mousedown);
+ }
+ function mousedown() {
+ var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null, offset, origin_ = point(), moved = 0;
+ var w = d3.select(window).on(touchId != null ? "touchmove.drag-" + touchId : "mousemove.drag", dragmove).on(touchId != null ? "touchend.drag-" + touchId : "mouseup.drag", dragend, true);
+ if (origin) {
+ offset = origin.apply(target, arguments);
+ offset = [ offset.x - origin_[0], offset.y - origin_[1] ];
+ } else {
+ offset = [ 0, 0 ];
+ }
+ if (touchId == null) d3_eventCancel();
+ event_({
+ type: "dragstart"
+ });
+ function point() {
+ var p = target.parentNode;
+ return touchId != null ? d3.touches(p).filter(function(p) {
+ return p.identifier === touchId;
+ })[0] : d3.mouse(p);
+ }
+ function dragmove() {
+ if (!target.parentNode) return dragend();
+ var p = point(), dx = p[0] - origin_[0], dy = p[1] - origin_[1];
+ moved |= dx | dy;
+ origin_ = p;
+ d3_eventCancel();
+ event_({
+ type: "drag",
+ x: p[0] + offset[0],
+ y: p[1] + offset[1],
+ dx: dx,
+ dy: dy
+ });
+ }
+ function dragend() {
+ event_({
+ type: "dragend"
+ });
+ if (moved) {
+ d3_eventCancel();
+ if (d3.event.target === eventTarget) w.on("click.drag", click, true);
+ }
+ w.on(touchId != null ? "touchmove.drag-" + touchId : "mousemove.drag", null).on(touchId != null ? "touchend.drag-" + touchId : "mouseup.drag", null);
+ }
+ function click() {
+ d3_eventCancel();
+ w.on("click.drag", null);
+ }
+ }
+ drag.origin = function(x) {
+ if (!arguments.length) return origin;
+ origin = x;
+ return drag;
+ };
+ return d3.rebind(drag, event, "on");
+ };
+ d3.behavior.zoom = function() {
+ var translate = [ 0, 0 ], translate0, scale = 1, scale0, scaleExtent = d3_behavior_zoomInfinity, event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0, y1, touchtime;
+ function zoom() {
+ this.on("mousedown.zoom", mousedown).on("mousewheel.zoom", mousewheel).on("mousemove.zoom", mousemove).on("DOMMouseScroll.zoom", mousewheel).on("dblclick.zoom", dblclick).on("touchstart.zoom", touchstart).on("touchmove.zoom", touchmove).on("touchend.zoom", touchstart);
+ }
+ zoom.translate = function(x) {
+ if (!arguments.length) return translate;
+ translate = x.map(Number);
+ rescale();
+ return zoom;
+ };
+ zoom.scale = function(x) {
+ if (!arguments.length) return scale;
+ scale = +x;
+ rescale();
+ return zoom;
+ };
+ zoom.scaleExtent = function(x) {
+ if (!arguments.length) return scaleExtent;
+ scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number);
+ return zoom;
+ };
+ zoom.x = function(z) {
+ if (!arguments.length) return x1;
+ x1 = z;
+ x0 = z.copy();
+ translate = [ 0, 0 ];
+ scale = 1;
+ return zoom;
+ };
+ zoom.y = function(z) {
+ if (!arguments.length) return y1;
+ y1 = z;
+ y0 = z.copy();
+ translate = [ 0, 0 ];
+ scale = 1;
+ return zoom;
+ };
+ function location(p) {
+ return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ];
+ }
+ function point(l) {
+ return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ];
+ }
+ function scaleTo(s) {
+ scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
+ }
+ function translateTo(p, l) {
+ l = point(l);
+ translate[0] += p[0] - l[0];
+ translate[1] += p[1] - l[1];
+ }
+ function rescale() {
+ if (x1) x1.domain(x0.range().map(function(x) {
+ return (x - translate[0]) / scale;
+ }).map(x0.invert));
+ if (y1) y1.domain(y0.range().map(function(y) {
+ return (y - translate[1]) / scale;
+ }).map(y0.invert));
+ }
+ function dispatch(event) {
+ rescale();
+ d3.event.preventDefault();
+ event({
+ type: "zoom",
+ scale: scale,
+ translate: translate
+ });
+ }
+ function mousedown() {
+ var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, moved = 0, w = d3.select(window).on("mousemove.zoom", mousemove).on("mouseup.zoom", mouseup), l = location(d3.mouse(target));
+ window.focus();
+ d3_eventCancel();
+ function mousemove() {
+ moved = 1;
+ translateTo(d3.mouse(target), l);
+ dispatch(event_);
+ }
+ function mouseup() {
+ if (moved) d3_eventCancel();
+ w.on("mousemove.zoom", null).on("mouseup.zoom", null);
+ if (moved && d3.event.target === eventTarget) w.on("click.zoom", click, true);
+ }
+ function click() {
+ d3_eventCancel();
+ w.on("click.zoom", null);
+ }
+ }
+ function mousewheel() {
+ if (!translate0) translate0 = location(d3.mouse(this));
+ scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale);
+ translateTo(d3.mouse(this), translate0);
+ dispatch(event.of(this, arguments));
+ }
+ function mousemove() {
+ translate0 = null;
+ }
+ function dblclick() {
+ var p = d3.mouse(this), l = location(p), k = Math.log(scale) / Math.LN2;
+ scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1));
+ translateTo(p, l);
+ dispatch(event.of(this, arguments));
+ }
+ function touchstart() {
+ var touches = d3.touches(this), now = Date.now();
+ scale0 = scale;
+ translate0 = {};
+ touches.forEach(function(t) {
+ translate0[t.identifier] = location(t);
+ });
+ d3_eventCancel();
+ if (touches.length === 1) {
+ if (now - touchtime < 500) {
+ var p = touches[0], l = location(touches[0]);
+ scaleTo(scale * 2);
+ translateTo(p, l);
+ dispatch(event.of(this, arguments));
+ }
+ touchtime = now;
+ }
+ }
+ function touchmove() {
+ var touches = d3.touches(this), p0 = touches[0], l0 = translate0[p0.identifier];
+ if (p1 = touches[1]) {
+ var p1, l1 = translate0[p1.identifier];
+ p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ];
+ l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ];
+ scaleTo(d3.event.scale * scale0);
+ }
+ translateTo(p0, l0);
+ touchtime = null;
+ dispatch(event.of(this, arguments));
+ }
+ return d3.rebind(zoom, event, "on");
+ };
+ var d3_behavior_zoomDiv, d3_behavior_zoomInfinity = [ 0, Infinity ];
+ function d3_behavior_zoomDelta() {
+ if (!d3_behavior_zoomDiv) {
+ d3_behavior_zoomDiv = d3.select("body").append("div").style("visibility", "hidden").style("top", 0).style("height", 0).style("width", 0).style("overflow-y", "scroll").append("div").style("height", "2000px").node().parentNode;
+ }
+ var e = d3.event, delta;
+ try {
+ d3_behavior_zoomDiv.scrollTop = 1e3;
+ d3_behavior_zoomDiv.dispatchEvent(e);
+ delta = 1e3 - d3_behavior_zoomDiv.scrollTop;
+ } catch (error) {
+ delta = e.wheelDelta || -e.detail * 5;
+ }
+ return delta;
+ }
+ d3.layout = {};
+ d3.layout.bundle = function() {
+ return function(links) {
+ var paths = [], i = -1, n = links.length;
+ while (++i < n) paths.push(d3_layout_bundlePath(links[i]));
+ return paths;
+ };
+ };
+ function d3_layout_bundlePath(link) {
+ var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ];
+ while (start !== lca) {
+ start = start.parent;
+ points.push(start);
+ }
+ var k = points.length;
+ while (end !== lca) {
+ points.splice(k, 0, end);
+ end = end.parent;
+ }
+ return points;
+ }
+ function d3_layout_bundleAncestors(node) {
+ var ancestors = [], parent = node.parent;
+ while (parent != null) {
+ ancestors.push(node);
+ node = parent;
+ parent = parent.parent;
+ }
+ ancestors.push(node);
+ return ancestors;
+ }
+ function d3_layout_bundleLeastCommonAncestor(a, b) {
+ if (a === b) return a;
+ var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null;
+ while (aNode === bNode) {
+ sharedNode = aNode;
+ aNode = aNodes.pop();
+ bNode = bNodes.pop();
+ }
+ return sharedNode;
+ }
+ d3.layout.chord = function() {
+ var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords;
+ function relayout() {
+ var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j;
+ chords = [];
+ groups = [];
+ k = 0, i = -1;
+ while (++i < n) {
+ x = 0, j = -1;
+ while (++j < n) {
+ x += matrix[i][j];
+ }
+ groupSums.push(x);
+ subgroupIndex.push(d3.range(n));
+ k += x;
+ }
+ if (sortGroups) {
+ groupIndex.sort(function(a, b) {
+ return sortGroups(groupSums[a], groupSums[b]);
+ });
+ }
+ if (sortSubgroups) {
+ subgroupIndex.forEach(function(d, i) {
+ d.sort(function(a, b) {
+ return sortSubgroups(matrix[i][a], matrix[i][b]);
+ });
+ });
+ }
+ k = (2 * π - padding * n) / k;
+ x = 0, i = -1;
+ while (++i < n) {
+ x0 = x, j = -1;
+ while (++j < n) {
+ var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k;
+ subgroups[di + "-" + dj] = {
+ index: di,
+ subindex: dj,
+ startAngle: a0,
+ endAngle: a1,
+ value: v
+ };
+ }
+ groups[di] = {
+ index: di,
+ startAngle: x0,
+ endAngle: x,
+ value: (x - x0) / k
+ };
+ x += padding;
+ }
+ i = -1;
+ while (++i < n) {
+ j = i - 1;
+ while (++j < n) {
+ var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i];
+ if (source.value || target.value) {
+ chords.push(source.value < target.value ? {
+ source: target,
+ target: source
+ } : {
+ source: source,
+ target: target
+ });
+ }
+ }
+ }
+ if (sortChords) resort();
+ }
+ function resort() {
+ chords.sort(function(a, b) {
+ return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2);
+ });
+ }
+ chord.matrix = function(x) {
+ if (!arguments.length) return matrix;
+ n = (matrix = x) && matrix.length;
+ chords = groups = null;
+ return chord;
+ };
+ chord.padding = function(x) {
+ if (!arguments.length) return padding;
+ padding = x;
+ chords = groups = null;
+ return chord;
+ };
+ chord.sortGroups = function(x) {
+ if (!arguments.length) return sortGroups;
+ sortGroups = x;
+ chords = groups = null;
+ return chord;
+ };
+ chord.sortSubgroups = function(x) {
+ if (!arguments.length) return sortSubgroups;
+ sortSubgroups = x;
+ chords = null;
+ return chord;
+ };
+ chord.sortChords = function(x) {
+ if (!arguments.length) return sortChords;
+ sortChords = x;
+ if (chords) resort();
+ return chord;
+ };
+ chord.chords = function() {
+ if (!chords) relayout();
+ return chords;
+ };
+ chord.groups = function() {
+ if (!groups) relayout();
+ return groups;
+ };
+ return chord;
+ };
+ d3.layout.force = function() {
+ var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, nodes = [], links = [], distances, strengths, charges;
+ function repulse(node) {
+ return function(quad, x1, _, x2) {
+ if (quad.point !== node) {
+ var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy);
+ if ((x2 - x1) * dn < theta) {
+ var k = quad.charge * dn * dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
+ return true;
+ }
+ if (quad.point && isFinite(dn)) {
+ var k = quad.pointCharge * dn * dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
+ }
+ }
+ return !quad.charge;
+ };
+ }
+ force.tick = function() {
+ if ((alpha *= .99) < .005) {
+ event.end({
+ type: "end",
+ alpha: alpha = 0
+ });
+ return true;
+ }
+ var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y;
+ for (i = 0; i < m; ++i) {
+ o = links[i];
+ s = o.source;
+ t = o.target;
+ x = t.x - s.x;
+ y = t.y - s.y;
+ if (l = x * x + y * y) {
+ l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
+ x *= l;
+ y *= l;
+ t.x -= x * (k = s.weight / (t.weight + s.weight));
+ t.y -= y * k;
+ s.x += x * (k = 1 - k);
+ s.y += y * k;
+ }
+ }
+ if (k = alpha * gravity) {
+ x = size[0] / 2;
+ y = size[1] / 2;
+ i = -1;
+ if (k) while (++i < n) {
+ o = nodes[i];
+ o.x += (x - o.x) * k;
+ o.y += (y - o.y) * k;
+ }
+ }
+ if (charge) {
+ d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);
+ i = -1;
+ while (++i < n) {
+ if (!(o = nodes[i]).fixed) {
+ q.visit(repulse(o));
+ }
+ }
+ }
+ i = -1;
+ while (++i < n) {
+ o = nodes[i];
+ if (o.fixed) {
+ o.x = o.px;
+ o.y = o.py;
+ } else {
+ o.x -= (o.px - (o.px = o.x)) * friction;
+ o.y -= (o.py - (o.py = o.y)) * friction;
+ }
+ }
+ event.tick({
+ type: "tick",
+ alpha: alpha
+ });
+ };
+ force.nodes = function(x) {
+ if (!arguments.length) return nodes;
+ nodes = x;
+ return force;
+ };
+ force.links = function(x) {
+ if (!arguments.length) return links;
+ links = x;
+ return force;
+ };
+ force.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return force;
+ };
+ force.linkDistance = function(x) {
+ if (!arguments.length) return linkDistance;
+ linkDistance = d3_functor(x);
+ return force;
+ };
+ force.distance = force.linkDistance;
+ force.linkStrength = function(x) {
+ if (!arguments.length) return linkStrength;
+ linkStrength = d3_functor(x);
+ return force;
+ };
+ force.friction = function(x) {
+ if (!arguments.length) return friction;
+ friction = x;
+ return force;
+ };
+ force.charge = function(x) {
+ if (!arguments.length) return charge;
+ charge = typeof x === "function" ? x : +x;
+ return force;
+ };
+ force.gravity = function(x) {
+ if (!arguments.length) return gravity;
+ gravity = x;
+ return force;
+ };
+ force.theta = function(x) {
+ if (!arguments.length) return theta;
+ theta = x;
+ return force;
+ };
+ force.alpha = function(x) {
+ if (!arguments.length) return alpha;
+ if (alpha) {
+ if (x > 0) alpha = x; else alpha = 0;
+ } else if (x > 0) {
+ event.start({
+ type: "start",
+ alpha: alpha = x
+ });
+ d3.timer(force.tick);
+ }
+ return force;
+ };
+ force.start = function() {
+ var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o;
+ for (i = 0; i < n; ++i) {
+ (o = nodes[i]).index = i;
+ o.weight = 0;
+ }
+ distances = [];
+ strengths = [];
+ for (i = 0; i < m; ++i) {
+ o = links[i];
+ if (typeof o.source == "number") o.source = nodes[o.source];
+ if (typeof o.target == "number") o.target = nodes[o.target];
+ distances[i] = linkDistance.call(this, o, i);
+ strengths[i] = linkStrength.call(this, o, i);
+ ++o.source.weight;
+ ++o.target.weight;
+ }
+ for (i = 0; i < n; ++i) {
+ o = nodes[i];
+ if (isNaN(o.x)) o.x = position("x", w);
+ if (isNaN(o.y)) o.y = position("y", h);
+ if (isNaN(o.px)) o.px = o.x;
+ if (isNaN(o.py)) o.py = o.y;
+ }
+ charges = [];
+ if (typeof charge === "function") {
+ for (i = 0; i < n; ++i) {
+ charges[i] = +charge.call(this, nodes[i], i);
+ }
+ } else {
+ for (i = 0; i < n; ++i) {
+ charges[i] = charge;
+ }
+ }
+ function position(dimension, size) {
+ var neighbors = neighbor(i), j = -1, m = neighbors.length, x;
+ while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x;
+ return Math.random() * size;
+ }
+ function neighbor() {
+ if (!neighbors) {
+ neighbors = [];
+ for (j = 0; j < n; ++j) {
+ neighbors[j] = [];
+ }
+ for (j = 0; j < m; ++j) {
+ var o = links[j];
+ neighbors[o.source.index].push(o.target);
+ neighbors[o.target.index].push(o.source);
+ }
+ }
+ return neighbors[i];
+ }
+ return force.resume();
+ };
+ force.resume = function() {
+ return force.alpha(.1);
+ };
+ force.stop = function() {
+ return force.alpha(0);
+ };
+ force.drag = function() {
+ if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart", d3_layout_forceDragstart).on("drag", dragmove).on("dragend", d3_layout_forceDragend);
+ this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag);
+ };
+ function dragmove(d) {
+ d.px = d3.event.x, d.py = d3.event.y;
+ force.resume();
+ }
+ return d3.rebind(force, event, "on");
+ };
+ function d3_layout_forceDragstart(d) {
+ d.fixed |= 2;
+ }
+ function d3_layout_forceDragend(d) {
+ d.fixed &= 1;
+ }
+ function d3_layout_forceMouseover(d) {
+ d.fixed |= 4;
+ d.px = d.x, d.py = d.y;
+ }
+ function d3_layout_forceMouseout(d) {
+ d.fixed &= 3;
+ }
+ function d3_layout_forceAccumulate(quad, alpha, charges) {
+ var cx = 0, cy = 0;
+ quad.charge = 0;
+ if (!quad.leaf) {
+ var nodes = quad.nodes, n = nodes.length, i = -1, c;
+ while (++i < n) {
+ c = nodes[i];
+ if (c == null) continue;
+ d3_layout_forceAccumulate(c, alpha, charges);
+ quad.charge += c.charge;
+ cx += c.charge * c.cx;
+ cy += c.charge * c.cy;
+ }
+ }
+ if (quad.point) {
+ if (!quad.leaf) {
+ quad.point.x += Math.random() - .5;
+ quad.point.y += Math.random() - .5;
+ }
+ var k = alpha * charges[quad.point.index];
+ quad.charge += quad.pointCharge = k;
+ cx += k * quad.point.x;
+ cy += k * quad.point.y;
+ }
+ quad.cx = cx / quad.charge;
+ quad.cy = cy / quad.charge;
+ }
+ function d3_layout_forceLinkDistance() {
+ return 20;
+ }
+ function d3_layout_forceLinkStrength() {
+ return 1;
+ }
+ d3.layout.partition = function() {
+ var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ];
+ function position(node, x, dx, dy) {
+ var children = node.children;
+ node.x = x;
+ node.y = node.depth * dy;
+ node.dx = dx;
+ node.dy = dy;
+ if (children && (n = children.length)) {
+ var i = -1, n, c, d;
+ dx = node.value ? dx / node.value : 0;
+ while (++i < n) {
+ position(c = children[i], x, d = c.value * dx, dy);
+ x += d;
+ }
+ }
+ }
+ function depth(node) {
+ var children = node.children, d = 0;
+ if (children && (n = children.length)) {
+ var i = -1, n;
+ while (++i < n) d = Math.max(d, depth(children[i]));
+ }
+ return 1 + d;
+ }
+ function partition(d, i) {
+ var nodes = hierarchy.call(this, d, i);
+ position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
+ return nodes;
+ }
+ partition.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return partition;
+ };
+ return d3_layout_hierarchyRebind(partition, hierarchy);
+ };
+ d3.layout.pie = function() {
+ var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 * π;
+ function pie(data) {
+ var values = data.map(function(d, i) {
+ return +value.call(pie, d, i);
+ });
+ var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle);
+ var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - startAngle) / d3.sum(values);
+ var index = d3.range(data.length);
+ if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) {
+ return values[j] - values[i];
+ } : function(i, j) {
+ return sort(data[i], data[j]);
+ });
+ var arcs = [];
+ index.forEach(function(i) {
+ var d;
+ arcs[i] = {
+ data: data[i],
+ value: d = values[i],
+ startAngle: a,
+ endAngle: a += d * k
+ };
+ });
+ return arcs;
+ }
+ pie.value = function(x) {
+ if (!arguments.length) return value;
+ value = x;
+ return pie;
+ };
+ pie.sort = function(x) {
+ if (!arguments.length) return sort;
+ sort = x;
+ return pie;
+ };
+ pie.startAngle = function(x) {
+ if (!arguments.length) return startAngle;
+ startAngle = x;
+ return pie;
+ };
+ pie.endAngle = function(x) {
+ if (!arguments.length) return endAngle;
+ endAngle = x;
+ return pie;
+ };
+ return pie;
+ };
+ var d3_layout_pieSortByValue = {};
+ d3.layout.stack = function() {
+ var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY;
+ function stack(data, index) {
+ var series = data.map(function(d, i) {
+ return values.call(stack, d, i);
+ });
+ var points = series.map(function(d) {
+ return d.map(function(v, i) {
+ return [ x.call(stack, v, i), y.call(stack, v, i) ];
+ });
+ });
+ var orders = order.call(stack, points, index);
+ series = d3.permute(series, orders);
+ points = d3.permute(points, orders);
+ var offsets = offset.call(stack, points, index);
+ var n = series.length, m = series[0].length, i, j, o;
+ for (j = 0; j < m; ++j) {
+ out.call(stack, series[0][j], o = offsets[j], points[0][j][1]);
+ for (i = 1; i < n; ++i) {
+ out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]);
+ }
+ }
+ return data;
+ }
+ stack.values = function(x) {
+ if (!arguments.length) return values;
+ values = x;
+ return stack;
+ };
+ stack.order = function(x) {
+ if (!arguments.length) return order;
+ order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault;
+ return stack;
+ };
+ stack.offset = function(x) {
+ if (!arguments.length) return offset;
+ offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero;
+ return stack;
+ };
+ stack.x = function(z) {
+ if (!arguments.length) return x;
+ x = z;
+ return stack;
+ };
+ stack.y = function(z) {
+ if (!arguments.length) return y;
+ y = z;
+ return stack;
+ };
+ stack.out = function(z) {
+ if (!arguments.length) return out;
+ out = z;
+ return stack;
+ };
+ return stack;
+ };
+ function d3_layout_stackX(d) {
+ return d.x;
+ }
+ function d3_layout_stackY(d) {
+ return d.y;
+ }
+ function d3_layout_stackOut(d, y0, y) {
+ d.y0 = y0;
+ d.y = y;
+ }
+ var d3_layout_stackOrders = d3.map({
+ "inside-out": function(data) {
+ var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) {
+ return max[a] - max[b];
+ }), top = 0, bottom = 0, tops = [], bottoms = [];
+ for (i = 0; i < n; ++i) {
+ j = index[i];
+ if (top < bottom) {
+ top += sums[j];
+ tops.push(j);
+ } else {
+ bottom += sums[j];
+ bottoms.push(j);
+ }
+ }
+ return bottoms.reverse().concat(tops);
+ },
+ reverse: function(data) {
+ return d3.range(data.length).reverse();
+ },
+ "default": d3_layout_stackOrderDefault
+ });
+ var d3_layout_stackOffsets = d3.map({
+ silhouette: function(data) {
+ var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = [];
+ for (j = 0; j < m; ++j) {
+ for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
+ if (o > max) max = o;
+ sums.push(o);
+ }
+ for (j = 0; j < m; ++j) {
+ y0[j] = (max - sums[j]) / 2;
+ }
+ return y0;
+ },
+ wiggle: function(data) {
+ var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = [];
+ y0[0] = o = o0 = 0;
+ for (j = 1; j < m; ++j) {
+ for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1];
+ for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) {
+ for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) {
+ s3 += (data[k][j][1] - data[k][j - 1][1]) / dx;
+ }
+ s2 += s3 * data[i][j][1];
+ }
+ y0[j] = o -= s1 ? s2 / s1 * dx : 0;
+ if (o < o0) o0 = o;
+ }
+ for (j = 0; j < m; ++j) y0[j] -= o0;
+ return y0;
+ },
+ expand: function(data) {
+ var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = [];
+ for (j = 0; j < m; ++j) {
+ for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
+ if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k;
+ }
+ for (j = 0; j < m; ++j) y0[j] = 0;
+ return y0;
+ },
+ zero: d3_layout_stackOffsetZero
+ });
+ function d3_layout_stackOrderDefault(data) {
+ return d3.range(data.length);
+ }
+ function d3_layout_stackOffsetZero(data) {
+ var j = -1, m = data[0].length, y0 = [];
+ while (++j < m) y0[j] = 0;
+ return y0;
+ }
+ function d3_layout_stackMaxIndex(array) {
+ var i = 1, j = 0, v = array[0][1], k, n = array.length;
+ for (;i < n; ++i) {
+ if ((k = array[i][1]) > v) {
+ j = i;
+ v = k;
+ }
+ }
+ return j;
+ }
+ function d3_layout_stackReduceSum(d) {
+ return d.reduce(d3_layout_stackSum, 0);
+ }
+ function d3_layout_stackSum(p, d) {
+ return p + d[1];
+ }
+ d3.layout.histogram = function() {
+ var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges;
+ function histogram(data, i) {
+ var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x;
+ while (++i < m) {
+ bin = bins[i] = [];
+ bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);
+ bin.y = 0;
+ }
+ if (m > 0) {
+ i = -1;
+ while (++i < n) {
+ x = values[i];
+ if (x >= range[0] && x <= range[1]) {
+ bin = bins[d3.bisect(thresholds, x, 1, m) - 1];
+ bin.y += k;
+ bin.push(data[i]);
+ }
+ }
+ }
+ return bins;
+ }
+ histogram.value = function(x) {
+ if (!arguments.length) return valuer;
+ valuer = x;
+ return histogram;
+ };
+ histogram.range = function(x) {
+ if (!arguments.length) return ranger;
+ ranger = d3_functor(x);
+ return histogram;
+ };
+ histogram.bins = function(x) {
+ if (!arguments.length) return binner;
+ binner = typeof x === "number" ? function(range) {
+ return d3_layout_histogramBinFixed(range, x);
+ } : d3_functor(x);
+ return histogram;
+ };
+ histogram.frequency = function(x) {
+ if (!arguments.length) return frequency;
+ frequency = !!x;
+ return histogram;
+ };
+ return histogram;
+ };
+ function d3_layout_histogramBinSturges(range, values) {
+ return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1));
+ }
+ function d3_layout_histogramBinFixed(range, n) {
+ var x = -1, b = +range[0], m = (range[1] - b) / n, f = [];
+ while (++x <= n) f[x] = m * x + b;
+ return f;
+ }
+ function d3_layout_histogramRange(values) {
+ return [ d3.min(values), d3.max(values) ];
+ }
+ d3.layout.hierarchy = function() {
+ var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue;
+ function recurse(node, depth, nodes) {
+ var childs = children.call(hierarchy, node, depth);
+ node.depth = depth;
+ nodes.push(node);
+ if (childs && (n = childs.length)) {
+ var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d;
+ while (++i < n) {
+ d = recurse(childs[i], j, nodes);
+ d.parent = node;
+ c.push(d);
+ v += d.value;
+ }
+ if (sort) c.sort(sort);
+ if (value) node.value = v;
+ } else if (value) {
+ node.value = +value.call(hierarchy, node, depth) || 0;
+ }
+ return node;
+ }
+ function revalue(node, depth) {
+ var children = node.children, v = 0;
+ if (children && (n = children.length)) {
+ var i = -1, n, j = depth + 1;
+ while (++i < n) v += revalue(children[i], j);
+ } else if (value) {
+ v = +value.call(hierarchy, node, depth) || 0;
+ }
+ if (value) node.value = v;
+ return v;
+ }
+ function hierarchy(d) {
+ var nodes = [];
+ recurse(d, 0, nodes);
+ return nodes;
+ }
+ hierarchy.sort = function(x) {
+ if (!arguments.length) return sort;
+ sort = x;
+ return hierarchy;
+ };
+ hierarchy.children = function(x) {
+ if (!arguments.length) return children;
+ children = x;
+ return hierarchy;
+ };
+ hierarchy.value = function(x) {
+ if (!arguments.length) return value;
+ value = x;
+ return hierarchy;
+ };
+ hierarchy.revalue = function(root) {
+ revalue(root, 0);
+ return root;
+ };
+ return hierarchy;
+ };
+ function d3_layout_hierarchyRebind(object, hierarchy) {
+ d3.rebind(object, hierarchy, "sort", "children", "value");
+ object.nodes = object;
+ object.links = d3_layout_hierarchyLinks;
+ return object;
+ }
+ function d3_layout_hierarchyChildren(d) {
+ return d.children;
+ }
+ function d3_layout_hierarchyValue(d) {
+ return d.value;
+ }
+ function d3_layout_hierarchySort(a, b) {
+ return b.value - a.value;
+ }
+ function d3_layout_hierarchyLinks(nodes) {
+ return d3.merge(nodes.map(function(parent) {
+ return (parent.children || []).map(function(child) {
+ return {
+ source: parent,
+ target: child
+ };
+ });
+ }));
+ }
+ d3.layout.pack = function() {
+ var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ];
+ function pack(d, i) {
+ var nodes = hierarchy.call(this, d, i), root = nodes[0];
+ root.x = 0;
+ root.y = 0;
+ d3_layout_treeVisitAfter(root, function(d) {
+ d.r = Math.sqrt(d.value);
+ });
+ d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
+ var w = size[0], h = size[1], k = Math.max(2 * root.r / w, 2 * root.r / h);
+ if (padding > 0) {
+ var dr = padding * k / 2;
+ d3_layout_treeVisitAfter(root, function(d) {
+ d.r += dr;
+ });
+ d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
+ d3_layout_treeVisitAfter(root, function(d) {
+ d.r -= dr;
+ });
+ k = Math.max(2 * root.r / w, 2 * root.r / h);
+ }
+ d3_layout_packTransform(root, w / 2, h / 2, 1 / k);
+ return nodes;
+ }
+ pack.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return pack;
+ };
+ pack.padding = function(_) {
+ if (!arguments.length) return padding;
+ padding = +_;
+ return pack;
+ };
+ return d3_layout_hierarchyRebind(pack, hierarchy);
+ };
+ function d3_layout_packSort(a, b) {
+ return a.value - b.value;
+ }
+ function d3_layout_packInsert(a, b) {
+ var c = a._pack_next;
+ a._pack_next = b;
+ b._pack_prev = a;
+ b._pack_next = c;
+ c._pack_prev = b;
+ }
+ function d3_layout_packSplice(a, b) {
+ a._pack_next = b;
+ b._pack_prev = a;
+ }
+ function d3_layout_packIntersects(a, b) {
+ var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r;
+ return dr * dr - dx * dx - dy * dy > .001;
+ }
+ function d3_layout_packSiblings(node) {
+ if (!(nodes = node.children) || !(n = nodes.length)) return;
+ var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n;
+ function bound(node) {
+ xMin = Math.min(node.x - node.r, xMin);
+ xMax = Math.max(node.x + node.r, xMax);
+ yMin = Math.min(node.y - node.r, yMin);
+ yMax = Math.max(node.y + node.r, yMax);
+ }
+ nodes.forEach(d3_layout_packLink);
+ a = nodes[0];
+ a.x = -a.r;
+ a.y = 0;
+ bound(a);
+ if (n > 1) {
+ b = nodes[1];
+ b.x = b.r;
+ b.y = 0;
+ bound(b);
+ if (n > 2) {
+ c = nodes[2];
+ d3_layout_packPlace(a, b, c);
+ bound(c);
+ d3_layout_packInsert(a, c);
+ a._pack_prev = c;
+ d3_layout_packInsert(c, b);
+ b = a._pack_next;
+ for (i = 3; i < n; i++) {
+ d3_layout_packPlace(a, b, c = nodes[i]);
+ var isect = 0, s1 = 1, s2 = 1;
+ for (j = b._pack_next; j !== b; j = j._pack_next, s1++) {
+ if (d3_layout_packIntersects(j, c)) {
+ isect = 1;
+ break;
+ }
+ }
+ if (isect == 1) {
+ for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) {
+ if (d3_layout_packIntersects(k, c)) {
+ break;
+ }
+ }
+ }
+ if (isect) {
+ if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b);
+ i--;
+ } else {
+ d3_layout_packInsert(a, c);
+ b = c;
+ bound(c);
+ }
+ }
+ }
+ }
+ var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0;
+ for (i = 0; i < n; i++) {
+ c = nodes[i];
+ c.x -= cx;
+ c.y -= cy;
+ cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y));
+ }
+ node.r = cr;
+ nodes.forEach(d3_layout_packUnlink);
+ }
+ function d3_layout_packLink(node) {
+ node._pack_next = node._pack_prev = node;
+ }
+ function d3_layout_packUnlink(node) {
+ delete node._pack_next;
+ delete node._pack_prev;
+ }
+ function d3_layout_packTransform(node, x, y, k) {
+ var children = node.children;
+ node.x = x += k * node.x;
+ node.y = y += k * node.y;
+ node.r *= k;
+ if (children) {
+ var i = -1, n = children.length;
+ while (++i < n) d3_layout_packTransform(children[i], x, y, k);
+ }
+ }
+ function d3_layout_packPlace(a, b, c) {
+ var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y;
+ if (db && (dx || dy)) {
+ var da = b.r + c.r, dc = dx * dx + dy * dy;
+ da *= da;
+ db *= db;
+ var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
+ c.x = a.x + x * dx + y * dy;
+ c.y = a.y + x * dy - y * dx;
+ } else {
+ c.x = a.x + db;
+ c.y = a.y;
+ }
+ }
+ d3.layout.cluster = function() {
+ var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ];
+ function cluster(d, i) {
+ var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0;
+ d3_layout_treeVisitAfter(root, function(node) {
+ var children = node.children;
+ if (children && children.length) {
+ node.x = d3_layout_clusterX(children);
+ node.y = d3_layout_clusterY(children);
+ } else {
+ node.x = previousNode ? x += separation(node, previousNode) : 0;
+ node.y = 0;
+ previousNode = node;
+ }
+ });
+ var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2;
+ d3_layout_treeVisitAfter(root, function(node) {
+ node.x = (node.x - x0) / (x1 - x0) * size[0];
+ node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1];
+ });
+ return nodes;
+ }
+ cluster.separation = function(x) {
+ if (!arguments.length) return separation;
+ separation = x;
+ return cluster;
+ };
+ cluster.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return cluster;
+ };
+ return d3_layout_hierarchyRebind(cluster, hierarchy);
+ };
+ function d3_layout_clusterY(children) {
+ return 1 + d3.max(children, function(child) {
+ return child.y;
+ });
+ }
+ function d3_layout_clusterX(children) {
+ return children.reduce(function(x, child) {
+ return x + child.x;
+ }, 0) / children.length;
+ }
+ function d3_layout_clusterLeft(node) {
+ var children = node.children;
+ return children && children.length ? d3_layout_clusterLeft(children[0]) : node;
+ }
+ function d3_layout_clusterRight(node) {
+ var children = node.children, n;
+ return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node;
+ }
+ d3.layout.tree = function() {
+ var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ];
+ function tree(d, i) {
+ var nodes = hierarchy.call(this, d, i), root = nodes[0];
+ function firstWalk(node, previousSibling) {
+ var children = node.children, layout = node._tree;
+ if (children && (n = children.length)) {
+ var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1;
+ while (++i < n) {
+ child = children[i];
+ firstWalk(child, previousChild);
+ ancestor = apportion(child, previousChild, ancestor);
+ previousChild = child;
+ }
+ d3_layout_treeShift(node);
+ var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim);
+ if (previousSibling) {
+ layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
+ layout.mod = layout.prelim - midpoint;
+ } else {
+ layout.prelim = midpoint;
+ }
+ } else {
+ if (previousSibling) {
+ layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
+ }
+ }
+ }
+ function secondWalk(node, x) {
+ node.x = node._tree.prelim + x;
+ var children = node.children;
+ if (children && (n = children.length)) {
+ var i = -1, n;
+ x += node._tree.mod;
+ while (++i < n) {
+ secondWalk(children[i], x);
+ }
+ }
+ }
+ function apportion(node, previousSibling, ancestor) {
+ if (previousSibling) {
+ var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift;
+ while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) {
+ vom = d3_layout_treeLeft(vom);
+ vop = d3_layout_treeRight(vop);
+ vop._tree.ancestor = node;
+ shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip);
+ if (shift > 0) {
+ d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift);
+ sip += shift;
+ sop += shift;
+ }
+ sim += vim._tree.mod;
+ sip += vip._tree.mod;
+ som += vom._tree.mod;
+ sop += vop._tree.mod;
+ }
+ if (vim && !d3_layout_treeRight(vop)) {
+ vop._tree.thread = vim;
+ vop._tree.mod += sim - sop;
+ }
+ if (vip && !d3_layout_treeLeft(vom)) {
+ vom._tree.thread = vip;
+ vom._tree.mod += sip - som;
+ ancestor = node;
+ }
+ }
+ return ancestor;
+ }
+ d3_layout_treeVisitAfter(root, function(node, previousSibling) {
+ node._tree = {
+ ancestor: node,
+ prelim: 0,
+ mod: 0,
+ change: 0,
+ shift: 0,
+ number: previousSibling ? previousSibling._tree.number + 1 : 0
+ };
+ });
+ firstWalk(root);
+ secondWalk(root, -root._tree.prelim);
+ var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1;
+ d3_layout_treeVisitAfter(root, function(node) {
+ node.x = (node.x - x0) / (x1 - x0) * size[0];
+ node.y = node.depth / y1 * size[1];
+ delete node._tree;
+ });
+ return nodes;
+ }
+ tree.separation = function(x) {
+ if (!arguments.length) return separation;
+ separation = x;
+ return tree;
+ };
+ tree.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return tree;
+ };
+ return d3_layout_hierarchyRebind(tree, hierarchy);
+ };
+ function d3_layout_treeSeparation(a, b) {
+ return a.parent == b.parent ? 1 : 2;
+ }
+ function d3_layout_treeLeft(node) {
+ var children = node.children;
+ return children && children.length ? children[0] : node._tree.thread;
+ }
+ function d3_layout_treeRight(node) {
+ var children = node.children, n;
+ return children && (n = children.length) ? children[n - 1] : node._tree.thread;
+ }
+ function d3_layout_treeSearch(node, compare) {
+ var children = node.children;
+ if (children && (n = children.length)) {
+ var child, n, i = -1;
+ while (++i < n) {
+ if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
+ node = child;
+ }
+ }
+ }
+ return node;
+ }
+ function d3_layout_treeRightmost(a, b) {
+ return a.x - b.x;
+ }
+ function d3_layout_treeLeftmost(a, b) {
+ return b.x - a.x;
+ }
+ function d3_layout_treeDeepest(a, b) {
+ return a.depth - b.depth;
+ }
+ function d3_layout_treeVisitAfter(node, callback) {
+ function visit(node, previousSibling) {
+ var children = node.children;
+ if (children && (n = children.length)) {
+ var child, previousChild = null, i = -1, n;
+ while (++i < n) {
+ child = children[i];
+ visit(child, previousChild);
+ previousChild = child;
+ }
+ }
+ callback(node, previousSibling);
+ }
+ visit(node, null);
+ }
+ function d3_layout_treeShift(node) {
+ var shift = 0, change = 0, children = node.children, i = children.length, child;
+ while (--i >= 0) {
+ child = children[i]._tree;
+ child.prelim += shift;
+ child.mod += shift;
+ shift += child.shift + (change += child.change);
+ }
+ }
+ function d3_layout_treeMove(ancestor, node, shift) {
+ ancestor = ancestor._tree;
+ node = node._tree;
+ var change = shift / (node.number - ancestor.number);
+ ancestor.change += change;
+ node.change -= change;
+ node.shift += shift;
+ node.prelim += shift;
+ node.mod += shift;
+ }
+ function d3_layout_treeAncestor(vim, node, ancestor) {
+ return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor;
+ }
+ d3.layout.treemap = function() {
+ var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5));
+ function scale(children, k) {
+ var i = -1, n = children.length, child, area;
+ while (++i < n) {
+ area = (child = children[i]).value * (k < 0 ? 0 : k);
+ child.area = isNaN(area) || area <= 0 ? 0 : area;
+ }
+ }
+ function squarify(node) {
+ var children = node.children;
+ if (children && children.length) {
+ var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n;
+ scale(remaining, rect.dx * rect.dy / node.value);
+ row.area = 0;
+ while ((n = remaining.length) > 0) {
+ row.push(child = remaining[n - 1]);
+ row.area += child.area;
+ if (mode !== "squarify" || (score = worst(row, u)) <= best) {
+ remaining.pop();
+ best = score;
+ } else {
+ row.area -= row.pop().area;
+ position(row, u, rect, false);
+ u = Math.min(rect.dx, rect.dy);
+ row.length = row.area = 0;
+ best = Infinity;
+ }
+ }
+ if (row.length) {
+ position(row, u, rect, true);
+ row.length = row.area = 0;
+ }
+ children.forEach(squarify);
+ }
+ }
+ function stickify(node) {
+ var children = node.children;
+ if (children && children.length) {
+ var rect = pad(node), remaining = children.slice(), child, row = [];
+ scale(remaining, rect.dx * rect.dy / node.value);
+ row.area = 0;
+ while (child = remaining.pop()) {
+ row.push(child);
+ row.area += child.area;
+ if (child.z != null) {
+ position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);
+ row.length = row.area = 0;
+ }
+ }
+ children.forEach(stickify);
+ }
+ }
+ function worst(row, u) {
+ var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length;
+ while (++i < n) {
+ if (!(r = row[i].area)) continue;
+ if (r < rmin) rmin = r;
+ if (r > rmax) rmax = r;
+ }
+ s *= s;
+ u *= u;
+ return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity;
+ }
+ function position(row, u, rect, flush) {
+ var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o;
+ if (u == rect.dx) {
+ if (flush || v > rect.dy) v = rect.dy;
+ while (++i < n) {
+ o = row[i];
+ o.x = x;
+ o.y = y;
+ o.dy = v;
+ x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0);
+ }
+ o.z = true;
+ o.dx += rect.x + rect.dx - x;
+ rect.y += v;
+ rect.dy -= v;
+ } else {
+ if (flush || v > rect.dx) v = rect.dx;
+ while (++i < n) {
+ o = row[i];
+ o.x = x;
+ o.y = y;
+ o.dx = v;
+ y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0);
+ }
+ o.z = false;
+ o.dy += rect.y + rect.dy - y;
+ rect.x += v;
+ rect.dx -= v;
+ }
+ }
+ function treemap(d) {
+ var nodes = stickies || hierarchy(d), root = nodes[0];
+ root.x = 0;
+ root.y = 0;
+ root.dx = size[0];
+ root.dy = size[1];
+ if (stickies) hierarchy.revalue(root);
+ scale([ root ], root.dx * root.dy / root.value);
+ (stickies ? stickify : squarify)(root);
+ if (sticky) stickies = nodes;
+ return nodes;
+ }
+ treemap.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return treemap;
+ };
+ treemap.padding = function(x) {
+ if (!arguments.length) return padding;
+ function padFunction(node) {
+ var p = x.call(treemap, node, node.depth);
+ return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p);
+ }
+ function padConstant(node) {
+ return d3_layout_treemapPad(node, x);
+ }
+ var type;
+ pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ],
+ padConstant) : padConstant;
+ return treemap;
+ };
+ treemap.round = function(x) {
+ if (!arguments.length) return round != Number;
+ round = x ? Math.round : Number;
+ return treemap;
+ };
+ treemap.sticky = function(x) {
+ if (!arguments.length) return sticky;
+ sticky = x;
+ stickies = null;
+ return treemap;
+ };
+ treemap.ratio = function(x) {
+ if (!arguments.length) return ratio;
+ ratio = x;
+ return treemap;
+ };
+ treemap.mode = function(x) {
+ if (!arguments.length) return mode;
+ mode = x + "";
+ return treemap;
+ };
+ return d3_layout_hierarchyRebind(treemap, hierarchy);
+ };
+ function d3_layout_treemapPadNull(node) {
+ return {
+ x: node.x,
+ y: node.y,
+ dx: node.dx,
+ dy: node.dy
+ };
+ }
+ function d3_layout_treemapPad(node, padding) {
+ var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2];
+ if (dx < 0) {
+ x += dx / 2;
+ dx = 0;
+ }
+ if (dy < 0) {
+ y += dy / 2;
+ dy = 0;
+ }
+ return {
+ x: x,
+ y: y,
+ dx: dx,
+ dy: dy
+ };
+ }
+ function d3_dsv(delimiter, mimeType) {
+ var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0);
+ function dsv(url, callback) {
+ return d3.xhr(url, mimeType, callback).response(response);
+ }
+ function response(request) {
+ return dsv.parse(request.responseText);
+ }
+ dsv.parse = function(text) {
+ var o;
+ return dsv.parseRows(text, function(row) {
+ if (o) return o(row);
+ o = new Function("d", "return {" + row.map(function(name, i) {
+ return JSON.stringify(name) + ": d[" + i + "]";
+ }).join(",") + "}");
+ });
+ };
+ dsv.parseRows = function(text, f) {
+ var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol;
+ function token() {
+ if (I >= N) return EOF;
+ if (eol) return eol = false, EOL;
+ var j = I;
+ if (text.charCodeAt(j) === 34) {
+ var i = j;
+ while (i++ < N) {
+ if (text.charCodeAt(i) === 34) {
+ if (text.charCodeAt(i + 1) !== 34) break;
+ ++i;
+ }
+ }
+ I = i + 2;
+ var c = text.charCodeAt(i + 1);
+ if (c === 13) {
+ eol = true;
+ if (text.charCodeAt(i + 2) === 10) ++I;
+ } else if (c === 10) {
+ eol = true;
+ }
+ return text.substring(j + 1, i).replace(/""/g, '"');
+ }
+ while (I < N) {
+ var c = text.charCodeAt(I++), k = 1;
+ if (c === 10) eol = true; else if (c === 13) {
+ eol = true;
+ if (text.charCodeAt(I) === 10) ++I, ++k;
+ } else if (c !== delimiterCode) continue;
+ return text.substring(j, I - k);
+ }
+ return text.substring(j);
+ }
+ while ((t = token()) !== EOF) {
+ var a = [];
+ while (t !== EOL && t !== EOF) {
+ a.push(t);
+ t = token();
+ }
+ if (f && !(a = f(a, n++))) continue;
+ rows.push(a);
+ }
+ return rows;
+ };
+ dsv.format = function(rows) {
+ return rows.map(formatRow).join("\n");
+ };
+ function formatRow(row) {
+ return row.map(formatValue).join(delimiter);
+ }
+ function formatValue(text) {
+ return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text;
+ }
+ return dsv;
+ }
+ d3.csv = d3_dsv(",", "text/csv");
+ d3.tsv = d3_dsv(" ", "text/tab-separated-values");
+ d3.geo = {};
+ d3.geo.stream = function(object, listener) {
+ if (d3_geo_streamObjectType.hasOwnProperty(object.type)) {
+ d3_geo_streamObjectType[object.type](object, listener);
+ } else {
+ d3_geo_streamGeometry(object, listener);
+ }
+ };
+ function d3_geo_streamGeometry(geometry, listener) {
+ if (d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) {
+ d3_geo_streamGeometryType[geometry.type](geometry, listener);
+ }
+ }
+ var d3_geo_streamObjectType = {
+ Feature: function(feature, listener) {
+ d3_geo_streamGeometry(feature.geometry, listener);
+ },
+ FeatureCollection: function(object, listener) {
+ var features = object.features, i = -1, n = features.length;
+ while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener);
+ }
+ };
+ var d3_geo_streamGeometryType = {
+ Sphere: function(object, listener) {
+ listener.sphere();
+ },
+ Point: function(object, listener) {
+ var coordinate = object.coordinates;
+ listener.point(coordinate[0], coordinate[1]);
+ },
+ MultiPoint: function(object, listener) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length, coordinate;
+ while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]);
+ },
+ LineString: function(object, listener) {
+ d3_geo_streamLine(object.coordinates, listener, 0);
+ },
+ MultiLineString: function(object, listener) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0);
+ },
+ Polygon: function(object, listener) {
+ d3_geo_streamPolygon(object.coordinates, listener);
+ },
+ MultiPolygon: function(object, listener) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) d3_geo_streamPolygon(coordinates[i], listener);
+ },
+ GeometryCollection: function(object, listener) {
+ var geometries = object.geometries, i = -1, n = geometries.length;
+ while (++i < n) d3_geo_streamGeometry(geometries[i], listener);
+ }
+ };
+ function d3_geo_streamLine(coordinates, listener, closed) {
+ var i = -1, n = coordinates.length - closed, coordinate;
+ listener.lineStart();
+ while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]);
+ listener.lineEnd();
+ }
+ function d3_geo_streamPolygon(coordinates, listener) {
+ var i = -1, n = coordinates.length;
+ listener.polygonStart();
+ while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1);
+ listener.polygonEnd();
+ }
+ function d3_geo_spherical(cartesian) {
+ return [ Math.atan2(cartesian[1], cartesian[0]), Math.asin(Math.max(-1, Math.min(1, cartesian[2]))) ];
+ }
+ function d3_geo_sphericalEqual(a, b) {
+ return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε;
+ }
+ function d3_geo_cartesian(spherical) {
+ var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ);
+ return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ];
+ }
+ function d3_geo_cartesianDot(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+ }
+ function d3_geo_cartesianCross(a, b) {
+ return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ];
+ }
+ function d3_geo_cartesianAdd(a, b) {
+ a[0] += b[0];
+ a[1] += b[1];
+ a[2] += b[2];
+ }
+ function d3_geo_cartesianScale(vector, k) {
+ return [ vector[0] * k, vector[1] * k, vector[2] * k ];
+ }
+ function d3_geo_cartesianNormalize(d) {
+ var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
+ d[0] /= l;
+ d[1] /= l;
+ d[2] /= l;
+ }
+ function d3_geo_resample(project) {
+ var δ2 = .5, maxDepth = 16;
+ function resample(stream) {
+ var λ0, x0, y0, a0, b0, c0;
+ var resample = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ stream.polygonStart();
+ resample.lineStart = polygonLineStart;
+ },
+ polygonEnd: function() {
+ stream.polygonEnd();
+ resample.lineStart = lineStart;
+ }
+ };
+ function point(x, y) {
+ x = project(x, y);
+ stream.point(x[0], x[1]);
+ }
+ function lineStart() {
+ x0 = NaN;
+ resample.point = linePoint;
+ stream.lineStart();
+ }
+ function linePoint(λ, φ) {
+ var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ);
+ resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
+ stream.point(x0, y0);
+ }
+ function lineEnd() {
+ resample.point = point;
+ stream.lineEnd();
+ }
+ function polygonLineStart() {
+ var λ00, φ00, x00, y00, a00, b00, c00;
+ lineStart();
+ resample.point = function(λ, φ) {
+ linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
+ resample.point = linePoint;
+ };
+ resample.lineEnd = function() {
+ resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream);
+ resample.lineEnd = lineEnd;
+ lineEnd();
+ };
+ }
+ return resample;
+ }
+ function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) {
+ var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy;
+ if (d2 > 4 * δ2 && depth--) {
+ var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = Math.abs(Math.abs(c) - 1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2;
+ if (dz * dz / d2 > δ2 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3) {
+ resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream);
+ stream.point(x2, y2);
+ resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream);
+ }
+ }
+ }
+ resample.precision = function(_) {
+ if (!arguments.length) return Math.sqrt(δ2);
+ maxDepth = (δ2 = _ * _) > 0 && 16;
+ return resample;
+ };
+ return resample;
+ }
+ d3.geo.albersUsa = function() {
+ var lower48 = d3.geo.albers();
+ var alaska = d3.geo.albers().rotate([ 160, 0 ]).center([ 0, 60 ]).parallels([ 55, 65 ]);
+ var hawaii = d3.geo.albers().rotate([ 160, 0 ]).center([ 0, 20 ]).parallels([ 8, 18 ]);
+ var puertoRico = d3.geo.albers().rotate([ 60, 0 ]).center([ 0, 10 ]).parallels([ 8, 18 ]);
+ function albersUsa(coordinates) {
+ return projection(coordinates)(coordinates);
+ }
+ function projection(point) {
+ var lon = point[0], lat = point[1];
+ return lat > 50 ? alaska : lon < -140 ? hawaii : lat < 21 ? puertoRico : lower48;
+ }
+ albersUsa.scale = function(x) {
+ if (!arguments.length) return lower48.scale();
+ lower48.scale(x);
+ alaska.scale(x * .6);
+ hawaii.scale(x);
+ puertoRico.scale(x * 1.5);
+ return albersUsa.translate(lower48.translate());
+ };
+ albersUsa.translate = function(x) {
+ if (!arguments.length) return lower48.translate();
+ var dz = lower48.scale(), dx = x[0], dy = x[1];
+ lower48.translate(x);
+ alaska.translate([ dx - .4 * dz, dy + .17 * dz ]);
+ hawaii.translate([ dx - .19 * dz, dy + .2 * dz ]);
+ puertoRico.translate([ dx + .58 * dz, dy + .43 * dz ]);
+ return albersUsa;
+ };
+ return albersUsa.scale(lower48.scale());
+ };
+ function d3_geo_albers(φ0, φ1) {
+ var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n;
+ function albers(λ, φ) {
+ var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n;
+ return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ];
+ }
+ albers.invert = function(x, y) {
+ var ρ0_y = ρ0 - y;
+ return [ Math.atan2(x, ρ0_y) / n, Math.asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ];
+ };
+ return albers;
+ }
+ (d3.geo.albers = function() {
+ var φ0 = 29.5 * d3_radians, φ1 = 45.5 * d3_radians, m = d3_geo_projectionMutator(d3_geo_albers), p = m(φ0, φ1);
+ p.parallels = function(_) {
+ if (!arguments.length) return [ φ0 * d3_degrees, φ1 * d3_degrees ];
+ return m(φ0 = _[0] * d3_radians, φ1 = _[1] * d3_radians);
+ };
+ return p.rotate([ 98, 0 ]).center([ 0, 38 ]).scale(1e3);
+ }).raw = d3_geo_albers;
+ var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) {
+ return Math.sqrt(2 / (1 + cosλcosφ));
+ }, function(ρ) {
+ return 2 * Math.asin(ρ / 2);
+ });
+ (d3.geo.azimuthalEqualArea = function() {
+ return d3_geo_projection(d3_geo_azimuthalEqualArea);
+ }).raw = d3_geo_azimuthalEqualArea;
+ var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) {
+ var c = Math.acos(cosλcosφ);
+ return c && c / Math.sin(c);
+ }, d3_identity);
+ (d3.geo.azimuthalEquidistant = function() {
+ return d3_geo_projection(d3_geo_azimuthalEquidistant);
+ }).raw = d3_geo_azimuthalEquidistant;
+ d3.geo.bounds = d3_geo_bounds(d3_identity);
+ function d3_geo_bounds(projectStream) {
+ var x0, y0, x1, y1;
+ var bound = {
+ point: boundPoint,
+ lineStart: d3_noop,
+ lineEnd: d3_noop,
+ polygonStart: function() {
+ bound.lineEnd = boundPolygonLineEnd;
+ },
+ polygonEnd: function() {
+ bound.point = boundPoint;
+ }
+ };
+ function boundPoint(x, y) {
+ if (x < x0) x0 = x;
+ if (x > x1) x1 = x;
+ if (y < y0) y0 = y;
+ if (y > y1) y1 = y;
+ }
+ function boundPolygonLineEnd() {
+ bound.point = bound.lineEnd = d3_noop;
+ }
+ return function(feature) {
+ y1 = x1 = -(x0 = y0 = Infinity);
+ d3.geo.stream(feature, projectStream(bound));
+ return [ [ x0, y0 ], [ x1, y1 ] ];
+ };
+ }
+ d3.geo.centroid = function(object) {
+ d3_geo_centroidDimension = d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ d3.geo.stream(object, d3_geo_centroid);
+ var m;
+ if (d3_geo_centroidW && Math.abs(m = Math.sqrt(d3_geo_centroidX * d3_geo_centroidX + d3_geo_centroidY * d3_geo_centroidY + d3_geo_centroidZ * d3_geo_centroidZ)) > ε) {
+ return [ Math.atan2(d3_geo_centroidY, d3_geo_centroidX) * d3_degrees, Math.asin(Math.max(-1, Math.min(1, d3_geo_centroidZ / m))) * d3_degrees ];
+ }
+ };
+ var d3_geo_centroidDimension, d3_geo_centroidW, d3_geo_centroidX, d3_geo_centroidY, d3_geo_centroidZ;
+ var d3_geo_centroid = {
+ sphere: function() {
+ if (d3_geo_centroidDimension < 2) {
+ d3_geo_centroidDimension = 2;
+ d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ }
+ },
+ point: d3_geo_centroidPoint,
+ lineStart: d3_geo_centroidLineStart,
+ lineEnd: d3_geo_centroidLineEnd,
+ polygonStart: function() {
+ if (d3_geo_centroidDimension < 2) {
+ d3_geo_centroidDimension = 2;
+ d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ }
+ d3_geo_centroid.lineStart = d3_geo_centroidRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_centroid.lineStart = d3_geo_centroidLineStart;
+ }
+ };
+ function d3_geo_centroidPoint(λ, φ) {
+ if (d3_geo_centroidDimension) return;
+ ++d3_geo_centroidW;
+ λ *= d3_radians;
+ var cosφ = Math.cos(φ *= d3_radians);
+ d3_geo_centroidX += (cosφ * Math.cos(λ) - d3_geo_centroidX) / d3_geo_centroidW;
+ d3_geo_centroidY += (cosφ * Math.sin(λ) - d3_geo_centroidY) / d3_geo_centroidW;
+ d3_geo_centroidZ += (Math.sin(φ) - d3_geo_centroidZ) / d3_geo_centroidW;
+ }
+ function d3_geo_centroidRingStart() {
+ var λ00, φ00;
+ d3_geo_centroidDimension = 1;
+ d3_geo_centroidLineStart();
+ d3_geo_centroidDimension = 2;
+ var linePoint = d3_geo_centroid.point;
+ d3_geo_centroid.point = function(λ, φ) {
+ linePoint(λ00 = λ, φ00 = φ);
+ };
+ d3_geo_centroid.lineEnd = function() {
+ d3_geo_centroid.point(λ00, φ00);
+ d3_geo_centroidLineEnd();
+ d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;
+ };
+ }
+ function d3_geo_centroidLineStart() {
+ var x0, y0, z0;
+ if (d3_geo_centroidDimension > 1) return;
+ if (d3_geo_centroidDimension < 1) {
+ d3_geo_centroidDimension = 1;
+ d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ }
+ d3_geo_centroid.point = function(λ, φ) {
+ λ *= d3_radians;
+ var cosφ = Math.cos(φ *= d3_radians);
+ x0 = cosφ * Math.cos(λ);
+ y0 = cosφ * Math.sin(λ);
+ z0 = Math.sin(φ);
+ d3_geo_centroid.point = nextPoint;
+ };
+ function nextPoint(λ, φ) {
+ λ *= d3_radians;
+ var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
+ d3_geo_centroidW += w;
+ d3_geo_centroidX += w * (x0 + (x0 = x));
+ d3_geo_centroidY += w * (y0 + (y0 = y));
+ d3_geo_centroidZ += w * (z0 + (z0 = z));
+ }
+ }
+ function d3_geo_centroidLineEnd() {
+ d3_geo_centroid.point = d3_geo_centroidPoint;
+ }
+ d3.geo.circle = function() {
+ var origin = [ 0, 0 ], angle, precision = 6, interpolate;
+ function circle() {
+ var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = [];
+ interpolate(null, null, 1, {
+ point: function(x, y) {
+ ring.push(x = rotate(x, y));
+ x[0] *= d3_degrees, x[1] *= d3_degrees;
+ }
+ });
+ return {
+ type: "Polygon",
+ coordinates: [ ring ]
+ };
+ }
+ circle.origin = function(x) {
+ if (!arguments.length) return origin;
+ origin = x;
+ return circle;
+ };
+ circle.angle = function(x) {
+ if (!arguments.length) return angle;
+ interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians);
+ return circle;
+ };
+ circle.precision = function(_) {
+ if (!arguments.length) return precision;
+ interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians);
+ return circle;
+ };
+ return circle.angle(90);
+ };
+ function d3_geo_circleInterpolate(radians, precision) {
+ var cr = Math.cos(radians), sr = Math.sin(radians);
+ return function(from, to, direction, listener) {
+ if (from != null) {
+ from = d3_geo_circleAngle(cr, from);
+ to = d3_geo_circleAngle(cr, to);
+ if (direction > 0 ? from < to : from > to) from += direction * 2 * π;
+ } else {
+ from = radians + direction * 2 * π;
+ to = radians;
+ }
+ var point;
+ for (var step = direction * precision, t = from; direction > 0 ? t > to : t < to; t -= step) {
+ listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]);
+ }
+ };
+ }
+ function d3_geo_circleAngle(cr, point) {
+ var a = d3_geo_cartesian(point);
+ a[0] -= cr;
+ d3_geo_cartesianNormalize(a);
+ var angle = Math.acos(Math.max(-1, Math.min(1, -a[1])));
+ return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
+ }
+ function d3_geo_clip(pointVisible, clipLine, interpolate) {
+ return function(listener) {
+ var line = clipLine(listener);
+ var clip = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ clip.point = pointRing;
+ clip.lineStart = ringStart;
+ clip.lineEnd = ringEnd;
+ invisible = false;
+ invisibleArea = visibleArea = 0;
+ segments = [];
+ listener.polygonStart();
+ },
+ polygonEnd: function() {
+ clip.point = point;
+ clip.lineStart = lineStart;
+ clip.lineEnd = lineEnd;
+ segments = d3.merge(segments);
+ if (segments.length) {
+ d3_geo_clipPolygon(segments, interpolate, listener);
+ } else if (visibleArea < -ε || invisible && invisibleArea < -ε) {
+ listener.lineStart();
+ interpolate(null, null, 1, listener);
+ listener.lineEnd();
+ }
+ listener.polygonEnd();
+ segments = null;
+ },
+ sphere: function() {
+ listener.polygonStart();
+ listener.lineStart();
+ interpolate(null, null, 1, listener);
+ listener.lineEnd();
+ listener.polygonEnd();
+ }
+ };
+ function point(λ, φ) {
+ if (pointVisible(λ, φ)) listener.point(λ, φ);
+ }
+ function pointLine(λ, φ) {
+ line.point(λ, φ);
+ }
+ function lineStart() {
+ clip.point = pointLine;
+ line.lineStart();
+ }
+ function lineEnd() {
+ clip.point = point;
+ line.lineEnd();
+ }
+ var segments, visibleArea, invisibleArea, invisible;
+ var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), ring;
+ function pointRing(λ, φ) {
+ ringListener.point(λ, φ);
+ ring.push([ λ, φ ]);
+ }
+ function ringStart() {
+ ringListener.lineStart();
+ ring = [];
+ }
+ function ringEnd() {
+ pointRing(ring[0][0], ring[0][1]);
+ ringListener.lineEnd();
+ var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length;
+ if (!n) {
+ invisible = true;
+ invisibleArea += d3_geo_clipAreaRing(ring, -1);
+ ring = null;
+ return;
+ }
+ ring = null;
+ if (clean & 1) {
+ segment = ringSegments[0];
+ visibleArea += d3_geo_clipAreaRing(segment, 1);
+ var n = segment.length - 1, i = -1, point;
+ listener.lineStart();
+ while (++i < n) listener.point((point = segment[i])[0], point[1]);
+ listener.lineEnd();
+ return;
+ }
+ if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
+ segments.push(ringSegments.filter(d3_geo_clipSegmentLength1));
+ }
+ return clip;
+ };
+ }
+ function d3_geo_clipPolygon(segments, interpolate, listener) {
+ var subject = [], clip = [];
+ segments.forEach(function(segment) {
+ var n = segment.length;
+ if (n <= 1) return;
+ var p0 = segment[0], p1 = segment[n - 1], a = {
+ point: p0,
+ points: segment,
+ other: null,
+ visited: false,
+ entry: true,
+ subject: true
+ }, b = {
+ point: p0,
+ points: [ p0 ],
+ other: a,
+ visited: false,
+ entry: false,
+ subject: false
+ };
+ a.other = b;
+ subject.push(a);
+ clip.push(b);
+ a = {
+ point: p1,
+ points: [ p1 ],
+ other: null,
+ visited: false,
+ entry: false,
+ subject: true
+ };
+ b = {
+ point: p1,
+ points: [ p1 ],
+ other: a,
+ visited: false,
+ entry: true,
+ subject: false
+ };
+ a.other = b;
+ subject.push(a);
+ clip.push(b);
+ });
+ clip.sort(d3_geo_clipSort);
+ d3_geo_clipLinkCircular(subject);
+ d3_geo_clipLinkCircular(clip);
+ if (!subject.length) return;
+ var start = subject[0], current, points, point;
+ while (1) {
+ current = start;
+ while (current.visited) if ((current = current.next) === start) return;
+ points = current.points;
+ listener.lineStart();
+ do {
+ current.visited = current.other.visited = true;
+ if (current.entry) {
+ if (current.subject) {
+ for (var i = 0; i < points.length; i++) listener.point((point = points[i])[0], point[1]);
+ } else {
+ interpolate(current.point, current.next.point, 1, listener);
+ }
+ current = current.next;
+ } else {
+ if (current.subject) {
+ points = current.prev.points;
+ for (var i = points.length; --i >= 0; ) listener.point((point = points[i])[0], point[1]);
+ } else {
+ interpolate(current.point, current.prev.point, -1, listener);
+ }
+ current = current.prev;
+ }
+ current = current.other;
+ points = current.points;
+ } while (!current.visited);
+ listener.lineEnd();
+ }
+ }
+ function d3_geo_clipLinkCircular(array) {
+ if (!(n = array.length)) return;
+ var n, i = 0, a = array[0], b;
+ while (++i < n) {
+ a.next = b = array[i];
+ b.prev = a;
+ a = b;
+ }
+ a.next = b = array[0];
+ b.prev = a;
+ }
+ function d3_geo_clipSort(a, b) {
+ return ((a = a.point)[0] < 0 ? a[1] - π / 2 - ε : π / 2 - a[1]) - ((b = b.point)[0] < 0 ? b[1] - π / 2 - ε : π / 2 - b[1]);
+ }
+ function d3_geo_clipSegmentLength1(segment) {
+ return segment.length > 1;
+ }
+ function d3_geo_clipBufferListener() {
+ var lines = [], line;
+ return {
+ lineStart: function() {
+ lines.push(line = []);
+ },
+ point: function(λ, φ) {
+ line.push([ λ, φ ]);
+ },
+ lineEnd: d3_noop,
+ buffer: function() {
+ var buffer = lines;
+ lines = [];
+ line = null;
+ return buffer;
+ }
+ };
+ }
+ function d3_geo_clipAreaRing(ring, invisible) {
+ if (!(n = ring.length)) return 0;
+ var n, i = 0, area = 0, p = ring[0], λ = p[0], φ = p[1], cosφ = Math.cos(φ), x0 = Math.atan2(invisible * Math.sin(λ) * cosφ, Math.sin(φ)), y0 = 1 - invisible * Math.cos(λ) * cosφ, x1 = x0, x, y;
+ while (++i < n) {
+ p = ring[i];
+ cosφ = Math.cos(φ = p[1]);
+ x = Math.atan2(invisible * Math.sin(λ = p[0]) * cosφ, Math.sin(φ));
+ y = 1 - invisible * Math.cos(λ) * cosφ;
+ if (Math.abs(y0 - 2) < ε && Math.abs(y - 2) < ε) continue;
+ if (Math.abs(y) < ε || Math.abs(y0) < ε) {} else if (Math.abs(Math.abs(x - x0) - π) < ε) {
+ if (y + y0 > 2) area += 4 * (x - x0);
+ } else if (Math.abs(y0 - 2) < ε) area += 4 * (x - x1); else area += ((3 * π + x - x0) % (2 * π) - π) * (y0 + y);
+ x1 = x0, x0 = x, y0 = y;
+ }
+ return area;
+ }
+ var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate);
+ function d3_geo_clipAntimeridianLine(listener) {
+ var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean;
+ return {
+ lineStart: function() {
+ listener.lineStart();
+ clean = 1;
+ },
+ point: function(λ1, φ1) {
+ var sλ1 = λ1 > 0 ? π : -π, dλ = Math.abs(λ1 - λ0);
+ if (Math.abs(dλ - π) < ε) {
+ listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? π / 2 : -π / 2);
+ listener.point(sλ0, φ0);
+ listener.lineEnd();
+ listener.lineStart();
+ listener.point(sλ1, φ0);
+ listener.point(λ1, φ0);
+ clean = 0;
+ } else if (sλ0 !== sλ1 && dλ >= π) {
+ if (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
+ if (Math.abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
+ φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1);
+ listener.point(sλ0, φ0);
+ listener.lineEnd();
+ listener.lineStart();
+ listener.point(sλ1, φ0);
+ clean = 0;
+ }
+ listener.point(λ0 = λ1, φ0 = φ1);
+ sλ0 = sλ1;
+ },
+ lineEnd: function() {
+ listener.lineEnd();
+ λ0 = φ0 = NaN;
+ },
+ clean: function() {
+ return 2 - clean;
+ }
+ };
+ }
+ function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) {
+ var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1);
+ return Math.abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2;
+ }
+ function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {
+ var φ;
+ if (from == null) {
+ φ = direction * π / 2;
+ listener.point(-π, φ);
+ listener.point(0, φ);
+ listener.point(π, φ);
+ listener.point(π, 0);
+ listener.point(π, -φ);
+ listener.point(0, -φ);
+ listener.point(-π, -φ);
+ listener.point(-π, 0);
+ listener.point(-π, φ);
+ } else if (Math.abs(from[0] - to[0]) > ε) {
+ var s = (from[0] < to[0] ? 1 : -1) * π;
+ φ = direction * s / 2;
+ listener.point(-s, φ);
+ listener.point(0, φ);
+ listener.point(s, φ);
+ } else {
+ listener.point(to[0], to[1]);
+ }
+ }
+ function d3_geo_clipCircle(degrees) {
+ var radians = degrees * d3_radians, cr = Math.cos(radians), interpolate = d3_geo_circleInterpolate(radians, 6 * d3_radians);
+ return d3_geo_clip(visible, clipLine, interpolate);
+ function visible(λ, φ) {
+ return Math.cos(λ) * Math.cos(φ) > cr;
+ }
+ function clipLine(listener) {
+ var point0, v0, v00, clean;
+ return {
+ lineStart: function() {
+ v00 = v0 = false;
+ clean = 1;
+ },
+ point: function(λ, φ) {
+ var point1 = [ λ, φ ], point2, v = visible(λ, φ);
+ if (!point0 && (v00 = v0 = v)) listener.lineStart();
+ if (v !== v0) {
+ point2 = intersect(point0, point1);
+ if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) {
+ point1[0] += ε;
+ point1[1] += ε;
+ v = visible(point1[0], point1[1]);
+ }
+ }
+ if (v !== v0) {
+ clean = 0;
+ if (v0 = v) {
+ listener.lineStart();
+ point2 = intersect(point1, point0);
+ listener.point(point2[0], point2[1]);
+ } else {
+ point2 = intersect(point0, point1);
+ listener.point(point2[0], point2[1]);
+ listener.lineEnd();
+ }
+ point0 = point2;
+ }
+ if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) listener.point(point1[0], point1[1]);
+ point0 = point1;
+ },
+ lineEnd: function() {
+ if (v0) listener.lineEnd();
+ point0 = null;
+ },
+ clean: function() {
+ return clean | (v00 && v0) << 1;
+ }
+ };
+ }
+ function intersect(a, b) {
+ var pa = d3_geo_cartesian(a, 0), pb = d3_geo_cartesian(b, 0);
+ var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2;
+ if (!determinant) return a;
+ var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2);
+ d3_geo_cartesianAdd(A, B);
+ var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t = Math.sqrt(w * w - uu * (d3_geo_cartesianDot(A, A) - 1)), q = d3_geo_cartesianScale(u, (-w - t) / uu);
+ d3_geo_cartesianAdd(q, A);
+ return d3_geo_spherical(q);
+ }
+ }
+ function d3_geo_compose(a, b) {
+ function compose(x, y) {
+ return x = a(x, y), b(x[0], x[1]);
+ }
+ if (a.invert && b.invert) compose.invert = function(x, y) {
+ return x = b.invert(x, y), x && a.invert(x[0], x[1]);
+ };
+ return compose;
+ }
+ function d3_geo_equirectangular(λ, φ) {
+ return [ λ, φ ];
+ }
+ (d3.geo.equirectangular = function() {
+ return d3_geo_projection(d3_geo_equirectangular).scale(250 / π);
+ }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;
+ var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) {
+ return 1 / cosλcosφ;
+ }, Math.atan);
+ (d3.geo.gnomonic = function() {
+ return d3_geo_projection(d3_geo_gnomonic);
+ }).raw = d3_geo_gnomonic;
+ d3.geo.graticule = function() {
+ var x1, x0, y1, y0, dx = 22.5, dy = dx, x, y, precision = 2.5;
+ function graticule() {
+ return {
+ type: "MultiLineString",
+ coordinates: lines()
+ };
+ }
+ function lines() {
+ return d3.range(Math.ceil(x0 / dx) * dx, x1, dx).map(x).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).map(y));
+ }
+ graticule.lines = function() {
+ return lines().map(function(coordinates) {
+ return {
+ type: "LineString",
+ coordinates: coordinates
+ };
+ });
+ };
+ graticule.outline = function() {
+ return {
+ type: "Polygon",
+ coordinates: [ x(x0).concat(y(y1).slice(1), x(x1).reverse().slice(1), y(y0).reverse().slice(1)) ]
+ };
+ };
+ graticule.extent = function(_) {
+ if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
+ x0 = +_[0][0], x1 = +_[1][0];
+ y0 = +_[0][1], y1 = +_[1][1];
+ if (x0 > x1) _ = x0, x0 = x1, x1 = _;
+ if (y0 > y1) _ = y0, y0 = y1, y1 = _;
+ return graticule.precision(precision);
+ };
+ graticule.step = function(_) {
+ if (!arguments.length) return [ dx, dy ];
+ dx = +_[0], dy = +_[1];
+ return graticule;
+ };
+ graticule.precision = function(_) {
+ if (!arguments.length) return precision;
+ precision = +_;
+ x = d3_geo_graticuleX(y0, y1, precision);
+ y = d3_geo_graticuleY(x0, x1, precision);
+ return graticule;
+ };
+ return graticule.extent([ [ -180 + ε, -90 + ε ], [ 180 - ε, 90 - ε ] ]);
+ };
+ function d3_geo_graticuleX(y0, y1, dy) {
+ var y = d3.range(y0, y1 - ε, dy).concat(y1);
+ return function(x) {
+ return y.map(function(y) {
+ return [ x, y ];
+ });
+ };
+ }
+ function d3_geo_graticuleY(x0, x1, dx) {
+ var x = d3.range(x0, x1 - ε, dx).concat(x1);
+ return function(y) {
+ return x.map(function(x) {
+ return [ x, y ];
+ });
+ };
+ }
+ d3.geo.interpolate = function(source, target) {
+ return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians);
+ };
+ function d3_geo_interpolate(x0, y0, x1, y1) {
+ var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = Math.acos(Math.max(-1, Math.min(1, sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)))), k = 1 / Math.sin(d);
+ function interpolate(t) {
+ var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1;
+ return [ Math.atan2(y, x) / d3_radians, Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_radians ];
+ }
+ interpolate.distance = d;
+ return interpolate;
+ }
+ d3.geo.greatArc = function() {
+ var source = d3_source, source_, target = d3_target, target_, precision = 6 * d3_radians, interpolate;
+ function greatArc() {
+ var p0 = source_ || source.apply(this, arguments), p1 = target_ || target.apply(this, arguments), i = interpolate || d3.geo.interpolate(p0, p1), t = 0, dt = precision / i.distance, coordinates = [ p0 ];
+ while ((t += dt) < 1) coordinates.push(i(t));
+ coordinates.push(p1);
+ return {
+ type: "LineString",
+ coordinates: coordinates
+ };
+ }
+ greatArc.distance = function() {
+ return (interpolate || d3.geo.interpolate(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments))).distance;
+ };
+ greatArc.source = function(_) {
+ if (!arguments.length) return source;
+ source = _, source_ = typeof _ === "function" ? null : _;
+ interpolate = source_ && target_ ? d3.geo.interpolate(source_, target_) : null;
+ return greatArc;
+ };
+ greatArc.target = function(_) {
+ if (!arguments.length) return target;
+ target = _, target_ = typeof _ === "function" ? null : _;
+ interpolate = source_ && target_ ? d3.geo.interpolate(source_, target_) : null;
+ return greatArc;
+ };
+ greatArc.precision = function(_) {
+ if (!arguments.length) return precision / d3_radians;
+ precision = _ * d3_radians;
+ return greatArc;
+ };
+ return greatArc;
+ };
+ function d3_geo_mercator(λ, φ) {
+ return [ λ / (2 * π), Math.max(-.5, Math.min(+.5, Math.log(Math.tan(π / 4 + φ / 2)) / (2 * π))) ];
+ }
+ d3_geo_mercator.invert = function(x, y) {
+ return [ 2 * π * x, 2 * Math.atan(Math.exp(2 * π * y)) - π / 2 ];
+ };
+ (d3.geo.mercator = function() {
+ return d3_geo_projection(d3_geo_mercator).scale(500);
+ }).raw = d3_geo_mercator;
+ var d3_geo_orthographic = d3_geo_azimuthal(function() {
+ return 1;
+ }, Math.asin);
+ (d3.geo.orthographic = function() {
+ return d3_geo_projection(d3_geo_orthographic);
+ }).raw = d3_geo_orthographic;
+ d3.geo.path = function() {
+ var pointRadius = 4.5, projection, context, projectStream, contextStream;
+ function path(object) {
+ if (object) d3.geo.stream(object, projectStream(contextStream.pointRadius(typeof pointRadius === "function" ? +pointRadius.apply(this, arguments) : pointRadius)));
+ return contextStream.result();
+ }
+ path.area = function(object) {
+ d3_geo_pathAreaSum = 0;
+ d3.geo.stream(object, projectStream(d3_geo_pathArea));
+ return d3_geo_pathAreaSum;
+ };
+ path.centroid = function(object) {
+ d3_geo_centroidDimension = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ d3.geo.stream(object, projectStream(d3_geo_pathCentroid));
+ return d3_geo_centroidZ ? [ d3_geo_centroidX / d3_geo_centroidZ, d3_geo_centroidY / d3_geo_centroidZ ] : undefined;
+ };
+ path.bounds = function(object) {
+ return d3_geo_bounds(projectStream)(object);
+ };
+ path.projection = function(_) {
+ if (!arguments.length) return projection;
+ projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity;
+ return path;
+ };
+ path.context = function(_) {
+ if (!arguments.length) return context;
+ contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_);
+ return path;
+ };
+ path.pointRadius = function(_) {
+ if (!arguments.length) return pointRadius;
+ pointRadius = typeof _ === "function" ? _ : +_;
+ return path;
+ };
+ return path.projection(d3.geo.albersUsa()).context(null);
+ };
+ function d3_geo_pathCircle(radius) {
+ return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + +2 * radius + "z";
+ }
+ function d3_geo_pathProjectStream(project) {
+ var resample = d3_geo_resample(function(λ, φ) {
+ return project([ λ * d3_degrees, φ * d3_degrees ]);
+ });
+ return function(stream) {
+ stream = resample(stream);
+ return {
+ point: function(λ, φ) {
+ stream.point(λ * d3_radians, φ * d3_radians);
+ },
+ sphere: function() {
+ stream.sphere();
+ },
+ lineStart: function() {
+ stream.lineStart();
+ },
+ lineEnd: function() {
+ stream.lineEnd();
+ },
+ polygonStart: function() {
+ stream.polygonStart();
+ },
+ polygonEnd: function() {
+ stream.polygonEnd();
+ }
+ };
+ };
+ }
+ function d3_geo_pathBuffer() {
+ var pointCircle = d3_geo_pathCircle(4.5), buffer = [];
+ var stream = {
+ point: point,
+ lineStart: function() {
+ stream.point = pointLineStart;
+ },
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ stream.lineEnd = lineEndPolygon;
+ },
+ polygonEnd: function() {
+ stream.lineEnd = lineEnd;
+ stream.point = point;
+ },
+ pointRadius: function(_) {
+ pointCircle = d3_geo_pathCircle(_);
+ return stream;
+ },
+ result: function() {
+ if (buffer.length) {
+ var result = buffer.join("");
+ buffer = [];
+ return result;
+ }
+ }
+ };
+ function point(x, y) {
+ buffer.push("M", x, ",", y, pointCircle);
+ }
+ function pointLineStart(x, y) {
+ buffer.push("M", x, ",", y);
+ stream.point = pointLine;
+ }
+ function pointLine(x, y) {
+ buffer.push("L", x, ",", y);
+ }
+ function lineEnd() {
+ stream.point = point;
+ }
+ function lineEndPolygon() {
+ buffer.push("Z");
+ }
+ return stream;
+ }
+ function d3_geo_pathContext(context) {
+ var pointRadius = 4.5;
+ var stream = {
+ point: point,
+ lineStart: function() {
+ stream.point = pointLineStart;
+ },
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ stream.lineEnd = lineEndPolygon;
+ },
+ polygonEnd: function() {
+ stream.lineEnd = lineEnd;
+ stream.point = point;
+ },
+ pointRadius: function(_) {
+ pointRadius = _;
+ return stream;
+ },
+ result: d3_noop
+ };
+ function point(x, y) {
+ context.moveTo(x, y);
+ context.arc(x, y, pointRadius, 0, 2 * π);
+ }
+ function pointLineStart(x, y) {
+ context.moveTo(x, y);
+ stream.point = pointLine;
+ }
+ function pointLine(x, y) {
+ context.lineTo(x, y);
+ }
+ function lineEnd() {
+ stream.point = point;
+ }
+ function lineEndPolygon() {
+ context.closePath();
+ }
+ return stream;
+ }
+ var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = {
+ point: d3_noop,
+ lineStart: d3_noop,
+ lineEnd: d3_noop,
+ polygonStart: function() {
+ d3_geo_pathAreaPolygon = 0;
+ d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop;
+ d3_geo_pathAreaSum += Math.abs(d3_geo_pathAreaPolygon / 2);
+ }
+ };
+ function d3_geo_pathAreaRingStart() {
+ var x00, y00, x0, y0;
+ d3_geo_pathArea.point = function(x, y) {
+ d3_geo_pathArea.point = nextPoint;
+ x00 = x0 = x, y00 = y0 = y;
+ };
+ function nextPoint(x, y) {
+ d3_geo_pathAreaPolygon += y0 * x - x0 * y;
+ x0 = x, y0 = y;
+ }
+ d3_geo_pathArea.lineEnd = function() {
+ nextPoint(x00, y00);
+ };
+ }
+ var d3_geo_pathCentroid = {
+ point: d3_geo_pathCentroidPoint,
+ lineStart: d3_geo_pathCentroidLineStart,
+ lineEnd: d3_geo_pathCentroidLineEnd,
+ polygonStart: function() {
+ d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
+ d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart;
+ d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd;
+ }
+ };
+ function d3_geo_pathCentroidPoint(x, y) {
+ if (d3_geo_centroidDimension) return;
+ d3_geo_centroidX += x;
+ d3_geo_centroidY += y;
+ ++d3_geo_centroidZ;
+ }
+ function d3_geo_pathCentroidLineStart() {
+ var x0, y0;
+ if (d3_geo_centroidDimension !== 1) {
+ if (d3_geo_centroidDimension < 1) {
+ d3_geo_centroidDimension = 1;
+ d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ } else return;
+ }
+ d3_geo_pathCentroid.point = function(x, y) {
+ d3_geo_pathCentroid.point = nextPoint;
+ x0 = x, y0 = y;
+ };
+ function nextPoint(x, y) {
+ var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
+ d3_geo_centroidX += z * (x0 + x) / 2;
+ d3_geo_centroidY += z * (y0 + y) / 2;
+ d3_geo_centroidZ += z;
+ x0 = x, y0 = y;
+ }
+ }
+ function d3_geo_pathCentroidLineEnd() {
+ d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
+ }
+ function d3_geo_pathCentroidRingStart() {
+ var x00, y00, x0, y0;
+ if (d3_geo_centroidDimension < 2) {
+ d3_geo_centroidDimension = 2;
+ d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
+ }
+ d3_geo_pathCentroid.point = function(x, y) {
+ d3_geo_pathCentroid.point = nextPoint;
+ x00 = x0 = x, y00 = y0 = y;
+ };
+ function nextPoint(x, y) {
+ var z = y0 * x - x0 * y;
+ d3_geo_centroidX += z * (x0 + x);
+ d3_geo_centroidY += z * (y0 + y);
+ d3_geo_centroidZ += z * 3;
+ x0 = x, y0 = y;
+ }
+ d3_geo_pathCentroid.lineEnd = function() {
+ nextPoint(x00, y00);
+ };
+ }
+ d3.geo.area = function(object) {
+ d3_geo_areaSum = 0;
+ d3.geo.stream(object, d3_geo_area);
+ return d3_geo_areaSum;
+ };
+ var d3_geo_areaSum, d3_geo_areaRing;
+ var d3_geo_area = {
+ sphere: function() {
+ d3_geo_areaSum += 4 * π;
+ },
+ point: d3_noop,
+ lineStart: d3_noop,
+ lineEnd: d3_noop,
+ polygonStart: function() {
+ d3_geo_areaRing = 0;
+ d3_geo_area.lineStart = d3_geo_areaRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_areaSum += d3_geo_areaRing < 0 ? 4 * π + d3_geo_areaRing : d3_geo_areaRing;
+ d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;
+ }
+ };
+ function d3_geo_areaRingStart() {
+ var λ00, φ00, λ1, λ0, φ0, cosφ0, sinφ0;
+ d3_geo_area.point = function(λ, φ) {
+ d3_geo_area.point = nextPoint;
+ λ1 = λ0 = (λ00 = λ) * d3_radians, φ0 = (φ00 = φ) * d3_radians, cosφ0 = Math.cos(φ0),
+ sinφ0 = Math.sin(φ0);
+ };
+ function nextPoint(λ, φ) {
+ λ *= d3_radians, φ *= d3_radians;
+ if (Math.abs(Math.abs(φ0) - π / 2) < ε && Math.abs(Math.abs(φ) - π / 2) < ε) return;
+ var cosφ = Math.cos(φ), sinφ = Math.sin(φ);
+ if (Math.abs(φ0 - π / 2) < ε) d3_geo_areaRing += (λ - λ1) * 2; else {
+ var dλ = λ - λ0, cosdλ = Math.cos(dλ), d = Math.atan2(Math.sqrt((d = cosφ * Math.sin(dλ)) * d + (d = cosφ0 * sinφ - sinφ0 * cosφ * cosdλ) * d), sinφ0 * sinφ + cosφ0 * cosφ * cosdλ), s = (d + π + φ0 + φ) / 4;
+ d3_geo_areaRing += (dλ < 0 && dλ > -π || dλ > π ? -4 : 4) * Math.atan(Math.sqrt(Math.abs(Math.tan(s) * Math.tan(s - d / 2) * Math.tan(s - π / 4 - φ0 / 2) * Math.tan(s - π / 4 - φ / 2))));
+ }
+ λ1 = λ0, λ0 = λ, φ0 = φ, cosφ0 = cosφ, sinφ0 = sinφ;
+ }
+ d3_geo_area.lineEnd = function() {
+ nextPoint(λ00, φ00);
+ };
+ }
+ d3.geo.projection = d3_geo_projection;
+ d3.geo.projectionMutator = d3_geo_projectionMutator;
+ function d3_geo_projection(project) {
+ return d3_geo_projectionMutator(function() {
+ return project;
+ })();
+ }
+ function d3_geo_projectionMutator(projectAt) {
+ var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) {
+ x = project(x, y);
+ return [ x[0] * k + δx, δy - x[1] * k ];
+ }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, clip = d3_geo_clipAntimeridian, clipAngle = null;
+ function projection(point) {
+ point = projectRotate(point[0] * d3_radians, point[1] * d3_radians);
+ return [ point[0] * k + δx, δy - point[1] * k ];
+ }
+ function invert(point) {
+ point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k);
+ return point && [ point[0] * d3_degrees, point[1] * d3_degrees ];
+ }
+ projection.stream = function(stream) {
+ return d3_geo_projectionRadiansRotate(rotate, clip(projectResample(stream)));
+ };
+ projection.clipAngle = function(_) {
+ if (!arguments.length) return clipAngle;
+ clip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle(clipAngle = +_);
+ return projection;
+ };
+ projection.scale = function(_) {
+ if (!arguments.length) return k;
+ k = +_;
+ return reset();
+ };
+ projection.translate = function(_) {
+ if (!arguments.length) return [ x, y ];
+ x = +_[0];
+ y = +_[1];
+ return reset();
+ };
+ projection.center = function(_) {
+ if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ];
+ λ = _[0] % 360 * d3_radians;
+ φ = _[1] % 360 * d3_radians;
+ return reset();
+ };
+ projection.rotate = function(_) {
+ if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ];
+ δλ = _[0] % 360 * d3_radians;
+ δφ = _[1] % 360 * d3_radians;
+ δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0;
+ return reset();
+ };
+ d3.rebind(projection, projectResample, "precision");
+ function reset() {
+ projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project);
+ var center = project(λ, φ);
+ δx = x - center[0] * k;
+ δy = y + center[1] * k;
+ return projection;
+ }
+ return function() {
+ project = projectAt.apply(this, arguments);
+ projection.invert = project.invert && invert;
+ return reset();
+ };
+ }
+ function d3_geo_projectionRadiansRotate(rotate, stream) {
+ return {
+ point: function(x, y) {
+ y = rotate(x * d3_radians, y * d3_radians), x = y[0];
+ stream.point(x > π ? x - 2 * π : x < -π ? x + 2 * π : x, y[1]);
+ },
+ sphere: function() {
+ stream.sphere();
+ },
+ lineStart: function() {
+ stream.lineStart();
+ },
+ lineEnd: function() {
+ stream.lineEnd();
+ },
+ polygonStart: function() {
+ stream.polygonStart();
+ },
+ polygonEnd: function() {
+ stream.polygonEnd();
+ }
+ };
+ }
+ function d3_geo_rotation(δλ, δφ, δγ) {
+ return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_equirectangular;
+ }
+ function d3_geo_forwardRotationλ(δλ) {
+ return function(λ, φ) {
+ return λ += δλ, [ λ > π ? λ - 2 * π : λ < -π ? λ + 2 * π : λ, φ ];
+ };
+ }
+ function d3_geo_rotationλ(δλ) {
+ var rotation = d3_geo_forwardRotationλ(δλ);
+ rotation.invert = d3_geo_forwardRotationλ(-δλ);
+ return rotation;
+ }
+ function d3_geo_rotationφγ(δφ, δγ) {
+ var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ);
+ function rotation(λ, φ) {
+ var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ;
+ return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), Math.asin(Math.max(-1, Math.min(1, k * cosδγ + y * sinδγ))) ];
+ }
+ rotation.invert = function(λ, φ) {
+ var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ;
+ return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), Math.asin(Math.max(-1, Math.min(1, k * cosδφ - x * sinδφ))) ];
+ };
+ return rotation;
+ }
+ var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) {
+ return 1 / (1 + cosλcosφ);
+ }, function(ρ) {
+ return 2 * Math.atan(ρ);
+ });
+ (d3.geo.stereographic = function() {
+ return d3_geo_projection(d3_geo_stereographic);
+ }).raw = d3_geo_stereographic;
+ function d3_geo_azimuthal(scale, angle) {
+ function azimuthal(λ, φ) {
+ var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ);
+ return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ];
+ }
+ azimuthal.invert = function(x, y) {
+ var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c);
+ return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ];
+ };
+ return azimuthal;
+ }
+ d3.geom = {};
+ d3.geom.hull = function(vertices) {
+ if (vertices.length < 3) return [];
+ var len = vertices.length, plen = len - 1, points = [], stack = [], i, j, h = 0, x1, y1, x2, y2, u, v, a, sp;
+ for (i = 1; i < len; ++i) {
+ if (vertices[i][1] < vertices[h][1]) {
+ h = i;
+ } else if (vertices[i][1] == vertices[h][1]) {
+ h = vertices[i][0] < vertices[h][0] ? i : h;
+ }
+ }
+ for (i = 0; i < len; ++i) {
+ if (i === h) continue;
+ y1 = vertices[i][1] - vertices[h][1];
+ x1 = vertices[i][0] - vertices[h][0];
+ points.push({
+ angle: Math.atan2(y1, x1),
+ index: i
+ });
+ }
+ points.sort(function(a, b) {
+ return a.angle - b.angle;
+ });
+ a = points[0].angle;
+ v = points[0].index;
+ u = 0;
+ for (i = 1; i < plen; ++i) {
+ j = points[i].index;
+ if (a == points[i].angle) {
+ x1 = vertices[v][0] - vertices[h][0];
+ y1 = vertices[v][1] - vertices[h][1];
+ x2 = vertices[j][0] - vertices[h][0];
+ y2 = vertices[j][1] - vertices[h][1];
+ if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) {
+ points[i].index = -1;
+ } else {
+ points[u].index = -1;
+ a = points[i].angle;
+ u = i;
+ v = j;
+ }
+ } else {
+ a = points[i].angle;
+ u = i;
+ v = j;
+ }
+ }
+ stack.push(h);
+ for (i = 0, j = 0; i < 2; ++j) {
+ if (points[j].index !== -1) {
+ stack.push(points[j].index);
+ i++;
+ }
+ }
+ sp = stack.length;
+ for (;j < plen; ++j) {
+ if (points[j].index === -1) continue;
+ while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) {
+ --sp;
+ }
+ stack[sp++] = points[j].index;
+ }
+ var poly = [];
+ for (i = 0; i < sp; ++i) {
+ poly.push(vertices[stack[i]]);
+ }
+ return poly;
+ };
+ function d3_geom_hullCCW(i1, i2, i3, v) {
+ var t, a, b, c, d, e, f;
+ t = v[i1];
+ a = t[0];
+ b = t[1];
+ t = v[i2];
+ c = t[0];
+ d = t[1];
+ t = v[i3];
+ e = t[0];
+ f = t[1];
+ return (f - b) * (c - a) - (d - b) * (e - a) > 0;
+ }
+ d3.geom.polygon = function(coordinates) {
+ coordinates.area = function() {
+ var i = 0, n = coordinates.length, area = coordinates[n - 1][1] * coordinates[0][0] - coordinates[n - 1][0] * coordinates[0][1];
+ while (++i < n) {
+ area += coordinates[i - 1][1] * coordinates[i][0] - coordinates[i - 1][0] * coordinates[i][1];
+ }
+ return area * .5;
+ };
+ coordinates.centroid = function(k) {
+ var i = -1, n = coordinates.length, x = 0, y = 0, a, b = coordinates[n - 1], c;
+ if (!arguments.length) k = -1 / (6 * coordinates.area());
+ while (++i < n) {
+ a = b;
+ b = coordinates[i];
+ c = a[0] * b[1] - b[0] * a[1];
+ x += (a[0] + b[0]) * c;
+ y += (a[1] + b[1]) * c;
+ }
+ return [ x * k, y * k ];
+ };
+ coordinates.clip = function(subject) {
+ var input, i = -1, n = coordinates.length, j, m, a = coordinates[n - 1], b, c, d;
+ while (++i < n) {
+ input = subject.slice();
+ subject.length = 0;
+ b = coordinates[i];
+ c = input[(m = input.length) - 1];
+ j = -1;
+ while (++j < m) {
+ d = input[j];
+ if (d3_geom_polygonInside(d, a, b)) {
+ if (!d3_geom_polygonInside(c, a, b)) {
+ subject.push(d3_geom_polygonIntersect(c, d, a, b));
+ }
+ subject.push(d);
+ } else if (d3_geom_polygonInside(c, a, b)) {
+ subject.push(d3_geom_polygonIntersect(c, d, a, b));
+ }
+ c = d;
+ }
+ a = b;
+ }
+ return subject;
+ };
+ return coordinates;
+ };
+ function d3_geom_polygonInside(p, a, b) {
+ return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
+ }
+ function d3_geom_polygonIntersect(c, d, a, b) {
+ var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21);
+ return [ x1 + ua * x21, y1 + ua * y21 ];
+ }
+ d3.geom.voronoi = function(vertices) {
+ var polygons = vertices.map(function() {
+ return [];
+ }), Z = 1e6;
+ d3_voronoi_tessellate(vertices, function(e) {
+ var s1, s2, x1, x2, y1, y2;
+ if (e.a === 1 && e.b >= 0) {
+ s1 = e.ep.r;
+ s2 = e.ep.l;
+ } else {
+ s1 = e.ep.l;
+ s2 = e.ep.r;
+ }
+ if (e.a === 1) {
+ y1 = s1 ? s1.y : -Z;
+ x1 = e.c - e.b * y1;
+ y2 = s2 ? s2.y : Z;
+ x2 = e.c - e.b * y2;
+ } else {
+ x1 = s1 ? s1.x : -Z;
+ y1 = e.c - e.a * x1;
+ x2 = s2 ? s2.x : Z;
+ y2 = e.c - e.a * x2;
+ }
+ var v1 = [ x1, y1 ], v2 = [ x2, y2 ];
+ polygons[e.region.l.index].push(v1, v2);
+ polygons[e.region.r.index].push(v1, v2);
+ });
+ polygons = polygons.map(function(polygon, i) {
+ var cx = vertices[i][0], cy = vertices[i][1], angle = polygon.map(function(v) {
+ return Math.atan2(v[0] - cx, v[1] - cy);
+ });
+ return d3.range(polygon.length).sort(function(a, b) {
+ return angle[a] - angle[b];
+ }).filter(function(d, i, order) {
+ return !i || angle[d] - angle[order[i - 1]] > ε;
+ }).map(function(d) {
+ return polygon[d];
+ });
+ });
+ polygons.forEach(function(polygon, i) {
+ var n = polygon.length;
+ if (!n) return polygon.push([ -Z, -Z ], [ -Z, Z ], [ Z, Z ], [ Z, -Z ]);
+ if (n > 2) return;
+ var p0 = vertices[i], p1 = polygon[0], p2 = polygon[1], x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1], dx = Math.abs(x2 - x1), dy = y2 - y1;
+ if (Math.abs(dy) < ε) {
+ var y = y0 < y1 ? -Z : Z;
+ polygon.push([ -Z, y ], [ Z, y ]);
+ } else if (dx < ε) {
+ var x = x0 < x1 ? -Z : Z;
+ polygon.push([ x, -Z ], [ x, Z ]);
+ } else {
+ var y = (x2 - x1) * (y1 - y0) < (x1 - x0) * (y2 - y1) ? Z : -Z, z = Math.abs(dy) - dx;
+ if (Math.abs(z) < ε) {
+ polygon.push([ dy < 0 ? y : -y, y ]);
+ } else {
+ if (z > 0) y *= -1;
+ polygon.push([ -Z, y ], [ Z, y ]);
+ }
+ }
+ });
+ return polygons;
+ };
+ var d3_voronoi_opposite = {
+ l: "r",
+ r: "l"
+ };
+ function d3_voronoi_tessellate(vertices, callback) {
+ var Sites = {
+ list: vertices.map(function(v, i) {
+ return {
+ index: i,
+ x: v[0],
+ y: v[1]
+ };
+ }).sort(function(a, b) {
+ return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0;
+ }),
+ bottomSite: null
+ };
+ var EdgeList = {
+ list: [],
+ leftEnd: null,
+ rightEnd: null,
+ init: function() {
+ EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l");
+ EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l");
+ EdgeList.leftEnd.r = EdgeList.rightEnd;
+ EdgeList.rightEnd.l = EdgeList.leftEnd;
+ EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd);
+ },
+ createHalfEdge: function(edge, side) {
+ return {
+ edge: edge,
+ side: side,
+ vertex: null,
+ l: null,
+ r: null
+ };
+ },
+ insert: function(lb, he) {
+ he.l = lb;
+ he.r = lb.r;
+ lb.r.l = he;
+ lb.r = he;
+ },
+ leftBound: function(p) {
+ var he = EdgeList.leftEnd;
+ do {
+ he = he.r;
+ } while (he != EdgeList.rightEnd && Geom.rightOf(he, p));
+ he = he.l;
+ return he;
+ },
+ del: function(he) {
+ he.l.r = he.r;
+ he.r.l = he.l;
+ he.edge = null;
+ },
+ right: function(he) {
+ return he.r;
+ },
+ left: function(he) {
+ return he.l;
+ },
+ leftRegion: function(he) {
+ return he.edge == null ? Sites.bottomSite : he.edge.region[he.side];
+ },
+ rightRegion: function(he) {
+ return he.edge == null ? Sites.bottomSite : he.edge.region[d3_voronoi_opposite[he.side]];
+ }
+ };
+ var Geom = {
+ bisect: function(s1, s2) {
+ var newEdge = {
+ region: {
+ l: s1,
+ r: s2
+ },
+ ep: {
+ l: null,
+ r: null
+ }
+ };
+ var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy;
+ newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5;
+ if (adx > ady) {
+ newEdge.a = 1;
+ newEdge.b = dy / dx;
+ newEdge.c /= dx;
+ } else {
+ newEdge.b = 1;
+ newEdge.a = dx / dy;
+ newEdge.c /= dy;
+ }
+ return newEdge;
+ },
+ intersect: function(el1, el2) {
+ var e1 = el1.edge, e2 = el2.edge;
+ if (!e1 || !e2 || e1.region.r == e2.region.r) {
+ return null;
+ }
+ var d = e1.a * e2.b - e1.b * e2.a;
+ if (Math.abs(d) < 1e-10) {
+ return null;
+ }
+ var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e;
+ if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) {
+ el = el1;
+ e = e1;
+ } else {
+ el = el2;
+ e = e2;
+ }
+ var rightOfSite = xint >= e.region.r.x;
+ if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") {
+ return null;
+ }
+ return {
+ x: xint,
+ y: yint
+ };
+ },
+ rightOf: function(he, p) {
+ var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x;
+ if (rightOfSite && he.side === "l") {
+ return 1;
+ }
+ if (!rightOfSite && he.side === "r") {
+ return 0;
+ }
+ if (e.a === 1) {
+ var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0;
+ if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) {
+ above = fast = dyp >= e.b * dxp;
+ } else {
+ above = p.x + p.y * e.b > e.c;
+ if (e.b < 0) {
+ above = !above;
+ }
+ if (!above) {
+ fast = 1;
+ }
+ }
+ if (!fast) {
+ var dxs = topsite.x - e.region.l.x;
+ above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b);
+ if (e.b < 0) {
+ above = !above;
+ }
+ }
+ } else {
+ var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y;
+ above = t1 * t1 > t2 * t2 + t3 * t3;
+ }
+ return he.side === "l" ? above : !above;
+ },
+ endPoint: function(edge, side, site) {
+ edge.ep[side] = site;
+ if (!edge.ep[d3_voronoi_opposite[side]]) return;
+ callback(edge);
+ },
+ distance: function(s, t) {
+ var dx = s.x - t.x, dy = s.y - t.y;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+ };
+ var EventQueue = {
+ list: [],
+ insert: function(he, site, offset) {
+ he.vertex = site;
+ he.ystar = site.y + offset;
+ for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) {
+ var next = list[i];
+ if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ list.splice(i, 0, he);
+ },
+ del: function(he) {
+ for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {}
+ ls.splice(i, 1);
+ },
+ empty: function() {
+ return EventQueue.list.length === 0;
+ },
+ nextEvent: function(he) {
+ for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) {
+ if (ls[i] == he) return ls[i + 1];
+ }
+ return null;
+ },
+ min: function() {
+ var elem = EventQueue.list[0];
+ return {
+ x: elem.vertex.x,
+ y: elem.ystar
+ };
+ },
+ extractMin: function() {
+ return EventQueue.list.shift();
+ }
+ };
+ EdgeList.init();
+ Sites.bottomSite = Sites.list.shift();
+ var newSite = Sites.list.shift(), newIntStar;
+ var lbnd, rbnd, llbnd, rrbnd, bisector;
+ var bot, top, temp, p, v;
+ var e, pm;
+ while (true) {
+ if (!EventQueue.empty()) {
+ newIntStar = EventQueue.min();
+ }
+ if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) {
+ lbnd = EdgeList.leftBound(newSite);
+ rbnd = EdgeList.right(lbnd);
+ bot = EdgeList.rightRegion(lbnd);
+ e = Geom.bisect(bot, newSite);
+ bisector = EdgeList.createHalfEdge(e, "l");
+ EdgeList.insert(lbnd, bisector);
+ p = Geom.intersect(lbnd, bisector);
+ if (p) {
+ EventQueue.del(lbnd);
+ EventQueue.insert(lbnd, p, Geom.distance(p, newSite));
+ }
+ lbnd = bisector;
+ bisector = EdgeList.createHalfEdge(e, "r");
+ EdgeList.insert(lbnd, bisector);
+ p = Geom.intersect(bisector, rbnd);
+ if (p) {
+ EventQueue.insert(bisector, p, Geom.distance(p, newSite));
+ }
+ newSite = Sites.list.shift();
+ } else if (!EventQueue.empty()) {
+ lbnd = EventQueue.extractMin();
+ llbnd = EdgeList.left(lbnd);
+ rbnd = EdgeList.right(lbnd);
+ rrbnd = EdgeList.right(rbnd);
+ bot = EdgeList.leftRegion(lbnd);
+ top = EdgeList.rightRegion(rbnd);
+ v = lbnd.vertex;
+ Geom.endPoint(lbnd.edge, lbnd.side, v);
+ Geom.endPoint(rbnd.edge, rbnd.side, v);
+ EdgeList.del(lbnd);
+ EventQueue.del(rbnd);
+ EdgeList.del(rbnd);
+ pm = "l";
+ if (bot.y > top.y) {
+ temp = bot;
+ bot = top;
+ top = temp;
+ pm = "r";
+ }
+ e = Geom.bisect(bot, top);
+ bisector = EdgeList.createHalfEdge(e, pm);
+ EdgeList.insert(llbnd, bisector);
+ Geom.endPoint(e, d3_voronoi_opposite[pm], v);
+ p = Geom.intersect(llbnd, bisector);
+ if (p) {
+ EventQueue.del(llbnd);
+ EventQueue.insert(llbnd, p, Geom.distance(p, bot));
+ }
+ p = Geom.intersect(bisector, rrbnd);
+ if (p) {
+ EventQueue.insert(bisector, p, Geom.distance(p, bot));
+ }
+ } else {
+ break;
+ }
+ }
+ for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) {
+ callback(lbnd.edge);
+ }
+ }
+ d3.geom.delaunay = function(vertices) {
+ var edges = vertices.map(function() {
+ return [];
+ }), triangles = [];
+ d3_voronoi_tessellate(vertices, function(e) {
+ edges[e.region.l.index].push(vertices[e.region.r.index]);
+ });
+ edges.forEach(function(edge, i) {
+ var v = vertices[i], cx = v[0], cy = v[1];
+ edge.forEach(function(v) {
+ v.angle = Math.atan2(v[0] - cx, v[1] - cy);
+ });
+ edge.sort(function(a, b) {
+ return a.angle - b.angle;
+ });
+ for (var j = 0, m = edge.length - 1; j < m; j++) {
+ triangles.push([ v, edge[j], edge[j + 1] ]);
+ }
+ });
+ return triangles;
+ };
+ d3.geom.quadtree = function(points, x1, y1, x2, y2) {
+ var p, i = -1, n = points.length;
+ if (arguments.length < 5) {
+ if (arguments.length === 3) {
+ y2 = y1;
+ x2 = x1;
+ y1 = x1 = 0;
+ } else {
+ x1 = y1 = Infinity;
+ x2 = y2 = -Infinity;
+ while (++i < n) {
+ p = points[i];
+ if (p.x < x1) x1 = p.x;
+ if (p.y < y1) y1 = p.y;
+ if (p.x > x2) x2 = p.x;
+ if (p.y > y2) y2 = p.y;
+ }
+ }
+ }
+ var dx = x2 - x1, dy = y2 - y1;
+ if (dx > dy) y2 = y1 + dx; else x2 = x1 + dy;
+ function insert(n, p, x1, y1, x2, y2) {
+ if (isNaN(p.x) || isNaN(p.y)) return;
+ if (n.leaf) {
+ var v = n.point;
+ if (v) {
+ if (Math.abs(v.x - p.x) + Math.abs(v.y - p.y) < .01) {
+ insertChild(n, p, x1, y1, x2, y2);
+ } else {
+ n.point = null;
+ insertChild(n, v, x1, y1, x2, y2);
+ insertChild(n, p, x1, y1, x2, y2);
+ }
+ } else {
+ n.point = p;
+ }
+ } else {
+ insertChild(n, p, x1, y1, x2, y2);
+ }
+ }
+ function insertChild(n, p, x1, y1, x2, y2) {
+ var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = p.x >= sx, bottom = p.y >= sy, i = (bottom << 1) + right;
+ n.leaf = false;
+ n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
+ if (right) x1 = sx; else x2 = sx;
+ if (bottom) y1 = sy; else y2 = sy;
+ insert(n, p, x1, y1, x2, y2);
+ }
+ var root = d3_geom_quadtreeNode();
+ root.add = function(p) {
+ insert(root, p, x1, y1, x2, y2);
+ };
+ root.visit = function(f) {
+ d3_geom_quadtreeVisit(f, root, x1, y1, x2, y2);
+ };
+ points.forEach(root.add);
+ return root;
+ };
+ function d3_geom_quadtreeNode() {
+ return {
+ leaf: true,
+ nodes: [],
+ point: null
+ };
+ }
+ function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
+ if (!f(node, x1, y1, x2, y2)) {
+ var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes;
+ if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);
+ if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);
+ if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
+ if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
+ }
+ }
+ d3.time = {};
+ var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ];
+ function d3_time_utc() {
+ this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]);
+ }
+ d3_time_utc.prototype = {
+ getDate: function() {
+ return this._.getUTCDate();
+ },
+ getDay: function() {
+ return this._.getUTCDay();
+ },
+ getFullYear: function() {
+ return this._.getUTCFullYear();
+ },
+ getHours: function() {
+ return this._.getUTCHours();
+ },
+ getMilliseconds: function() {
+ return this._.getUTCMilliseconds();
+ },
+ getMinutes: function() {
+ return this._.getUTCMinutes();
+ },
+ getMonth: function() {
+ return this._.getUTCMonth();
+ },
+ getSeconds: function() {
+ return this._.getUTCSeconds();
+ },
+ getTime: function() {
+ return this._.getTime();
+ },
+ getTimezoneOffset: function() {
+ return 0;
+ },
+ valueOf: function() {
+ return this._.valueOf();
+ },
+ setDate: function() {
+ d3_time_prototype.setUTCDate.apply(this._, arguments);
+ },
+ setDay: function() {
+ d3_time_prototype.setUTCDay.apply(this._, arguments);
+ },
+ setFullYear: function() {
+ d3_time_prototype.setUTCFullYear.apply(this._, arguments);
+ },
+ setHours: function() {
+ d3_time_prototype.setUTCHours.apply(this._, arguments);
+ },
+ setMilliseconds: function() {
+ d3_time_prototype.setUTCMilliseconds.apply(this._, arguments);
+ },
+ setMinutes: function() {
+ d3_time_prototype.setUTCMinutes.apply(this._, arguments);
+ },
+ setMonth: function() {
+ d3_time_prototype.setUTCMonth.apply(this._, arguments);
+ },
+ setSeconds: function() {
+ d3_time_prototype.setUTCSeconds.apply(this._, arguments);
+ },
+ setTime: function() {
+ d3_time_prototype.setTime.apply(this._, arguments);
+ }
+ };
+ var d3_time_prototype = Date.prototype;
+ var d3_time_formatDateTime = "%a %b %e %X %Y", d3_time_formatDate = "%m/%d/%Y", d3_time_formatTime = "%H:%M:%S";
+ var d3_time_days = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
+ d3.time.format = function(template) {
+ var n = template.length;
+ function format(date) {
+ var string = [], i = -1, j = 0, c, p, f;
+ while (++i < n) {
+ if (template.charCodeAt(i) === 37) {
+ string.push(template.substring(j, i));
+ if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i);
+ if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p);
+ string.push(c);
+ j = i + 1;
+ }
+ }
+ string.push(template.substring(j, i));
+ return string.join("");
+ }
+ format.parse = function(string) {
+ var d = {
+ y: 1900,
+ m: 0,
+ d: 1,
+ H: 0,
+ M: 0,
+ S: 0,
+ L: 0
+ }, i = d3_time_parse(d, template, string, 0);
+ if (i != string.length) return null;
+ if ("p" in d) d.H = d.H % 12 + d.p * 12;
+ var date = new d3_time();
+ date.setFullYear(d.y, d.m, d.d);
+ date.setHours(d.H, d.M, d.S, d.L);
+ return date;
+ };
+ format.toString = function() {
+ return template;
+ };
+ return format;
+ };
+ function d3_time_parse(date, template, string, j) {
+ var c, p, i = 0, n = template.length, m = string.length;
+ while (i < n) {
+ if (j >= m) return -1;
+ c = template.charCodeAt(i++);
+ if (c === 37) {
+ p = d3_time_parsers[template.charAt(i++)];
+ if (!p || (j = p(date, string, j)) < 0) return -1;
+ } else if (c != string.charCodeAt(j++)) {
+ return -1;
+ }
+ }
+ return j;
+ }
+ function d3_time_formatRe(names) {
+ return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i");
+ }
+ function d3_time_formatLookup(names) {
+ var map = new d3_Map(), i = -1, n = names.length;
+ while (++i < n) map.set(names[i].toLowerCase(), i);
+ return map;
+ }
+ function d3_time_formatPad(value, fill, width) {
+ value += "";
+ var length = value.length;
+ return length < width ? new Array(width - length + 1).join(fill) + value : value;
+ }
+ var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations);
+ var d3_time_formatPads = {
+ "-": "",
+ _: " ",
+ "0": "0"
+ };
+ var d3_time_formats = {
+ a: function(d) {
+ return d3_time_dayAbbreviations[d.getDay()];
+ },
+ A: function(d) {
+ return d3_time_days[d.getDay()];
+ },
+ b: function(d) {
+ return d3_time_monthAbbreviations[d.getMonth()];
+ },
+ B: function(d) {
+ return d3_time_months[d.getMonth()];
+ },
+ c: d3.time.format(d3_time_formatDateTime),
+ d: function(d, p) {
+ return d3_time_formatPad(d.getDate(), p, 2);
+ },
+ e: function(d, p) {
+ return d3_time_formatPad(d.getDate(), p, 2);
+ },
+ H: function(d, p) {
+ return d3_time_formatPad(d.getHours(), p, 2);
+ },
+ I: function(d, p) {
+ return d3_time_formatPad(d.getHours() % 12 || 12, p, 2);
+ },
+ j: function(d, p) {
+ return d3_time_formatPad(1 + d3.time.dayOfYear(d), p, 3);
+ },
+ L: function(d, p) {
+ return d3_time_formatPad(d.getMilliseconds(), p, 3);
+ },
+ m: function(d, p) {
+ return d3_time_formatPad(d.getMonth() + 1, p, 2);
+ },
+ M: function(d, p) {
+ return d3_time_formatPad(d.getMinutes(), p, 2);
+ },
+ p: function(d) {
+ return d.getHours() >= 12 ? "PM" : "AM";
+ },
+ S: function(d, p) {
+ return d3_time_formatPad(d.getSeconds(), p, 2);
+ },
+ U: function(d, p) {
+ return d3_time_formatPad(d3.time.sundayOfYear(d), p, 2);
+ },
+ w: function(d) {
+ return d.getDay();
+ },
+ W: function(d, p) {
+ return d3_time_formatPad(d3.time.mondayOfYear(d), p, 2);
+ },
+ x: d3.time.format(d3_time_formatDate),
+ X: d3.time.format(d3_time_formatTime),
+ y: function(d, p) {
+ return d3_time_formatPad(d.getFullYear() % 100, p, 2);
+ },
+ Y: function(d, p) {
+ return d3_time_formatPad(d.getFullYear() % 1e4, p, 4);
+ },
+ Z: d3_time_zone,
+ "%": function() {
+ return "%";
+ }
+ };
+ var d3_time_parsers = {
+ a: d3_time_parseWeekdayAbbrev,
+ A: d3_time_parseWeekday,
+ b: d3_time_parseMonthAbbrev,
+ B: d3_time_parseMonth,
+ c: d3_time_parseLocaleFull,
+ d: d3_time_parseDay,
+ e: d3_time_parseDay,
+ H: d3_time_parseHour24,
+ I: d3_time_parseHour24,
+ L: d3_time_parseMilliseconds,
+ m: d3_time_parseMonthNumber,
+ M: d3_time_parseMinutes,
+ p: d3_time_parseAmPm,
+ S: d3_time_parseSeconds,
+ x: d3_time_parseLocaleDate,
+ X: d3_time_parseLocaleTime,
+ y: d3_time_parseYear,
+ Y: d3_time_parseFullYear
+ };
+ function d3_time_parseWeekdayAbbrev(date, string, i) {
+ d3_time_dayAbbrevRe.lastIndex = 0;
+ var n = d3_time_dayAbbrevRe.exec(string.substring(i));
+ return n ? i += n[0].length : -1;
+ }
+ function d3_time_parseWeekday(date, string, i) {
+ d3_time_dayRe.lastIndex = 0;
+ var n = d3_time_dayRe.exec(string.substring(i));
+ return n ? i += n[0].length : -1;
+ }
+ function d3_time_parseMonthAbbrev(date, string, i) {
+ d3_time_monthAbbrevRe.lastIndex = 0;
+ var n = d3_time_monthAbbrevRe.exec(string.substring(i));
+ return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i += n[0].length) : -1;
+ }
+ function d3_time_parseMonth(date, string, i) {
+ d3_time_monthRe.lastIndex = 0;
+ var n = d3_time_monthRe.exec(string.substring(i));
+ return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i += n[0].length) : -1;
+ }
+ function d3_time_parseLocaleFull(date, string, i) {
+ return d3_time_parse(date, d3_time_formats.c.toString(), string, i);
+ }
+ function d3_time_parseLocaleDate(date, string, i) {
+ return d3_time_parse(date, d3_time_formats.x.toString(), string, i);
+ }
+ function d3_time_parseLocaleTime(date, string, i) {
+ return d3_time_parse(date, d3_time_formats.X.toString(), string, i);
+ }
+ function d3_time_parseFullYear(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 4));
+ return n ? (date.y = +n[0], i += n[0].length) : -1;
+ }
+ function d3_time_parseYear(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.y = d3_time_expandYear(+n[0]), i += n[0].length) : -1;
+ }
+ function d3_time_expandYear(d) {
+ return d + (d > 68 ? 1900 : 2e3);
+ }
+ function d3_time_parseMonthNumber(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.m = n[0] - 1, i += n[0].length) : -1;
+ }
+ function d3_time_parseDay(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.d = +n[0], i += n[0].length) : -1;
+ }
+ function d3_time_parseHour24(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.H = +n[0], i += n[0].length) : -1;
+ }
+ function d3_time_parseMinutes(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.M = +n[0], i += n[0].length) : -1;
+ }
+ function d3_time_parseSeconds(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.S = +n[0], i += n[0].length) : -1;
+ }
+ function d3_time_parseMilliseconds(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 3));
+ return n ? (date.L = +n[0], i += n[0].length) : -1;
+ }
+ var d3_time_numberRe = /^\s*\d+/;
+ function d3_time_parseAmPm(date, string, i) {
+ var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase());
+ return n == null ? -1 : (date.p = n, i);
+ }
+ var d3_time_amPmLookup = d3.map({
+ am: 0,
+ pm: 1
+ });
+ function d3_time_zone(d) {
+ var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60;
+ return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2);
+ }
+ d3.time.format.utc = function(template) {
+ var local = d3.time.format(template);
+ function format(date) {
+ try {
+ d3_time = d3_time_utc;
+ var utc = new d3_time();
+ utc._ = date;
+ return local(utc);
+ } finally {
+ d3_time = Date;
+ }
+ }
+ format.parse = function(string) {
+ try {
+ d3_time = d3_time_utc;
+ var date = local.parse(string);
+ return date && date._;
+ } finally {
+ d3_time = Date;
+ }
+ };
+ format.toString = local.toString;
+ return format;
+ };
+ var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");
+ d3.time.format.iso = Date.prototype.toISOString ? d3_time_formatIsoNative : d3_time_formatIso;
+ function d3_time_formatIsoNative(date) {
+ return date.toISOString();
+ }
+ d3_time_formatIsoNative.parse = function(string) {
+ var date = new Date(string);
+ return isNaN(date) ? null : date;
+ };
+ d3_time_formatIsoNative.toString = d3_time_formatIso.toString;
+ function d3_time_interval(local, step, number) {
+ function round(date) {
+ var d0 = local(date), d1 = offset(d0, 1);
+ return date - d0 < d1 - date ? d0 : d1;
+ }
+ function ceil(date) {
+ step(date = local(new d3_time(date - 1)), 1);
+ return date;
+ }
+ function offset(date, k) {
+ step(date = new d3_time(+date), k);
+ return date;
+ }
+ function range(t0, t1, dt) {
+ var time = ceil(t0), times = [];
+ if (dt > 1) {
+ while (time < t1) {
+ if (!(number(time) % dt)) times.push(new Date(+time));
+ step(time, 1);
+ }
+ } else {
+ while (time < t1) times.push(new Date(+time)), step(time, 1);
+ }
+ return times;
+ }
+ function range_utc(t0, t1, dt) {
+ try {
+ d3_time = d3_time_utc;
+ var utc = new d3_time_utc();
+ utc._ = t0;
+ return range(utc, t1, dt);
+ } finally {
+ d3_time = Date;
+ }
+ }
+ local.floor = local;
+ local.round = round;
+ local.ceil = ceil;
+ local.offset = offset;
+ local.range = range;
+ var utc = local.utc = d3_time_interval_utc(local);
+ utc.floor = utc;
+ utc.round = d3_time_interval_utc(round);
+ utc.ceil = d3_time_interval_utc(ceil);
+ utc.offset = d3_time_interval_utc(offset);
+ utc.range = range_utc;
+ return local;
+ }
+ function d3_time_interval_utc(method) {
+ return function(date, k) {
+ try {
+ d3_time = d3_time_utc;
+ var utc = new d3_time_utc();
+ utc._ = date;
+ return method(utc, k)._;
+ } finally {
+ d3_time = Date;
+ }
+ };
+ }
+ d3.time.second = d3_time_interval(function(date) {
+ return new d3_time(Math.floor(date / 1e3) * 1e3);
+ }, function(date, offset) {
+ date.setTime(date.getTime() + Math.floor(offset) * 1e3);
+ }, function(date) {
+ return date.getSeconds();
+ });
+ d3.time.seconds = d3.time.second.range;
+ d3.time.seconds.utc = d3.time.second.utc.range;
+ d3.time.minute = d3_time_interval(function(date) {
+ return new d3_time(Math.floor(date / 6e4) * 6e4);
+ }, function(date, offset) {
+ date.setTime(date.getTime() + Math.floor(offset) * 6e4);
+ }, function(date) {
+ return date.getMinutes();
+ });
+ d3.time.minutes = d3.time.minute.range;
+ d3.time.minutes.utc = d3.time.minute.utc.range;
+ d3.time.hour = d3_time_interval(function(date) {
+ var timezone = date.getTimezoneOffset() / 60;
+ return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
+ }, function(date, offset) {
+ date.setTime(date.getTime() + Math.floor(offset) * 36e5);
+ }, function(date) {
+ return date.getHours();
+ });
+ d3.time.hours = d3.time.hour.range;
+ d3.time.hours.utc = d3.time.hour.utc.range;
+ d3.time.day = d3_time_interval(function(date) {
+ var day = new d3_time(1970, 0);
+ day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
+ return day;
+ }, function(date, offset) {
+ date.setDate(date.getDate() + offset);
+ }, function(date) {
+ return date.getDate() - 1;
+ });
+ d3.time.days = d3.time.day.range;
+ d3.time.days.utc = d3.time.day.utc.range;
+ d3.time.dayOfYear = function(date) {
+ var year = d3.time.year(date);
+ return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5);
+ };
+ d3_time_daySymbols.forEach(function(day, i) {
+ day = day.toLowerCase();
+ i = 7 - i;
+ var interval = d3.time[day] = d3_time_interval(function(date) {
+ (date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7);
+ return date;
+ }, function(date, offset) {
+ date.setDate(date.getDate() + Math.floor(offset) * 7);
+ }, function(date) {
+ var day = d3.time.year(date).getDay();
+ return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i);
+ });
+ d3.time[day + "s"] = interval.range;
+ d3.time[day + "s"].utc = interval.utc.range;
+ d3.time[day + "OfYear"] = function(date) {
+ var day = d3.time.year(date).getDay();
+ return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7);
+ };
+ });
+ d3.time.week = d3.time.sunday;
+ d3.time.weeks = d3.time.sunday.range;
+ d3.time.weeks.utc = d3.time.sunday.utc.range;
+ d3.time.weekOfYear = d3.time.sundayOfYear;
+ d3.time.month = d3_time_interval(function(date) {
+ date = d3.time.day(date);
+ date.setDate(1);
+ return date;
+ }, function(date, offset) {
+ date.setMonth(date.getMonth() + offset);
+ }, function(date) {
+ return date.getMonth();
+ });
+ d3.time.months = d3.time.month.range;
+ d3.time.months.utc = d3.time.month.utc.range;
+ d3.time.year = d3_time_interval(function(date) {
+ date = d3.time.day(date);
+ date.setMonth(0, 1);
+ return date;
+ }, function(date, offset) {
+ date.setFullYear(date.getFullYear() + offset);
+ }, function(date) {
+ return date.getFullYear();
+ });
+ d3.time.years = d3.time.year.range;
+ d3.time.years.utc = d3.time.year.utc.range;
+ function d3_time_scale(linear, methods, format) {
+ function scale(x) {
+ return linear(x);
+ }
+ scale.invert = function(x) {
+ return d3_time_scaleDate(linear.invert(x));
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return linear.domain().map(d3_time_scaleDate);
+ linear.domain(x);
+ return scale;
+ };
+ scale.nice = function(m) {
+ return scale.domain(d3_scale_nice(scale.domain(), function() {
+ return m;
+ }));
+ };
+ scale.ticks = function(m, k) {
+ var extent = d3_time_scaleExtent(scale.domain());
+ if (typeof m !== "function") {
+ var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target);
+ if (i == d3_time_scaleSteps.length) return methods.year(extent, m);
+ if (!i) return linear.ticks(m).map(d3_time_scaleDate);
+ if (Math.log(target / d3_time_scaleSteps[i - 1]) < Math.log(d3_time_scaleSteps[i] / target)) --i;
+ m = methods[i];
+ k = m[1];
+ m = m[0].range;
+ }
+ return m(extent[0], new Date(+extent[1] + 1), k);
+ };
+ scale.tickFormat = function() {
+ return format;
+ };
+ scale.copy = function() {
+ return d3_time_scale(linear.copy(), methods, format);
+ };
+ return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
+ }
+ function d3_time_scaleExtent(domain) {
+ var start = domain[0], stop = domain[domain.length - 1];
+ return start < stop ? [ start, stop ] : [ stop, start ];
+ }
+ function d3_time_scaleDate(t) {
+ return new Date(t);
+ }
+ function d3_time_scaleFormat(formats) {
+ return function(date) {
+ var i = formats.length - 1, f = formats[i];
+ while (!f[1](date)) f = formats[--i];
+ return f[0](date);
+ };
+ }
+ function d3_time_scaleSetYear(y) {
+ var d = new Date(y, 0, 1);
+ d.setFullYear(y);
+ return d;
+ }
+ function d3_time_scaleGetYear(d) {
+ var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1);
+ return y + (d - d0) / (d1 - d0);
+ }
+ var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ];
+ var d3_time_scaleLocalMethods = [ [ d3.time.second, 1 ], [ d3.time.second, 5 ], [ d3.time.second, 15 ], [ d3.time.second, 30 ], [ d3.time.minute, 1 ], [ d3.time.minute, 5 ], [ d3.time.minute, 15 ], [ d3.time.minute, 30 ], [ d3.time.hour, 1 ], [ d3.time.hour, 3 ], [ d3.time.hour, 6 ], [ d3.time.hour, 12 ], [ d3.time.day, 1 ], [ d3.time.day, 2 ], [ d3.time.week, 1 ], [ d3.time.month, 1 ], [ d3.time.month, 3 ], [ d3.time.year, 1 ] ];
+ var d3_time_scaleLocalFormats = [ [ d3.time.format("%Y"), d3_true ], [ d3.time.format("%B"), function(d) {
+ return d.getMonth();
+ } ], [ d3.time.format("%b %d"), function(d) {
+ return d.getDate() != 1;
+ } ], [ d3.time.format("%a %d"), function(d) {
+ return d.getDay() && d.getDate() != 1;
+ } ], [ d3.time.format("%I %p"), function(d) {
+ return d.getHours();
+ } ], [ d3.time.format("%I:%M"), function(d) {
+ return d.getMinutes();
+ } ], [ d3.time.format(":%S"), function(d) {
+ return d.getSeconds();
+ } ], [ d3.time.format(".%L"), function(d) {
+ return d.getMilliseconds();
+ } ] ];
+ var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats);
+ d3_time_scaleLocalMethods.year = function(extent, m) {
+ return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear);
+ };
+ d3.time.scale = function() {
+ return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
+ };
+ var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) {
+ return [ m[0].utc, m[1] ];
+ });
+ var d3_time_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), d3_true ], [ d3.time.format.utc("%B"), function(d) {
+ return d.getUTCMonth();
+ } ], [ d3.time.format.utc("%b %d"), function(d) {
+ return d.getUTCDate() != 1;
+ } ], [ d3.time.format.utc("%a %d"), function(d) {
+ return d.getUTCDay() && d.getUTCDate() != 1;
+ } ], [ d3.time.format.utc("%I %p"), function(d) {
+ return d.getUTCHours();
+ } ], [ d3.time.format.utc("%I:%M"), function(d) {
+ return d.getUTCMinutes();
+ } ], [ d3.time.format.utc(":%S"), function(d) {
+ return d.getUTCSeconds();
+ } ], [ d3.time.format.utc(".%L"), function(d) {
+ return d.getUTCMilliseconds();
+ } ] ];
+ var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats);
+ function d3_time_scaleUTCSetYear(y) {
+ var d = new Date(Date.UTC(y, 0, 1));
+ d.setUTCFullYear(y);
+ return d;
+ }
+ function d3_time_scaleUTCGetYear(d) {
+ var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1);
+ return y + (d - d0) / (d1 - d0);
+ }
+ d3_time_scaleUTCMethods.year = function(extent, m) {
+ return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear);
+ };
+ d3.time.scale.utc = function() {
+ return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat);
+ };
+})(); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/datatables/images/Sorting icons.psd b/SemanticResultFormats/resources/jquery/datatables/images/Sorting icons.psd
new file mode 100644
index 00000000..53b2e068
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/images/Sorting icons.psd
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/datatables/images/back_disabled.png b/SemanticResultFormats/resources/jquery/datatables/images/back_disabled.png
new file mode 100644
index 00000000..881de797
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/images/back_disabled.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/datatables/images/back_enabled.png b/SemanticResultFormats/resources/jquery/datatables/images/back_enabled.png
new file mode 100644
index 00000000..c608682b
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/images/back_enabled.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/datatables/images/back_enabled_hover.png b/SemanticResultFormats/resources/jquery/datatables/images/back_enabled_hover.png
new file mode 100644
index 00000000..d300f106
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/images/back_enabled_hover.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/datatables/images/favicon.ico b/SemanticResultFormats/resources/jquery/datatables/images/favicon.ico
new file mode 100644
index 00000000..6eeaa2a0
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/images/favicon.ico
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/datatables/images/forward_disabled.png b/SemanticResultFormats/resources/jquery/datatables/images/forward_disabled.png
new file mode 100644
index 00000000..6a6ded7d
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/images/forward_disabled.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled.png b/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled.png
new file mode 100644
index 00000000..a4e6b538
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled_hover.png b/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled_hover.png
new file mode 100644
index 00000000..fc46c5eb
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/images/forward_enabled_hover.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/datatables/images/sort_asc.png b/SemanticResultFormats/resources/jquery/datatables/images/sort_asc.png
new file mode 100644
index 00000000..a88d7975
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/images/sort_asc.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/datatables/images/sort_asc_disabled.png b/SemanticResultFormats/resources/jquery/datatables/images/sort_asc_disabled.png
new file mode 100644
index 00000000..4e144cf0
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/images/sort_asc_disabled.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/datatables/images/sort_both.png b/SemanticResultFormats/resources/jquery/datatables/images/sort_both.png
new file mode 100644
index 00000000..18670406
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/images/sort_both.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/datatables/images/sort_desc.png b/SemanticResultFormats/resources/jquery/datatables/images/sort_desc.png
new file mode 100644
index 00000000..def071ed
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/images/sort_desc.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/datatables/images/sort_desc_disabled.png b/SemanticResultFormats/resources/jquery/datatables/images/sort_desc_disabled.png
new file mode 100644
index 00000000..7824973c
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/images/sort_desc_disabled.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.css b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.css
new file mode 100644
index 00000000..1e55b3e2
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.css
@@ -0,0 +1,217 @@
+/**
+ * Copied from http://twitter.github.com/bootstrap/1.4.0/bootstrap.min.css
+ * and adopted in order to work only with .srf-datatables
+ */
+
+/* Table*/
+
+.srf-datatables .bordered-table{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.srf-datatables .bordered-table th+th,.srf-datatables .bordered-table td+td,.srf-datatables .bordered-table th+td{border-left:1px solid #ddd;}
+.srf-datatables .bordered-table thead tr:first-child th:first-child,.srf-datatables .bordered-table tbody tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;}
+.srf-datatables .bordered-table thead tr:first-child th:last-child,.srf-datatables .bordered-table tbody tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;}
+.srf-datatables .bordered-table tbody tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;}
+.srf-datatables .bordered-table tbody tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;}
+
+.srf-datatables table{width:100%;margin-bottom:18px;padding:0;font-size:13px;border-collapse:collapse;}
+.srf-datatables table th,.srf-datatables table td{padding:10px 10px 9px;line-height:18px;text-align:left;}
+.srf-datatables table th{padding-top:9px;font-weight:bold;vertical-align:middle;}
+.srf-datatables table td{vertical-align:top;border-top:1px solid #ddd;}
+.srf-datatables table tbody th{border-top:1px solid #ddd;vertical-align:top;}
+.srf-datatables .condensed-table th,.srf-datatables .condensed-table td{padding:5px 5px 4px;}
+.srf-datatables .bordered-table{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.bordered-table th+th,.bordered-table td+td,.bordered-table th+td{border-left:1px solid #ddd;}
+.srf-datatables .bordered-table thead tr:first-child th:first-child,.srf-datatables .bordered-table tbody tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;}
+.srf-datatables .bordered-table thead tr:first-child th:last-child,.srf-datatables .bordered-table tbody tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;}
+.srf-datatables .bordered-table tbody tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;}
+.srf-datatables .bordered-table tbody tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;}
+
+.srf-datatables .zebra-striped tbody tr:nth-child(odd) td,.srf-datatables .zebra-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;}
+.srf-datatables .zebra-striped tbody tr:hover td,.srf-datatables .zebra-striped tbody tr:hover th{background-color:#f5f5f5;}
+.srf-datatables table .header{cursor:pointer;}table .header:after{content:"";float:right;margin-top:7px;border-width:0 4px 4px;border-style:solid;border-color:#000 transparent;visibility:hidden;}
+.srf-datatables table .headerSortUp,.srf-datatables table .headerSortDown{background-color:rgba(141, 192, 219, 0.25);text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);}
+.srf-datatables table .header:hover:after{visibility:visible;}
+.srf-datatables table .headerSortDown:after,.srf-datatables table .headerSortDown:hover:after{visibility:visible;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;}
+.srf-datatables table .headerSortUp:after{border-bottom:none;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000;visibility:visible;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;filter:alpha(opacity=60);-khtml-opacity:0.6;-moz-opacity:0.6;opacity:0.6;}
+.srf-datatables table .blue{color:#049cdb;border-bottom-color:#049cdb;}
+.srf-datatables table .headerSortUp.blue,.srf-datatables table .headerSortDown.blue{background-color:#ade6fe;}
+.srf-datatables table .green{color:#46a546;border-bottom-color:#46a546;}
+.srf-datatables table .headerSortUp.green,.srf-datatables table .headerSortDown.green{background-color:#cdeacd;}
+.srf-datatables table .red{color:#9d261d;border-bottom-color:#9d261d;}
+.srf-datatables table .headerSortUp.red,.srf-datatables table .headerSortDown.red{background-color:#f4c8c5;}
+.srf-datatables table .yellow{color:#ffc40d;border-bottom-color:#ffc40d;}
+.srf-datatables table .headerSortUp.yellow,.srf-datatables table .headerSortDown.yellow{background-color:#fff6d9;}
+.srf-datatables table .orange{color:#f89406;border-bottom-color:#f89406;}
+.srf-datatables table .headerSortUp.orange,.srf-datatables table .headerSortDown.orange{background-color:#fee9cc;}
+.srf-datatables table .purple{color:#7a43b6;border-bottom-color:#7a43b6;}
+.srf-datatables table .headerSortUp.purple,.srf-datatables table .headerSortDown.purple{background-color:#e2d5f0;}
+
+/* Input */
+
+.srf-datatables button,.srf-datatables input,.srf-datatables select,.srf-datatables textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;}
+.srf-datatables button,.srf-datatables input{line-height:normal;*overflow:visible;}
+.srf-datatables button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}
+.srf-datatables button,.srf-datatables input[type="button"],.srf-datatables input[type="reset"],.srf-datatables input[type="submit"]{cursor:pointer;-webkit-appearance:button;}
+.srf-datatables input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;}
+.srf-datatables input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}
+
+.srf-datatables input[type=checkbox],input[type=radio]{cursor:pointer;}
+.srf-datatables input,.srf-datatables textarea,.srf-datatables select,.srf-datatables .uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;font-size:13px;line-height:18px;color:#808080;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+.srf-datatables select{padding:initial;}
+.srf-datatables input[type=checkbox],input[type=radio]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;border:none;}
+.srf-datatables input[type=file]{background-color:#ffffff;padding:initial;border:initial;line-height:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
+.srf-datatables input[type=button],input[type=reset],input[type=submit]{width:auto;height:auto;}
+.srf-datatables select,input[type=file]{height:27px;*height:auto;line-height:27px;*margin-top:4px;}
+.srf-datatables select[multiple]{height:inherit;background-color:#ffffff;}
+.srf-datatables textarea{height:auto;}
+.srf-datatables .uneditable-input{background-color:#ffffff;display:block;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}
+.srf-datatables :-moz-placeholder{color:#bfbfbf;}
+.srf-datatables ::-webkit-input-placeholder{color:#bfbfbf;}
+.srf-datatables input,textarea{-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);}
+.srf-datatables input:focus,textarea:focus{outline:0;border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);}
+.srf-datatables input[type=file]:focus,input[type=checkbox]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:1px dotted #666;}
+
+.srf-datatables .input-mini,.srf-datatables input.mini,textarea.mini,.srf-datatables select.mini{width:60px;}
+.srf-datatables .input-small,.srf-datatables input.small,textarea.small,.srf-datatables select.small{width:90px;}
+.srf-datatables .input-medium,.srf-datatables input.medium,textarea.medium,.srf-datatables select.medium{width:150px;}
+.srf-datatables .input-large,.srf-datatables input.large,textarea.large,.srf-datatables select.large{width:210px;}
+.srf-datatables .input-xlarge,.srf-datatables input.xlarge,textarea.xlarge,.srf-datatables select.xlarge{width:270px;}
+.srf-datatables .input-xxlarge,.srf-datatables input.xxlarge,textarea.xxlarge,.srf-datatables select.xxlarge{width:530px;}
+.srf-datatables textarea.xxlarge{overflow-y:auto;}
+.srf-datatables input.span1,.srf-datatables textarea.span1{display:inline-block;float:none;width:30px;margin-left:0;}
+.srf-datatables input.span2,.srf-datatables textarea.span2{display:inline-block;float:none;width:90px;margin-left:0;}
+
+.srf-datatables input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;}
+
+.srf-datatables .inline-inputs{color:#808080;}.inline-inputs span{padding:0 2px 0 1px;}
+.srf-datatables .input-prepend input,.input-append input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
+.srf-datatables .input-prepend .add-on,.srf-datatables .input-append .add-on{position:relative;background:#f5f5f5;border:1px solid #ccc;z-index:2;float:left;display:block;width:auto;min-width:16px;height:18px;padding:4px 4px 4px 5px;margin-right:-1px;font-weight:normal;line-height:18px;color:#bfbfbf;text-align:center;text-shadow:0 1px 0 #ffffff;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
+.srf-datatables .input-prepend .active,.srf-datatables .input-append .active{background:#a9dba9;border-color:#46a546;}
+.srf-datatables .input-prepend .add-on{*margin-top:1px;}
+.srf-datatables .input-append input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
+.srf-datatables .input-append .add-on{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;margin-right:0;margin-left:-1px;}
+.srf-datatables .inputs-list{margin:0 0 5px;width:100%;}
+.srf-datatables .inputs-list li{display:block;padding:0;width:100%;}
+.srf-datatables .inputs-list label{display:block;float:none;width:auto;padding:0;margin-left:20px;line-height:18px;text-align:left;white-space:normal;}
+.srf-datatables .inputs-list label strong{color:#808080;}
+.srf-datatables .inputs-list label small{font-size:11px;font-weight:normal;}
+.srf-datatables .inputs-list .inputs-list{margin-left:25px;margin-bottom:10px;padding-top:0;}
+.srf-datatables .inputs-list:first-child{padding-top:6px;}
+.srf-datatables .inputs-list li+li{padding-top:2px;}
+.srf-datatables .inputs-list input[type=radio],.srf-datatables .inputs-list input[type=checkbox]{margin-bottom:0;margin-left:-20px;float:left;}
+
+.srf-datatables .row{zoom:1;margin-left:-20px;}.srf-datatables .row:before,.srf-datatables .row:after{display:table;content:"";zoom:1;}
+.srf-datatables .row:after{clear:both;}
+.srf-datatables .row>[class*="span"]{display:inline;margin-left:20px;}
+
+/* pagination */
+
+.srf-datatables .pagination{height:36px;margin:18px 0;}.srf-datatables .pagination ul{float:left;margin:0;border:1px solid #ddd;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);}
+.srf-datatables .pagination li{display:inline;}
+.srf-datatables .pagination a{float:left;padding:0 14px;line-height:34px;border-right:1px solid;border-right-color:#ddd;border-right-color:rgba(0, 0, 0, 0.15);*border-right-color:#ddd;text-decoration:none;}
+.srf-datatables .pagination a:hover,.srf-datatables .pagination .active a{background-color:#c7eefe;}
+.srf-datatables .pagination .disabled a,.srf-datatables .pagination .disabled a:hover{background-color:transparent;color:#bfbfbf;}
+.srf-datatables .pagination .next a{border:0;}
+
+/* DataTables */
+.srf-datatables .span-search,.srf-datatables .span-page{ float: right; }
+.srf-datatables .span-select,.srf-datatables .span-list{ float: left; }
+
+.srf-datatables .dataTables_length label {
+ float: left;
+ text-align: left;
+}
+
+.srf-datatables .dataTables_length select {
+ width: 75px;
+}
+
+.srf-datatables .dataTables_filter label {
+ float: right;
+}
+
+.srf-datatables .dataTables_info {
+ padding-top: 8px;
+}
+
+.srf-datatables .dataTables_paginate {
+ float: right;
+ margin: 0;
+}
+
+.srf-datatables table {
+ margin: 1em 0;
+ clear: both;
+}
+
+.srf-datatables table.dataTable th:active {
+ outline: none;
+}
+
+.srf-datatables .ui-button-primary {
+color: white;
+background-image: none;
+background-color: #0064CD;
+background-repeat: repeat-x;
+background-image: -webkit-linear-gradient(top, #049CDB, #0064CD);
+background-image: -moz-linear-gradient(top, #049CDB, #0064CD);
+background-image: -o-linear-gradient(top, #049CDB, #0064CD);
+background-image: linear-gradient(top, #049CDB, #0064CD);
+filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#049CDB', endColorstr='#0064CD', GradientType=0);
+text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+border-color: #0064CD #0064CD #003F81;
+border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+}
+
+.srf-datatables .ui-button{
+ margin: 0 0 0 0;
+ cursor: pointer;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+ color: #333;
+ font-size: 13px;
+ line-height: normal;
+ cursor: pointer;
+ display: inline-block;
+
+ background-color: #E6E6E6;
+ background-repeat: no-repeat;
+ background-image: -webkit-linear-gradient(white, white 25%, #E6E6E6) !important;
+ background-image: -moz-linear-gradient(top, white, white 25%, #E6E6E6) !important;
+ background-image: -o-linear-gradient(white, white 25%, #E6E6E6) !important;
+ background-image: linear-gradient(white, white 25%, #E6E6E6) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='white', endColorstr='#E6E6E6', GradientType=0);
+ padding: 5px 14px 6px;
+ margin: 0;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+ color: #333;
+ font-size: 13px;
+ line-height: normal;
+ border: 1px solid #CCC !important;
+ border-bottom-color: #BBB;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -webkit-transition: 0.1s linear background-image;
+ -moz-transition: 0.1s linear background-image;
+ -o-transition: 0.1s linear background-image;
+ transition: 0.1s linear background-image;
+ overflow: visible;
+}
+
+.srf-datatables .ui-corner-bottom, .ui-corner-right, .ui-corner-br {
+-webkit-border-bottom-right-radius: 4px;
+-moz-border-radius-bottomright: 4px;
+border-bottom-right-radius: 4px;
+}
+
+.srf-datatables .ui-corner-top, .ui-corner-right, .ui-corner-tr {
+-webkit-border-top-right-radius: 4px;
+-moz-border-radius-topright: 4px;
+border-top-right-radius: 4px;
+}
+
+/* Word wrap a link so it doesn't overflow */
+.srf-datatables table td, .srf-datatables table th {
+ white-space: pre-wrap; /* css-3 */
+ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ word-wrap: break-word; /* Internet Explorer 5.5+ */
+} \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.js b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.js
new file mode 100644
index 00000000..9fdbadac
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.bootstrap.js
@@ -0,0 +1,108 @@
+/**
+ * DataTables extras
+ *
+ * @see http://datatables.net/extras/
+ *
+ * @since 1.9
+ */
+( function( $ ) {
+ 'use strict';
+
+$.extend( $.fn.dataTableExt.oStdClasses, {
+ 'sSortAsc': 'header headerSortDown',
+ 'sSortDesc': 'header headerSortUp',
+ 'sWrapper': 'dataTables_wrapper form-inline',
+ 'sSortable': 'header'
+} );
+
+/* API method to get paging information */
+$.fn.dataTableExt.oApi.fnPagingInfo = function ( oSettings ){
+return {
+ 'iStart': oSettings._iDisplayStart,
+ 'iEnd': oSettings.fnDisplayEnd(),
+ 'iLength': oSettings._iDisplayLength,
+ 'iTotal': oSettings.fnRecordsTotal(),
+ 'iFilteredTotal': oSettings.fnRecordsDisplay(),
+ 'iPage': Math.ceil( oSettings._iDisplayStart / oSettings._iDisplayLength ),
+ 'iTotalPages': Math.ceil( oSettings.fnRecordsDisplay() / oSettings._iDisplayLength )
+ };
+};
+
+/* Bootstrap style pagination control */
+$.extend( $.fn.dataTableExt.oPagination, {
+ 'bootstrap': {
+ fnInit: function( oSettings, nPaging, fnDraw ) {
+ var oLang = oSettings.oLanguage.oPaginate;
+ var fnClickHandler = function ( e ) {
+ e.preventDefault();
+ if ( oSettings.oApi._fnPageChange(oSettings, e.data.action) ) {
+ fnDraw( oSettings );
+ }
+ };
+
+ $(nPaging).addClass('pagination').append(
+ '<ul>'+
+ '<li class="prev disabled"><a href="#">&larr; '+oLang.sPrevious+'</a></li>'+
+ '<li class="next disabled"><a href="#">'+oLang.sNext+' &rarr; </a></li>'+
+ '</ul>'
+ );
+ var els = $('a', nPaging);
+ $(els[0]).bind( 'click.DT', { action: "previous" }, fnClickHandler );
+ $(els[1]).bind( 'click.DT', { action: "next" }, fnClickHandler );
+ },
+
+ fnUpdate: function ( oSettings, fnDraw ) {
+ var iListLength = 5;
+ var oPaging = oSettings.oInstance.fnPagingInfo();
+ var an = oSettings.aanFeatures.p;
+ var i, j, iLen, sClass, iStart, iEnd, iHalf=Math.floor(iListLength/2);
+
+ if ( oPaging.iTotalPages < iListLength) {
+ iStart = 1;
+ iEnd = oPaging.iTotalPages;
+ }
+ else if ( oPaging.iPage <= iHalf ) {
+ iStart = 1;
+ iEnd = iListLength;
+ } else if ( oPaging.iPage >= (oPaging.iTotalPages-iHalf) ) {
+ iStart = oPaging.iTotalPages - iListLength + 1;
+ iEnd = oPaging.iTotalPages;
+ } else {
+ iStart = oPaging.iPage - iHalf + 1;
+ iEnd = iStart + iListLength - 1;
+ }
+
+ for ( i=0, iLen=an.length ; i<iLen ; i++ ) {
+ // Remove the middle elements
+ $('li:gt(0)', an[i]).filter(':not(:last)').remove();
+
+ // Add the new list items and their event handlers
+ for ( j=iStart ; j<=iEnd ; j++ ) {
+ sClass = (j==oPaging.iPage+1) ? 'class="active"' : '';
+ $('<li '+sClass+'><a href="#">'+j+'</a></li>')
+ .insertBefore( $('li:last', an[i])[0] )
+ .bind('click', function (e) {
+ e.preventDefault();
+ oSettings._iDisplayStart = (parseInt($('a', this).text(),10)-1) * oPaging.iLength;
+ fnDraw( oSettings );
+ } );
+ }
+
+ // Add / remove disabled classes from the static elements
+ if ( oPaging.iPage === 0 ) {
+ $('li:first', an[i]).addClass('disabled');
+ } else {
+ $('li:first', an[i]).removeClass('disabled');
+ }
+
+ if ( oPaging.iPage === oPaging.iTotalPages-1 || oPaging.iTotalPages === 0 ) {
+ $('li:last', an[i]).addClass('disabled');
+ } else {
+ $('li:last', an[i]).removeClass('disabled');
+ }
+ }
+ }
+ }
+} );
+
+} )( jQuery ); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.css b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.css
new file mode 100644
index 00000000..7da7faec
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.css
@@ -0,0 +1,221 @@
+
+/*
+ * Table
+ */
+table.dataTable {
+ margin: 0 auto;
+ clear: both;
+ width: 100%;
+}
+
+table.dataTable thead th {
+ padding: 3px 18px 3px 10px;
+ border-bottom: 1px solid black;
+ font-weight: bold;
+ cursor: pointer;
+ *cursor: hand;
+}
+
+table.dataTable tfoot th {
+ padding: 3px 18px 3px 10px;
+ border-top: 1px solid black;
+ font-weight: bold;
+}
+
+table.dataTable td {
+ padding: 3px 10px;
+}
+
+table.dataTable td.center,
+table.dataTable td.dataTables_empty {
+ text-align: center;
+}
+
+table.dataTable tr.odd { background-color: #E2E4FF; }
+table.dataTable tr.even { background-color: white; }
+
+table.dataTable tr.odd td.sorting_1 { background-color: #D3D6FF; }
+table.dataTable tr.odd td.sorting_2 { background-color: #DADCFF; }
+table.dataTable tr.odd td.sorting_3 { background-color: #E0E2FF; }
+table.dataTable tr.even td.sorting_1 { background-color: #EAEBFF; }
+table.dataTable tr.even td.sorting_2 { background-color: #F2F3FF; }
+table.dataTable tr.even td.sorting_3 { background-color: #F9F9FF; }
+
+
+/*
+ * Table wrapper
+ */
+.dataTables_wrapper {
+ position: relative;
+ clear: both;
+ *zoom: 1;
+}
+
+
+/*
+ * Page length menu
+ */
+.dataTables_length {
+ float: left;
+}
+
+
+/*
+ * Filter
+ */
+.dataTables_filter {
+ float: right;
+ text-align: right;
+}
+
+
+/*
+ * Table information
+ */
+.dataTables_info {
+ clear: both;
+ float: left;
+}
+
+
+/*
+ * Pagination
+ */
+.dataTables_paginate {
+ float: right;
+ text-align: right;
+}
+
+/* Two button pagination - previous / next */
+.paginate_disabled_previous,
+.paginate_enabled_previous,
+.paginate_disabled_next,
+.paginate_enabled_next {
+ height: 19px;
+ float: left;
+ cursor: pointer;
+ *cursor: hand;
+ color: #111 !important;
+}
+.paginate_disabled_previous:hover,
+.paginate_enabled_previous:hover,
+.paginate_disabled_next:hover,
+.paginate_enabled_next:hover {
+ text-decoration: none !important;
+}
+.paginate_disabled_previous:active,
+.paginate_enabled_previous:active,
+.paginate_disabled_next:active,
+.paginate_enabled_next:active {
+ outline: none;
+}
+
+.paginate_disabled_previous,
+.paginate_disabled_next {
+ color: #666 !important;
+}
+.paginate_disabled_previous,
+.paginate_enabled_previous {
+ padding-left: 23px;
+}
+.paginate_disabled_next,
+.paginate_enabled_next {
+ padding-right: 23px;
+ margin-left: 10px;
+}
+
+.paginate_enabled_previous { background: url('../images/back_enabled.png') no-repeat top left; }
+.paginate_enabled_previous:hover { background: url('../images/back_enabled_hover.png') no-repeat top left; }
+.paginate_disabled_previous { background: url('../images/back_disabled.png') no-repeat top left; }
+
+.paginate_enabled_next { background: url('../images/forward_enabled.png') no-repeat top right; }
+.paginate_enabled_next:hover { background: url('../images/forward_enabled_hover.png') no-repeat top right; }
+.paginate_disabled_next { background: url('../images/forward_disabled.png') no-repeat top right; }
+
+/* Full number pagination */
+.paging_full_numbers {
+ height: 22px;
+ line-height: 22px;
+}
+.paging_full_numbers a:active {
+ outline: none
+}
+.paging_full_numbers a:hover {
+ text-decoration: none;
+}
+
+.paging_full_numbers a.paginate_button,
+.paging_full_numbers a.paginate_active {
+ border: 1px solid #aaa;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+ padding: 2px 5px;
+ margin: 0 3px;
+ cursor: pointer;
+ *cursor: hand;
+ color: #333 !important;
+}
+
+.paging_full_numbers a.paginate_button {
+ background-color: #ddd;
+}
+
+.paging_full_numbers a.paginate_button:hover {
+ background-color: #ccc;
+ text-decoration: none !important;
+}
+
+.paging_full_numbers a.paginate_active {
+ background-color: #99B3FF;
+}
+
+
+/*
+ * Processing indicator
+ */
+.dataTables_processing {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 250px;
+ height: 30px;
+ margin-left: -125px;
+ margin-top: -15px;
+ padding: 14px 0 2px 0;
+ border: 1px solid #ddd;
+ text-align: center;
+ color: #999;
+ font-size: 14px;
+ background-color: white;
+}
+
+
+/*
+ * Sorting
+ */
+.sorting { background: url('../images/sort_both.png') no-repeat center right; }
+.sorting_asc { background: url('../images/sort_asc.png') no-repeat center right; }
+.sorting_desc { background: url('../images/sort_desc.png') no-repeat center right; }
+
+.sorting_asc_disabled { background: url('../images/sort_asc_disabled.png') no-repeat center right; }
+.sorting_desc_disabled { background: url('../images/sort_desc_disabled.png') no-repeat center right; }
+
+table.dataTable thead th:active,
+table.dataTable thead td:active {
+ outline: none;
+}
+
+
+/*
+ * Scrolling
+ */
+.dataTables_scroll {
+ clear: both;
+}
+
+.dataTables_scrollBody {
+ *margin-top: -1px;
+ -webkit-overflow-scrolling: touch;
+}
+
diff --git a/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.extras.js b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.extras.js
new file mode 100644
index 00000000..3fe581c9
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.extras.js
@@ -0,0 +1,84 @@
+/**
+ * DataTables extras
+ *
+ * @see http://datatables.net/
+ *
+ * @since 1.9
+ */
+( function( $ ) {
+ 'use strict';
+
+// Sorting Currency Columns
+$.fn.dataTableExt.aTypes.unshift(
+ function ( sData ) {
+ var sValidChars = "0123456789.-,";
+ var Char;
+
+ if( sData !== undefined ) {
+ /* Check the numeric part */
+ for ( var i=1 ; i < sData.length ; i++ ) {
+ Char = sData.charAt(i);
+ if (sValidChars.indexOf(Char) == -1)
+ {
+ return null;
+ }
+ }
+
+ /* Check prefixed by currency */
+ if ( sData.charAt(0) == '$' || sData.charAt(0) == '£' ) {
+ return 'currency';
+ }
+ return null;
+ }
+ }
+);
+
+$.fn.dataTableExt.oSort['currency-asc'] = function(a,b) {
+ /* Remove any formatting */
+ var x = a == "-" ? 0 : a.replace( /[^\d\-\.]/g, "" );
+ var y = b == "-" ? 0 : b.replace( /[^\d\-\.]/g, "" );
+
+ /* Parse and return */
+ x = parseFloat( x );
+ y = parseFloat( y );
+ return x - y;
+};
+
+$.fn.dataTableExt.oSort['currency-desc'] = function(a,b) {
+ var x = a === '-' ? 0 : a.replace( /[^\d\-\.]/g, '' );
+ var y = b === '-' ? 0 : b.replace( /[^\d\-\.]/g, '' );
+
+ x = parseFloat( x );
+ y = parseFloat( y );
+ return y - x;
+};
+
+// Sorting Formatted Numbers
+$.fn.dataTableExt.aTypes.unshift(
+ function ( sData ) {
+ if( sData !== undefined && $.isNumeric( sData ) ) {
+ // var deformatted = sData.replace(/[^\d\-\.\/a-zA-Z]/g,'');
+ //if ( $.isNumeric( deformatted ) ) {
+ return 'formatted-num';
+ }
+ return null;
+ }
+);
+
+$.fn.dataTableExt.oSort['formatted-num-asc'] = function(a,b) {
+ /* Remove any formatting */
+ var x = a.match(/\d/) ? a.replace( /[^\d\-\.]/g, "" ) : 0;
+ var y = b.match(/\d/) ? b.replace( /[^\d\-\.]/g, "" ) : 0;
+
+ /* Parse and return */
+ return parseFloat(x) - parseFloat(y);
+};
+
+$.fn.dataTableExt.oSort['formatted-num-desc'] = function(a,b) {
+ var x = a.match(/\d/) ? a.replace( /[^\d\-\.]/g, "" ) : 0;
+ var y = b.match(/\d/) ? b.replace( /[^\d\-\.]/g, "" ) : 0;
+
+ return parseFloat(y) - parseFloat(x);
+};
+
+} )( jQuery ); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.images.css b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.images.css
new file mode 100644
index 00000000..0a0ec9fa
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.images.css
@@ -0,0 +1,29 @@
+/**
+ * CSS dataTables adopt for the MW ResourceLoader environment
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+
+.paginate_enabled_previous { /* @embed */ background: url('images/back_enabled.png') no-repeat top left; }
+.paginate_enabled_previous:hover { /* @embed */ background: url('images/back_enabled_hover.png') no-repeat top left; }
+.paginate_disabled_previous { /* @embed */ background: url('images/back_disabled.png') no-repeat top left; }
+
+.paginate_enabled_next { /* @embed */ background: url('images/forward_enabled.png') no-repeat top right; }
+.paginate_enabled_next:hover { /* @embed */ background: url('images/forward_enabled_hover.png') no-repeat top right; }
+.paginate_disabled_next { /* @embed */ background: url('images/forward_disabled.png') no-repeat top right; }
+
+/*
+ * Sorting
+ */
+.sorting { /* @embed */ background: url('images/sort_both.png') no-repeat center right; }
+.sorting_asc { /* @embed */ background: url('images/sort_asc.png') no-repeat center right; }
+.sorting_desc { /* @embed */ background: url('images/sort_desc.png') no-repeat center right; }
+
+.sorting_asc_disabled { /* @embed */ background: url('images/sort_asc_disabled.png') no-repeat center right; }
+.sorting_desc_disabled { /* @embed */ background: url('images/sort_desc_disabled.png') no-repeat center right; }
diff --git a/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.js b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.js
new file mode 100644
index 00000000..1d8a220b
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables.js
@@ -0,0 +1,12099 @@
+/**
+ * @summary DataTables
+ * @description Paginate, search and sort HTML tables
+ * @version 1.9.4
+ * @file jquery.dataTables.js
+ * @author Allan Jardine (www.sprymedia.co.uk)
+ * @contact www.sprymedia.co.uk/contact
+ *
+ * @copyright Copyright 2008-2012 Allan Jardine, all rights reserved.
+ *
+ * This source file is free software, under either the GPL v2 license or a
+ * BSD style license, available at:
+ * http://datatables.net/license_gpl2
+ * http://datatables.net/license_bsd
+ *
+ * This source file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
+ *
+ * For details please refer to: http://www.datatables.net
+ */
+
+/*jslint evil: true, undef: true, browser: true */
+/*globals $, jQuery,define,_fnExternApiFunc,_fnInitialise,_fnInitComplete,_fnLanguageCompat,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnCreateTr,_fnGatherData,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnServerParams,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAdjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnDetectHeader,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnApplyColumnDefs,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnJsonString,_fnRender,_fnNodeToColumnIndex,_fnInfoMacros,_fnBrowserDetect,_fnGetColumns*/
+
+(/** @lends <global> */function( window, document, undefined ) {
+
+(function( factory ) {
+ "use strict";
+
+ // Define as an AMD module if possible
+ if ( typeof define === 'function' && define.amd )
+ {
+ define( ['jquery'], factory );
+ }
+ /* Define using browser globals otherwise
+ * Prevent multiple instantiations if the script is loaded twice
+ */
+ else if ( jQuery && !jQuery.fn.dataTable )
+ {
+ factory( jQuery );
+ }
+}
+(/** @lends <global> */function( $ ) {
+ "use strict";
+ /**
+ * DataTables is a plug-in for the jQuery Javascript library. It is a
+ * highly flexible tool, based upon the foundations of progressive
+ * enhancement, which will add advanced interaction controls to any
+ * HTML table. For a full list of features please refer to
+ * <a href="http://datatables.net">DataTables.net</a>.
+ *
+ * Note that the <i>DataTable</i> object is not a global variable but is
+ * aliased to <i>jQuery.fn.DataTable</i> and <i>jQuery.fn.dataTable</i> through which
+ * it may be accessed.
+ *
+ * @class
+ * @param {object} [oInit={}] Configuration object for DataTables. Options
+ * are defined by {@link DataTable.defaults}
+ * @requires jQuery 1.3+
+ *
+ * @example
+ * // Basic initialisation
+ * $(document).ready( function {
+ * $('#example').dataTable();
+ * } );
+ *
+ * @example
+ * // Initialisation with configuration options - in this case, disable
+ * // pagination and sorting.
+ * $(document).ready( function {
+ * $('#example').dataTable( {
+ * "bPaginate": false,
+ * "bSort": false
+ * } );
+ * } );
+ */
+ var DataTable = function( oInit )
+ {
+
+
+ /**
+ * Add a column to the list used for the table with default values
+ * @param {object} oSettings dataTables settings object
+ * @param {node} nTh The th element for this column
+ * @memberof DataTable#oApi
+ */
+ function _fnAddColumn( oSettings, nTh )
+ {
+ var oDefaults = DataTable.defaults.columns;
+ var iCol = oSettings.aoColumns.length;
+ var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
+ "sSortingClass": oSettings.oClasses.sSortable,
+ "sSortingClassJUI": oSettings.oClasses.sSortJUI,
+ "nTh": nTh ? nTh : document.createElement('th'),
+ "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
+ "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
+ "mData": oDefaults.mData ? oDefaults.oDefaults : iCol
+ } );
+ oSettings.aoColumns.push( oCol );
+
+ /* Add a column specific filter */
+ if ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null )
+ {
+ oSettings.aoPreSearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch );
+ }
+ else
+ {
+ var oPre = oSettings.aoPreSearchCols[ iCol ];
+
+ /* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */
+ if ( oPre.bRegex === undefined )
+ {
+ oPre.bRegex = true;
+ }
+
+ if ( oPre.bSmart === undefined )
+ {
+ oPre.bSmart = true;
+ }
+
+ if ( oPre.bCaseInsensitive === undefined )
+ {
+ oPre.bCaseInsensitive = true;
+ }
+ }
+
+ /* Use the column options function to initialise classes etc */
+ _fnColumnOptions( oSettings, iCol, null );
+ }
+
+
+ /**
+ * Apply options for a column
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iCol column index to consider
+ * @param {object} oOptions object with sType, bVisible and bSearchable etc
+ * @memberof DataTable#oApi
+ */
+ function _fnColumnOptions( oSettings, iCol, oOptions )
+ {
+ var oCol = oSettings.aoColumns[ iCol ];
+
+ /* User specified column options */
+ if ( oOptions !== undefined && oOptions !== null )
+ {
+ /* Backwards compatibility for mDataProp */
+ if ( oOptions.mDataProp && !oOptions.mData )
+ {
+ oOptions.mData = oOptions.mDataProp;
+ }
+
+ if ( oOptions.sType !== undefined )
+ {
+ oCol.sType = oOptions.sType;
+ oCol._bAutoType = false;
+ }
+
+ $.extend( oCol, oOptions );
+ _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
+
+ /* iDataSort to be applied (backwards compatibility), but aDataSort will take
+ * priority if defined
+ */
+ if ( oOptions.iDataSort !== undefined )
+ {
+ oCol.aDataSort = [ oOptions.iDataSort ];
+ }
+ _fnMap( oCol, oOptions, "aDataSort" );
+ }
+
+ /* Cache the data get and set functions for speed */
+ var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
+ var mData = _fnGetObjectDataFn( oCol.mData );
+
+ oCol.fnGetData = function (oData, sSpecific) {
+ var innerData = mData( oData, sSpecific );
+
+ if ( oCol.mRender && (sSpecific && sSpecific !== '') )
+ {
+ return mRender( innerData, sSpecific, oData );
+ }
+ return innerData;
+ };
+ oCol.fnSetData = _fnSetObjectDataFn( oCol.mData );
+
+ /* Feature sorting overrides column specific when off */
+ if ( !oSettings.oFeatures.bSort )
+ {
+ oCol.bSortable = false;
+ }
+
+ /* Check that the class assignment is correct for sorting */
+ if ( !oCol.bSortable ||
+ ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )
+ {
+ oCol.sSortingClass = oSettings.oClasses.sSortableNone;
+ oCol.sSortingClassJUI = "";
+ }
+ else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1 )
+ {
+ oCol.sSortingClass = oSettings.oClasses.sSortable;
+ oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI;
+ }
+ else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 )
+ {
+ oCol.sSortingClass = oSettings.oClasses.sSortableAsc;
+ oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed;
+ }
+ else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 )
+ {
+ oCol.sSortingClass = oSettings.oClasses.sSortableDesc;
+ oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed;
+ }
+ }
+
+
+ /**
+ * Adjust the table column widths for new data. Note: you would probably want to
+ * do a redraw after calling this function!
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnAdjustColumnSizing ( oSettings )
+ {
+ /* Not interested in doing column width calculation if auto-width is disabled */
+ if ( oSettings.oFeatures.bAutoWidth === false )
+ {
+ return false;
+ }
+
+ _fnCalculateColumnWidths( oSettings );
+ for ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth;
+ }
+ }
+
+
+ /**
+ * Covert the index of a visible column to the index in the data array (take account
+ * of hidden columns)
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iMatch Visible column index to lookup
+ * @returns {int} i the data index
+ * @memberof DataTable#oApi
+ */
+ function _fnVisibleToColumnIndex( oSettings, iMatch )
+ {
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
+
+ return typeof aiVis[iMatch] === 'number' ?
+ aiVis[iMatch] :
+ null;
+ }
+
+
+ /**
+ * Covert the index of an index in the data array and convert it to the visible
+ * column index (take account of hidden columns)
+ * @param {int} iMatch Column index to lookup
+ * @param {object} oSettings dataTables settings object
+ * @returns {int} i the data index
+ * @memberof DataTable#oApi
+ */
+ function _fnColumnIndexToVisible( oSettings, iMatch )
+ {
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
+ var iPos = $.inArray( iMatch, aiVis );
+
+ return iPos !== -1 ? iPos : null;
+ }
+
+
+ /**
+ * Get the number of visible columns
+ * @param {object} oSettings dataTables settings object
+ * @returns {int} i the number of visible columns
+ * @memberof DataTable#oApi
+ */
+ function _fnVisbleColumns( oSettings )
+ {
+ return _fnGetColumns( oSettings, 'bVisible' ).length;
+ }
+
+
+ /**
+ * Get an array of column indexes that match a given property
+ * @param {object} oSettings dataTables settings object
+ * @param {string} sParam Parameter in aoColumns to look for - typically
+ * bVisible or bSearchable
+ * @returns {array} Array of indexes with matched properties
+ * @memberof DataTable#oApi
+ */
+ function _fnGetColumns( oSettings, sParam )
+ {
+ var a = [];
+
+ $.map( oSettings.aoColumns, function(val, i) {
+ if ( val[sParam] ) {
+ a.push( i );
+ }
+ } );
+
+ return a;
+ }
+
+
+ /**
+ * Get the sort type based on an input string
+ * @param {string} sData data we wish to know the type of
+ * @returns {string} type (defaults to 'string' if no type can be detected)
+ * @memberof DataTable#oApi
+ */
+ function _fnDetectType( sData )
+ {
+ var aTypes = DataTable.ext.aTypes;
+ var iLen = aTypes.length;
+
+ for ( var i=0 ; i<iLen ; i++ )
+ {
+ var sType = aTypes[i]( sData );
+ if ( sType !== null )
+ {
+ return sType;
+ }
+ }
+
+ return 'string';
+ }
+
+
+ /**
+ * Figure out how to reorder a display list
+ * @param {object} oSettings dataTables settings object
+ * @returns array {int} aiReturn index list for reordering
+ * @memberof DataTable#oApi
+ */
+ function _fnReOrderIndex ( oSettings, sColumns )
+ {
+ var aColumns = sColumns.split(',');
+ var aiReturn = [];
+
+ for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ for ( var j=0 ; j<iLen ; j++ )
+ {
+ if ( oSettings.aoColumns[i].sName == aColumns[j] )
+ {
+ aiReturn.push( j );
+ break;
+ }
+ }
+ }
+
+ return aiReturn;
+ }
+
+
+ /**
+ * Get the column ordering that DataTables expects
+ * @param {object} oSettings dataTables settings object
+ * @returns {string} comma separated list of names
+ * @memberof DataTable#oApi
+ */
+ function _fnColumnOrdering ( oSettings )
+ {
+ var sNames = '';
+ for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ sNames += oSettings.aoColumns[i].sName+',';
+ }
+ if ( sNames.length == iLen )
+ {
+ return "";
+ }
+ return sNames.slice(0, -1);
+ }
+
+
+ /**
+ * Take the column definitions and static columns arrays and calculate how
+ * they relate to column indexes. The callback function will then apply the
+ * definition found for a column to a suitable configuration object.
+ * @param {object} oSettings dataTables settings object
+ * @param {array} aoColDefs The aoColumnDefs array that is to be applied
+ * @param {array} aoCols The aoColumns array that defines columns individually
+ * @param {function} fn Callback function - takes two parameters, the calculated
+ * column index and the definition for that column.
+ * @memberof DataTable#oApi
+ */
+ function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
+ {
+ var i, iLen, j, jLen, k, kLen;
+
+ // Column definitions with aTargets
+ if ( aoColDefs )
+ {
+ /* Loop over the definitions array - loop in reverse so first instance has priority */
+ for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
+ {
+ /* Each definition can target multiple columns, as it is an array */
+ var aTargets = aoColDefs[i].aTargets;
+ if ( !$.isArray( aTargets ) )
+ {
+ _fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );
+ }
+
+ for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
+ {
+ if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
+ {
+ /* Add columns that we don't yet know about */
+ while( oSettings.aoColumns.length <= aTargets[j] )
+ {
+ _fnAddColumn( oSettings );
+ }
+
+ /* Integer, basic index */
+ fn( aTargets[j], aoColDefs[i] );
+ }
+ else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
+ {
+ /* Negative integer, right to left column counting */
+ fn( oSettings.aoColumns.length+aTargets[j], aoColDefs[i] );
+ }
+ else if ( typeof aTargets[j] === 'string' )
+ {
+ /* Class name matching on TH element */
+ for ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )
+ {
+ if ( aTargets[j] == "_all" ||
+ $(oSettings.aoColumns[k].nTh).hasClass( aTargets[j] ) )
+ {
+ fn( k, aoColDefs[i] );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Statically defined columns array
+ if ( aoCols )
+ {
+ for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
+ {
+ fn( i, aoCols[i] );
+ }
+ }
+ }
+
+ /**
+ * Add a data array to the table, creating DOM node etc. This is the parallel to
+ * _fnGatherData, but for adding rows from a Javascript source, rather than a
+ * DOM source.
+ * @param {object} oSettings dataTables settings object
+ * @param {array} aData data array to be added
+ * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
+ * @memberof DataTable#oApi
+ */
+ function _fnAddData ( oSettings, aDataSupplied )
+ {
+ var oCol;
+
+ /* Take an independent copy of the data source so we can bash it about as we wish */
+ var aDataIn = ($.isArray(aDataSupplied)) ?
+ aDataSupplied.slice() :
+ $.extend( true, {}, aDataSupplied );
+
+ /* Create the object for storing information about this new row */
+ var iRow = oSettings.aoData.length;
+ var oData = $.extend( true, {}, DataTable.models.oRow );
+ oData._aData = aDataIn;
+ oSettings.aoData.push( oData );
+
+ /* Create the cells */
+ var nTd, sThisType;
+ for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ oCol = oSettings.aoColumns[i];
+
+ /* Use rendered data for filtering / sorting */
+ if ( typeof oCol.fnRender === 'function' && oCol.bUseRendered && oCol.mData !== null )
+ {
+ _fnSetCellData( oSettings, iRow, i, _fnRender(oSettings, iRow, i) );
+ }
+ else
+ {
+ _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
+ }
+
+ /* See if we should auto-detect the column type */
+ if ( oCol._bAutoType && oCol.sType != 'string' )
+ {
+ /* Attempt to auto detect the type - same as _fnGatherData() */
+ var sVarType = _fnGetCellData( oSettings, iRow, i, 'type' );
+ if ( sVarType !== null && sVarType !== '' )
+ {
+ sThisType = _fnDetectType( sVarType );
+ if ( oCol.sType === null )
+ {
+ oCol.sType = sThisType;
+ }
+ else if ( oCol.sType != sThisType && oCol.sType != "html" )
+ {
+ /* String is always the 'fallback' option */
+ oCol.sType = 'string';
+ }
+ }
+ }
+ }
+
+ /* Add to the display array */
+ oSettings.aiDisplayMaster.push( iRow );
+
+ /* Create the DOM information */
+ if ( !oSettings.oFeatures.bDeferRender )
+ {
+ _fnCreateTr( oSettings, iRow );
+ }
+
+ return iRow;
+ }
+
+
+ /**
+ * Read in the data from the target table from the DOM
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnGatherData( oSettings )
+ {
+ var iLoop, i, iLen, j, jLen, jInner,
+ nTds, nTrs, nTd, nTr, aLocalData, iThisIndex,
+ iRow, iRows, iColumn, iColumns, sNodeName,
+ oCol, oData;
+
+ /*
+ * Process by row first
+ * Add the data object for the whole table - storing the tr node. Note - no point in getting
+ * DOM based data if we are going to go and replace it with Ajax source data.
+ */
+ if ( oSettings.bDeferLoading || oSettings.sAjaxSource === null )
+ {
+ nTr = oSettings.nTBody.firstChild;
+ while ( nTr )
+ {
+ if ( nTr.nodeName.toUpperCase() == "TR" )
+ {
+ iThisIndex = oSettings.aoData.length;
+ nTr._DT_RowIndex = iThisIndex;
+ oSettings.aoData.push( $.extend( true, {}, DataTable.models.oRow, {
+ "nTr": nTr
+ } ) );
+
+ oSettings.aiDisplayMaster.push( iThisIndex );
+ nTd = nTr.firstChild;
+ jInner = 0;
+ while ( nTd )
+ {
+ sNodeName = nTd.nodeName.toUpperCase();
+ if ( sNodeName == "TD" || sNodeName == "TH" )
+ {
+ _fnSetCellData( oSettings, iThisIndex, jInner, $.trim(nTd.innerHTML) );
+ jInner++;
+ }
+ nTd = nTd.nextSibling;
+ }
+ }
+ nTr = nTr.nextSibling;
+ }
+ }
+
+ /* Gather in the TD elements of the Table - note that this is basically the same as
+ * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet
+ * setup!
+ */
+ nTrs = _fnGetTrNodes( oSettings );
+ nTds = [];
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+ {
+ nTd = nTrs[i].firstChild;
+ while ( nTd )
+ {
+ sNodeName = nTd.nodeName.toUpperCase();
+ if ( sNodeName == "TD" || sNodeName == "TH" )
+ {
+ nTds.push( nTd );
+ }
+ nTd = nTd.nextSibling;
+ }
+ }
+
+ /* Now process by column */
+ for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
+ {
+ oCol = oSettings.aoColumns[iColumn];
+
+ /* Get the title of the column - unless there is a user set one */
+ if ( oCol.sTitle === null )
+ {
+ oCol.sTitle = oCol.nTh.innerHTML;
+ }
+
+ var
+ bAutoType = oCol._bAutoType,
+ bRender = typeof oCol.fnRender === 'function',
+ bClass = oCol.sClass !== null,
+ bVisible = oCol.bVisible,
+ nCell, sThisType, sRendered, sValType;
+
+ /* A single loop to rule them all (and be more efficient) */
+ if ( bAutoType || bRender || bClass || !bVisible )
+ {
+ for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )
+ {
+ oData = oSettings.aoData[iRow];
+ nCell = nTds[ (iRow*iColumns) + iColumn ];
+
+ /* Type detection */
+ if ( bAutoType && oCol.sType != 'string' )
+ {
+ sValType = _fnGetCellData( oSettings, iRow, iColumn, 'type' );
+ if ( sValType !== '' )
+ {
+ sThisType = _fnDetectType( sValType );
+ if ( oCol.sType === null )
+ {
+ oCol.sType = sThisType;
+ }
+ else if ( oCol.sType != sThisType &&
+ oCol.sType != "html" )
+ {
+ /* String is always the 'fallback' option */
+ oCol.sType = 'string';
+ }
+ }
+ }
+
+ if ( oCol.mRender )
+ {
+ // mRender has been defined, so we need to get the value and set it
+ nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
+ }
+ else if ( oCol.mData !== iColumn )
+ {
+ // If mData is not the same as the column number, then we need to
+ // get the dev set value. If it is the column, no point in wasting
+ // time setting the value that is already there!
+ nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
+ }
+
+ /* Rendering */
+ if ( bRender )
+ {
+ sRendered = _fnRender( oSettings, iRow, iColumn );
+ nCell.innerHTML = sRendered;
+ if ( oCol.bUseRendered )
+ {
+ /* Use the rendered data for filtering / sorting */
+ _fnSetCellData( oSettings, iRow, iColumn, sRendered );
+ }
+ }
+
+ /* Classes */
+ if ( bClass )
+ {
+ nCell.className += ' '+oCol.sClass;
+ }
+
+ /* Column visibility */
+ if ( !bVisible )
+ {
+ oData._anHidden[iColumn] = nCell;
+ nCell.parentNode.removeChild( nCell );
+ }
+ else
+ {
+ oData._anHidden[iColumn] = null;
+ }
+
+ if ( oCol.fnCreatedCell )
+ {
+ oCol.fnCreatedCell.call( oSettings.oInstance,
+ nCell, _fnGetCellData( oSettings, iRow, iColumn, 'display' ), oData._aData, iRow, iColumn
+ );
+ }
+ }
+ }
+ }
+
+ /* Row created callbacks */
+ if ( oSettings.aoRowCreatedCallback.length !== 0 )
+ {
+ for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+ {
+ oData = oSettings.aoData[i];
+ _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, i] );
+ }
+ }
+ }
+
+
+ /**
+ * Take a TR element and convert it to an index in aoData
+ * @param {object} oSettings dataTables settings object
+ * @param {node} n the TR element to find
+ * @returns {int} index if the node is found, null if not
+ * @memberof DataTable#oApi
+ */
+ function _fnNodeToDataIndex( oSettings, n )
+ {
+ return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
+ }
+
+
+ /**
+ * Take a TD element and convert it into a column data index (not the visible index)
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow The row number the TD/TH can be found in
+ * @param {node} n The TD/TH element to find
+ * @returns {int} index if the node is found, -1 if not
+ * @memberof DataTable#oApi
+ */
+ function _fnNodeToColumnIndex( oSettings, iRow, n )
+ {
+ var anCells = _fnGetTdNodes( oSettings, iRow );
+
+ for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ if ( anCells[i] === n )
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+
+ /**
+ * Get an array of data for a given row from the internal data cache
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow aoData row id
+ * @param {string} sSpecific data get type ('type' 'filter' 'sort')
+ * @param {array} aiColumns Array of column indexes to get data from
+ * @returns {array} Data array
+ * @memberof DataTable#oApi
+ */
+ function _fnGetRowData( oSettings, iRow, sSpecific, aiColumns )
+ {
+ var out = [];
+ for ( var i=0, iLen=aiColumns.length ; i<iLen ; i++ )
+ {
+ out.push( _fnGetCellData( oSettings, iRow, aiColumns[i], sSpecific ) );
+ }
+ return out;
+ }
+
+
+ /**
+ * Get the data for a given cell from the internal cache, taking into account data mapping
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow aoData row id
+ * @param {int} iCol Column index
+ * @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort')
+ * @returns {*} Cell data
+ * @memberof DataTable#oApi
+ */
+ function _fnGetCellData( oSettings, iRow, iCol, sSpecific )
+ {
+ var sData;
+ var oCol = oSettings.aoColumns[iCol];
+ var oData = oSettings.aoData[iRow]._aData;
+
+ if ( (sData=oCol.fnGetData( oData, sSpecific )) === undefined )
+ {
+ if ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )
+ {
+ _fnLog( oSettings, 0, "Requested unknown parameter "+
+ (typeof oCol.mData=='function' ? '{mData function}' : "'"+oCol.mData+"'")+
+ " from the data source for row "+iRow );
+ oSettings.iDrawError = oSettings.iDraw;
+ }
+ return oCol.sDefaultContent;
+ }
+
+ /* When the data source is null, we can use default column data */
+ if ( sData === null && oCol.sDefaultContent !== null )
+ {
+ sData = oCol.sDefaultContent;
+ }
+ else if ( typeof sData === 'function' )
+ {
+ /* If the data source is a function, then we run it and use the return */
+ return sData();
+ }
+
+ if ( sSpecific == 'display' && sData === null )
+ {
+ return '';
+ }
+ return sData;
+ }
+
+
+ /**
+ * Set the value for a specific cell, into the internal data cache
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow aoData row id
+ * @param {int} iCol Column index
+ * @param {*} val Value to set
+ * @memberof DataTable#oApi
+ */
+ function _fnSetCellData( oSettings, iRow, iCol, val )
+ {
+ var oCol = oSettings.aoColumns[iCol];
+ var oData = oSettings.aoData[iRow]._aData;
+
+ oCol.fnSetData( oData, val );
+ }
+
+
+ // Private variable that is used to match array syntax in the data property object
+ var __reArray = /\[.*?\]$/;
+
+ /**
+ * Return a function that can be used to get data from a source object, taking
+ * into account the ability to use nested objects as a source
+ * @param {string|int|function} mSource The data source for the object
+ * @returns {function} Data get function
+ * @memberof DataTable#oApi
+ */
+ function _fnGetObjectDataFn( mSource )
+ {
+ if ( mSource === null )
+ {
+ /* Give an empty string for rendering / sorting etc */
+ return function (data, type) {
+ return null;
+ };
+ }
+ else if ( typeof mSource === 'function' )
+ {
+ return function (data, type, extra) {
+ return mSource( data, type, extra );
+ };
+ }
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
+ {
+ /* If there is a . in the source string then the data source is in a
+ * nested object so we loop over the data for each level to get the next
+ * level down. On each loop we test for undefined, and if found immediately
+ * return. This allows entire objects to be missing and sDefaultContent to
+ * be used if defined, rather than throwing an error
+ */
+ var fetchData = function (data, type, src) {
+ var a = src.split('.');
+ var arrayNotation, out, innerSrc;
+
+ if ( src !== "" )
+ {
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
+ {
+ // Check if we are dealing with an array notation request
+ arrayNotation = a[i].match(__reArray);
+
+ if ( arrayNotation ) {
+ a[i] = a[i].replace(__reArray, '');
+
+ // Condition allows simply [] to be passed in
+ if ( a[i] !== "" ) {
+ data = data[ a[i] ];
+ }
+ out = [];
+
+ // Get the remainder of the nested object to get
+ a.splice( 0, i+1 );
+ innerSrc = a.join('.');
+
+ // Traverse each entry in the array getting the properties requested
+ for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
+ out.push( fetchData( data[j], type, innerSrc ) );
+ }
+
+ // If a string is given in between the array notation indicators, that
+ // is used to join the strings together, otherwise an array is returned
+ var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
+ data = (join==="") ? out : out.join(join);
+
+ // The inner call to fetchData has already traversed through the remainder
+ // of the source requested, so we exit from the loop
+ break;
+ }
+
+ if ( data === null || data[ a[i] ] === undefined )
+ {
+ return undefined;
+ }
+ data = data[ a[i] ];
+ }
+ }
+
+ return data;
+ };
+
+ return function (data, type) {
+ return fetchData( data, type, mSource );
+ };
+ }
+ else
+ {
+ /* Array or flat object mapping */
+ return function (data, type) {
+ return data[mSource];
+ };
+ }
+ }
+
+
+ /**
+ * Return a function that can be used to set data from a source object, taking
+ * into account the ability to use nested objects as a source
+ * @param {string|int|function} mSource The data source for the object
+ * @returns {function} Data set function
+ * @memberof DataTable#oApi
+ */
+ function _fnSetObjectDataFn( mSource )
+ {
+ if ( mSource === null )
+ {
+ /* Nothing to do when the data source is null */
+ return function (data, val) {};
+ }
+ else if ( typeof mSource === 'function' )
+ {
+ return function (data, val) {
+ mSource( data, 'set', val );
+ };
+ }
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
+ {
+ /* Like the get, we need to get data from a nested object */
+ var setData = function (data, val, src) {
+ var a = src.split('.'), b;
+ var arrayNotation, o, innerSrc;
+
+ for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
+ {
+ // Check if we are dealing with an array notation request
+ arrayNotation = a[i].match(__reArray);
+
+ if ( arrayNotation )
+ {
+ a[i] = a[i].replace(__reArray, '');
+ data[ a[i] ] = [];
+
+ // Get the remainder of the nested object to set so we can recurse
+ b = a.slice();
+ b.splice( 0, i+1 );
+ innerSrc = b.join('.');
+
+ // Traverse each entry in the array setting the properties requested
+ for ( var j=0, jLen=val.length ; j<jLen ; j++ )
+ {
+ o = {};
+ setData( o, val[j], innerSrc );
+ data[ a[i] ].push( o );
+ }
+
+ // The inner call to setData has already traversed through the remainder
+ // of the source and has set the data, thus we can exit here
+ return;
+ }
+
+ // If the nested object doesn't currently exist - since we are
+ // trying to set the value - create it
+ if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
+ {
+ data[ a[i] ] = {};
+ }
+ data = data[ a[i] ];
+ }
+
+ // If array notation is used, we just want to strip it and use the property name
+ // and assign the value. If it isn't used, then we get the result we want anyway
+ data[ a[a.length-1].replace(__reArray, '') ] = val;
+ };
+
+ return function (data, val) {
+ return setData( data, val, mSource );
+ };
+ }
+ else
+ {
+ /* Array or flat object mapping */
+ return function (data, val) {
+ data[mSource] = val;
+ };
+ }
+ }
+
+
+ /**
+ * Return an array with the full table data
+ * @param {object} oSettings dataTables settings object
+ * @returns array {array} aData Master data array
+ * @memberof DataTable#oApi
+ */
+ function _fnGetDataMaster ( oSettings )
+ {
+ var aData = [];
+ var iLen = oSettings.aoData.length;
+ for ( var i=0 ; i<iLen; i++ )
+ {
+ aData.push( oSettings.aoData[i]._aData );
+ }
+ return aData;
+ }
+
+
+ /**
+ * Nuke the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnClearTable( oSettings )
+ {
+ oSettings.aoData.splice( 0, oSettings.aoData.length );
+ oSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length );
+ oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length );
+ _fnCalculateEnd( oSettings );
+ }
+
+
+ /**
+ * Take an array of integers (index array) and remove a target integer (value - not
+ * the key!)
+ * @param {array} a Index array to target
+ * @param {int} iTarget value to find
+ * @memberof DataTable#oApi
+ */
+ function _fnDeleteIndex( a, iTarget )
+ {
+ var iTargetIndex = -1;
+
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
+ {
+ if ( a[i] == iTarget )
+ {
+ iTargetIndex = i;
+ }
+ else if ( a[i] > iTarget )
+ {
+ a[i]--;
+ }
+ }
+
+ if ( iTargetIndex != -1 )
+ {
+ a.splice( iTargetIndex, 1 );
+ }
+ }
+
+
+ /**
+ * Call the developer defined fnRender function for a given cell (row/column) with
+ * the required parameters and return the result.
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow aoData index for the row
+ * @param {int} iCol aoColumns index for the column
+ * @returns {*} Return of the developer's fnRender function
+ * @memberof DataTable#oApi
+ */
+ function _fnRender( oSettings, iRow, iCol )
+ {
+ var oCol = oSettings.aoColumns[iCol];
+
+ return oCol.fnRender( {
+ "iDataRow": iRow,
+ "iDataColumn": iCol,
+ "oSettings": oSettings,
+ "aData": oSettings.aoData[iRow]._aData,
+ "mDataProp": oCol.mData
+ }, _fnGetCellData(oSettings, iRow, iCol, 'display') );
+ }
+ /**
+ * Create a new TR element (and it's TD children) for a row
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow Row to consider
+ * @memberof DataTable#oApi
+ */
+ function _fnCreateTr ( oSettings, iRow )
+ {
+ var oData = oSettings.aoData[iRow];
+ var nTd;
+
+ if ( oData.nTr === null )
+ {
+ oData.nTr = document.createElement('tr');
+
+ /* Use a private property on the node to allow reserve mapping from the node
+ * to the aoData array for fast look up
+ */
+ oData.nTr._DT_RowIndex = iRow;
+
+ /* Special parameters can be given by the data source to be used on the row */
+ if ( oData._aData.DT_RowId )
+ {
+ oData.nTr.id = oData._aData.DT_RowId;
+ }
+
+ if ( oData._aData.DT_RowClass )
+ {
+ oData.nTr.className = oData._aData.DT_RowClass;
+ }
+
+ /* Process each column */
+ for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ var oCol = oSettings.aoColumns[i];
+ nTd = document.createElement( oCol.sCellType );
+
+ /* Render if needed - if bUseRendered is true then we already have the rendered
+ * value in the data source - so can just use that
+ */
+ nTd.innerHTML = (typeof oCol.fnRender === 'function' && (!oCol.bUseRendered || oCol.mData === null)) ?
+ _fnRender( oSettings, iRow, i ) :
+ _fnGetCellData( oSettings, iRow, i, 'display' );
+
+ /* Add user defined class */
+ if ( oCol.sClass !== null )
+ {
+ nTd.className = oCol.sClass;
+ }
+
+ if ( oCol.bVisible )
+ {
+ oData.nTr.appendChild( nTd );
+ oData._anHidden[i] = null;
+ }
+ else
+ {
+ oData._anHidden[i] = nTd;
+ }
+
+ if ( oCol.fnCreatedCell )
+ {
+ oCol.fnCreatedCell.call( oSettings.oInstance,
+ nTd, _fnGetCellData( oSettings, iRow, i, 'display' ), oData._aData, iRow, i
+ );
+ }
+ }
+
+ _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, iRow] );
+ }
+ }
+
+
+ /**
+ * Create the HTML header for the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnBuildHead( oSettings )
+ {
+ var i, nTh, iLen, j, jLen;
+ var iThs = $('th, td', oSettings.nTHead).length;
+ var iCorrector = 0;
+ var jqChildren;
+
+ /* If there is a header in place - then use it - otherwise it's going to get nuked... */
+ if ( iThs !== 0 )
+ {
+ /* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ nTh = oSettings.aoColumns[i].nTh;
+ nTh.setAttribute('role', 'columnheader');
+ if ( oSettings.aoColumns[i].bSortable )
+ {
+ nTh.setAttribute('tabindex', oSettings.iTabIndex);
+ nTh.setAttribute('aria-controls', oSettings.sTableId);
+ }
+
+ if ( oSettings.aoColumns[i].sClass !== null )
+ {
+ $(nTh).addClass( oSettings.aoColumns[i].sClass );
+ }
+
+ /* Set the title of the column if it is user defined (not what was auto detected) */
+ if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML )
+ {
+ nTh.innerHTML = oSettings.aoColumns[i].sTitle;
+ }
+ }
+ }
+ else
+ {
+ /* We don't have a header in the DOM - so we are going to have to create one */
+ var nTr = document.createElement( "tr" );
+
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ nTh = oSettings.aoColumns[i].nTh;
+ nTh.innerHTML = oSettings.aoColumns[i].sTitle;
+ nTh.setAttribute('tabindex', '0');
+
+ if ( oSettings.aoColumns[i].sClass !== null )
+ {
+ $(nTh).addClass( oSettings.aoColumns[i].sClass );
+ }
+
+ nTr.appendChild( nTh );
+ }
+ $(oSettings.nTHead).html( '' )[0].appendChild( nTr );
+ _fnDetectHeader( oSettings.aoHeader, oSettings.nTHead );
+ }
+
+ /* ARIA role for the rows */
+ $(oSettings.nTHead).children('tr').attr('role', 'row');
+
+ /* Add the extra markup needed by jQuery UI's themes */
+ if ( oSettings.bJUI )
+ {
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ nTh = oSettings.aoColumns[i].nTh;
+
+ var nDiv = document.createElement('div');
+ nDiv.className = oSettings.oClasses.sSortJUIWrapper;
+ $(nTh).contents().appendTo(nDiv);
+
+ var nSpan = document.createElement('span');
+ nSpan.className = oSettings.oClasses.sSortIcon;
+ nDiv.appendChild( nSpan );
+ nTh.appendChild( nDiv );
+ }
+ }
+
+ if ( oSettings.oFeatures.bSort )
+ {
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bSortable !== false )
+ {
+ _fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
+ }
+ else
+ {
+ $(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone );
+ }
+ }
+ }
+
+ /* Deal with the footer - add classes if required */
+ if ( oSettings.oClasses.sFooterTH !== "" )
+ {
+ $(oSettings.nTFoot).children('tr').children('th').addClass( oSettings.oClasses.sFooterTH );
+ }
+
+ /* Cache the footer elements */
+ if ( oSettings.nTFoot !== null )
+ {
+ var anCells = _fnGetUniqueThs( oSettings, null, oSettings.aoFooter );
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ if ( anCells[i] )
+ {
+ oSettings.aoColumns[i].nTf = anCells[i];
+ if ( oSettings.aoColumns[i].sClass )
+ {
+ $(anCells[i]).addClass( oSettings.aoColumns[i].sClass );
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Draw the header (or footer) element based on the column visibility states. The
+ * methodology here is to use the layout array from _fnDetectHeader, modified for
+ * the instantaneous column visibility, to construct the new layout. The grid is
+ * traversed over cell at a time in a rows x columns grid fashion, although each
+ * cell insert can cover multiple elements in the grid - which is tracks using the
+ * aApplied array. Cell inserts in the grid will only occur where there isn't
+ * already a cell in that position.
+ * @param {object} oSettings dataTables settings object
+ * @param array {objects} aoSource Layout array from _fnDetectHeader
+ * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
+ * @memberof DataTable#oApi
+ */
+ function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
+ {
+ var i, iLen, j, jLen, k, kLen, n, nLocalTr;
+ var aoLocal = [];
+ var aApplied = [];
+ var iColumns = oSettings.aoColumns.length;
+ var iRowspan, iColspan;
+
+ if ( bIncludeHidden === undefined )
+ {
+ bIncludeHidden = false;
+ }
+
+ /* Make a copy of the master layout array, but without the visible columns in it */
+ for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
+ {
+ aoLocal[i] = aoSource[i].slice();
+ aoLocal[i].nTr = aoSource[i].nTr;
+
+ /* Remove any columns which are currently hidden */
+ for ( j=iColumns-1 ; j>=0 ; j-- )
+ {
+ if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
+ {
+ aoLocal[i].splice( j, 1 );
+ }
+ }
+
+ /* Prep the applied array - it needs an element for each row */
+ aApplied.push( [] );
+ }
+
+ for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
+ {
+ nLocalTr = aoLocal[i].nTr;
+
+ /* All cells are going to be replaced, so empty out the row */
+ if ( nLocalTr )
+ {
+ while( (n = nLocalTr.firstChild) )
+ {
+ nLocalTr.removeChild( n );
+ }
+ }
+
+ for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
+ {
+ iRowspan = 1;
+ iColspan = 1;
+
+ /* Check to see if there is already a cell (row/colspan) covering our target
+ * insert point. If there is, then there is nothing to do.
+ */
+ if ( aApplied[i][j] === undefined )
+ {
+ nLocalTr.appendChild( aoLocal[i][j].cell );
+ aApplied[i][j] = 1;
+
+ /* Expand the cell to cover as many rows as needed */
+ while ( aoLocal[i+iRowspan] !== undefined &&
+ aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
+ {
+ aApplied[i+iRowspan][j] = 1;
+ iRowspan++;
+ }
+
+ /* Expand the cell to cover as many columns as needed */
+ while ( aoLocal[i][j+iColspan] !== undefined &&
+ aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
+ {
+ /* Must update the applied array over the rows for the columns */
+ for ( k=0 ; k<iRowspan ; k++ )
+ {
+ aApplied[i+k][j+iColspan] = 1;
+ }
+ iColspan++;
+ }
+
+ /* Do the actual expansion in the DOM */
+ aoLocal[i][j].cell.rowSpan = iRowspan;
+ aoLocal[i][j].cell.colSpan = iColspan;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Insert the required TR nodes into the table for display
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnDraw( oSettings )
+ {
+ /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
+ var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
+ if ( $.inArray( false, aPreDraw ) !== -1 )
+ {
+ _fnProcessingDisplay( oSettings, false );
+ return;
+ }
+
+ var i, iLen, n;
+ var anRows = [];
+ var iRowCount = 0;
+ var iStripes = oSettings.asStripeClasses.length;
+ var iOpenRows = oSettings.aoOpenRows.length;
+
+ oSettings.bDrawing = true;
+
+ /* Check and see if we have an initial draw position from state saving */
+ if ( oSettings.iInitDisplayStart !== undefined && oSettings.iInitDisplayStart != -1 )
+ {
+ if ( oSettings.oFeatures.bServerSide )
+ {
+ oSettings._iDisplayStart = oSettings.iInitDisplayStart;
+ }
+ else
+ {
+ oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ?
+ 0 : oSettings.iInitDisplayStart;
+ }
+ oSettings.iInitDisplayStart = -1;
+ _fnCalculateEnd( oSettings );
+ }
+
+ /* Server-side processing draw intercept */
+ if ( oSettings.bDeferLoading )
+ {
+ oSettings.bDeferLoading = false;
+ oSettings.iDraw++;
+ }
+ else if ( !oSettings.oFeatures.bServerSide )
+ {
+ oSettings.iDraw++;
+ }
+ else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
+ {
+ return;
+ }
+
+ if ( oSettings.aiDisplay.length !== 0 )
+ {
+ var iStart = oSettings._iDisplayStart;
+ var iEnd = oSettings._iDisplayEnd;
+
+ if ( oSettings.oFeatures.bServerSide )
+ {
+ iStart = 0;
+ iEnd = oSettings.aoData.length;
+ }
+
+ for ( var j=iStart ; j<iEnd ; j++ )
+ {
+ var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ];
+ if ( aoData.nTr === null )
+ {
+ _fnCreateTr( oSettings, oSettings.aiDisplay[j] );
+ }
+
+ var nRow = aoData.nTr;
+
+ /* Remove the old striping classes and then add the new one */
+ if ( iStripes !== 0 )
+ {
+ var sStripe = oSettings.asStripeClasses[ iRowCount % iStripes ];
+ if ( aoData._sRowStripe != sStripe )
+ {
+ $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
+ aoData._sRowStripe = sStripe;
+ }
+ }
+
+ /* Row callback functions - might want to manipulate the row */
+ _fnCallbackFire( oSettings, 'aoRowCallback', null,
+ [nRow, oSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j] );
+
+ anRows.push( nRow );
+ iRowCount++;
+
+ /* If there is an open row - and it is attached to this parent - attach it on redraw */
+ if ( iOpenRows !== 0 )
+ {
+ for ( var k=0 ; k<iOpenRows ; k++ )
+ {
+ if ( nRow == oSettings.aoOpenRows[k].nParent )
+ {
+ anRows.push( oSettings.aoOpenRows[k].nTr );
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Table is empty - create a row with an empty message in it */
+ anRows[ 0 ] = document.createElement( 'tr' );
+
+ if ( oSettings.asStripeClasses[0] )
+ {
+ anRows[ 0 ].className = oSettings.asStripeClasses[0];
+ }
+
+ var oLang = oSettings.oLanguage;
+ var sZero = oLang.sZeroRecords;
+ if ( oSettings.iDraw == 1 && oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
+ {
+ sZero = oLang.sLoadingRecords;
+ }
+ else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
+ {
+ sZero = oLang.sEmptyTable;
+ }
+
+ var nTd = document.createElement( 'td' );
+ nTd.setAttribute( 'valign', "top" );
+ nTd.colSpan = _fnVisbleColumns( oSettings );
+ nTd.className = oSettings.oClasses.sRowEmpty;
+ nTd.innerHTML = _fnInfoMacros( oSettings, sZero );
+
+ anRows[ iRowCount ].appendChild( nTd );
+ }
+
+ /* Header and footer callbacks */
+ _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
+ _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
+
+ _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
+ _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
+
+ /*
+ * Need to remove any old row from the display - note we can't just empty the tbody using
+ * $().html('') since this will unbind the jQuery event handlers (even although the node
+ * still exists!) - equally we can't use innerHTML, since IE throws an exception.
+ */
+ var
+ nAddFrag = document.createDocumentFragment(),
+ nRemoveFrag = document.createDocumentFragment(),
+ nBodyPar, nTrs;
+
+ if ( oSettings.nTBody )
+ {
+ nBodyPar = oSettings.nTBody.parentNode;
+ nRemoveFrag.appendChild( oSettings.nTBody );
+
+ /* When doing infinite scrolling, only remove child rows when sorting, filtering or start
+ * up. When not infinite scroll, always do it.
+ */
+ if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete ||
+ oSettings.bSorted || oSettings.bFiltered )
+ {
+ while( (n = oSettings.nTBody.firstChild) )
+ {
+ oSettings.nTBody.removeChild( n );
+ }
+ }
+
+ /* Put the draw table into the dom */
+ for ( i=0, iLen=anRows.length ; i<iLen ; i++ )
+ {
+ nAddFrag.appendChild( anRows[i] );
+ }
+
+ oSettings.nTBody.appendChild( nAddFrag );
+ if ( nBodyPar !== null )
+ {
+ nBodyPar.appendChild( oSettings.nTBody );
+ }
+ }
+
+ /* Call all required callback functions for the end of a draw */
+ _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
+
+ /* Draw is complete, sorting and filtering must be as well */
+ oSettings.bSorted = false;
+ oSettings.bFiltered = false;
+ oSettings.bDrawing = false;
+
+ if ( oSettings.oFeatures.bServerSide )
+ {
+ _fnProcessingDisplay( oSettings, false );
+ if ( !oSettings._bInitComplete )
+ {
+ _fnInitComplete( oSettings );
+ }
+ }
+ }
+
+
+ /**
+ * Redraw the table - taking account of the various features which are enabled
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnReDraw( oSettings )
+ {
+ if ( oSettings.oFeatures.bSort )
+ {
+ /* Sorting will refilter and draw for us */
+ _fnSort( oSettings, oSettings.oPreviousSearch );
+ }
+ else if ( oSettings.oFeatures.bFilter )
+ {
+ /* Filtering will redraw for us */
+ _fnFilterComplete( oSettings, oSettings.oPreviousSearch );
+ }
+ else
+ {
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+ }
+
+
+ /**
+ * Add the options to the page HTML for the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnAddOptionsHtml ( oSettings )
+ {
+ /*
+ * Create a temporary, empty, div which we can later on replace with what we have generated
+ * we do it this way to rendering the 'options' html offline - speed :-)
+ */
+ var nHolding = $('<div></div>')[0];
+ oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );
+
+ /*
+ * All DataTables are wrapped in a div
+ */
+ oSettings.nTableWrapper = $('<div id="'+oSettings.sTableId+'_wrapper" class="'+oSettings.oClasses.sWrapper+'" role="grid"></div>')[0];
+ oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
+
+ /* Track where we want to insert the option */
+ var nInsertNode = oSettings.nTableWrapper;
+
+ /* Loop over the user set positioning and place the elements as needed */
+ var aDom = oSettings.sDom.split('');
+ var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;
+ for ( var i=0 ; i<aDom.length ; i++ )
+ {
+ iPushFeature = 0;
+ cOption = aDom[i];
+
+ if ( cOption == '<' )
+ {
+ /* New container div */
+ nNewNode = $('<div></div>')[0];
+
+ /* Check to see if we should append an id and/or a class name to the container */
+ cNext = aDom[i+1];
+ if ( cNext == "'" || cNext == '"' )
+ {
+ sAttr = "";
+ j = 2;
+ while ( aDom[i+j] != cNext )
+ {
+ sAttr += aDom[i+j];
+ j++;
+ }
+
+ /* Replace jQuery UI constants */
+ if ( sAttr == "H" )
+ {
+ sAttr = oSettings.oClasses.sJUIHeader;
+ }
+ else if ( sAttr == "F" )
+ {
+ sAttr = oSettings.oClasses.sJUIFooter;
+ }
+
+ /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
+ * breaks the string into parts and applies them as needed
+ */
+ if ( sAttr.indexOf('.') != -1 )
+ {
+ var aSplit = sAttr.split('.');
+ nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
+ nNewNode.className = aSplit[1];
+ }
+ else if ( sAttr.charAt(0) == "#" )
+ {
+ nNewNode.id = sAttr.substr(1, sAttr.length-1);
+ }
+ else
+ {
+ nNewNode.className = sAttr;
+ }
+
+ i += j; /* Move along the position array */
+ }
+
+ nInsertNode.appendChild( nNewNode );
+ nInsertNode = nNewNode;
+ }
+ else if ( cOption == '>' )
+ {
+ /* End container div */
+ nInsertNode = nInsertNode.parentNode;
+ }
+ else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )
+ {
+ /* Length */
+ nTmp = _fnFeatureHtmlLength( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 'f' && oSettings.oFeatures.bFilter )
+ {
+ /* Filter */
+ nTmp = _fnFeatureHtmlFilter( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )
+ {
+ /* pRocessing */
+ nTmp = _fnFeatureHtmlProcessing( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 't' )
+ {
+ /* Table */
+ nTmp = _fnFeatureHtmlTable( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 'i' && oSettings.oFeatures.bInfo )
+ {
+ /* Info */
+ nTmp = _fnFeatureHtmlInfo( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )
+ {
+ /* Pagination */
+ nTmp = _fnFeatureHtmlPaginate( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( DataTable.ext.aoFeatures.length !== 0 )
+ {
+ /* Plug-in features */
+ var aoFeatures = DataTable.ext.aoFeatures;
+ for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
+ {
+ if ( cOption == aoFeatures[k].cFeature )
+ {
+ nTmp = aoFeatures[k].fnInit( oSettings );
+ if ( nTmp )
+ {
+ iPushFeature = 1;
+ }
+ break;
+ }
+ }
+ }
+
+ /* Add to the 2D features array */
+ if ( iPushFeature == 1 && nTmp !== null )
+ {
+ if ( typeof oSettings.aanFeatures[cOption] !== 'object' )
+ {
+ oSettings.aanFeatures[cOption] = [];
+ }
+ oSettings.aanFeatures[cOption].push( nTmp );
+ nInsertNode.appendChild( nTmp );
+ }
+ }
+
+ /* Built our DOM structure - replace the holding div with what we want */
+ nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );
+ }
+
+
+ /**
+ * Use the DOM source to create up an array of header cells. The idea here is to
+ * create a layout grid (array) of rows x columns, which contains a reference
+ * to the cell that that point in the grid (regardless of col/rowspan), such that
+ * any column / row could be removed and the new grid constructed
+ * @param array {object} aLayout Array to store the calculated layout in
+ * @param {node} nThead The header/footer element for the table
+ * @memberof DataTable#oApi
+ */
+ function _fnDetectHeader ( aLayout, nThead )
+ {
+ var nTrs = $(nThead).children('tr');
+ var nTr, nCell;
+ var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
+ var bUnique;
+ var fnShiftCol = function ( a, i, j ) {
+ var k = a[i];
+ while ( k[j] ) {
+ j++;
+ }
+ return j;
+ };
+
+ aLayout.splice( 0, aLayout.length );
+
+ /* We know how many rows there are in the layout - so prep it */
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+ {
+ aLayout.push( [] );
+ }
+
+ /* Calculate a layout array */
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+ {
+ nTr = nTrs[i];
+ iColumn = 0;
+
+ /* For every cell in the row... */
+ nCell = nTr.firstChild;
+ while ( nCell ) {
+ if ( nCell.nodeName.toUpperCase() == "TD" ||
+ nCell.nodeName.toUpperCase() == "TH" )
+ {
+ /* Get the col and rowspan attributes from the DOM and sanitise them */
+ iColspan = nCell.getAttribute('colspan') * 1;
+ iRowspan = nCell.getAttribute('rowspan') * 1;
+ iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
+ iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
+
+ /* There might be colspan cells already in this row, so shift our target
+ * accordingly
+ */
+ iColShifted = fnShiftCol( aLayout, i, iColumn );
+
+ /* Cache calculation for unique columns */
+ bUnique = iColspan === 1 ? true : false;
+
+ /* If there is col / rowspan, copy the information into the layout grid */
+ for ( l=0 ; l<iColspan ; l++ )
+ {
+ for ( k=0 ; k<iRowspan ; k++ )
+ {
+ aLayout[i+k][iColShifted+l] = {
+ "cell": nCell,
+ "unique": bUnique
+ };
+ aLayout[i+k].nTr = nTr;
+ }
+ }
+ }
+ nCell = nCell.nextSibling;
+ }
+ }
+ }
+
+
+ /**
+ * Get an array of unique th elements, one for each column
+ * @param {object} oSettings dataTables settings object
+ * @param {node} nHeader automatically detect the layout from this node - optional
+ * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
+ * @returns array {node} aReturn list of unique th's
+ * @memberof DataTable#oApi
+ */
+ function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
+ {
+ var aReturn = [];
+ if ( !aLayout )
+ {
+ aLayout = oSettings.aoHeader;
+ if ( nHeader )
+ {
+ aLayout = [];
+ _fnDetectHeader( aLayout, nHeader );
+ }
+ }
+
+ for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
+ {
+ for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
+ {
+ if ( aLayout[i][j].unique &&
+ (!aReturn[j] || !oSettings.bSortCellsTop) )
+ {
+ aReturn[j] = aLayout[i][j].cell;
+ }
+ }
+ }
+
+ return aReturn;
+ }
+
+
+
+ /**
+ * Update the table using an Ajax call
+ * @param {object} oSettings dataTables settings object
+ * @returns {boolean} Block the table drawing or not
+ * @memberof DataTable#oApi
+ */
+ function _fnAjaxUpdate( oSettings )
+ {
+ if ( oSettings.bAjaxDataGet )
+ {
+ oSettings.iDraw++;
+ _fnProcessingDisplay( oSettings, true );
+ var iColumns = oSettings.aoColumns.length;
+ var aoData = _fnAjaxParameters( oSettings );
+ _fnServerParams( oSettings, aoData );
+
+ oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData,
+ function(json) {
+ _fnAjaxUpdateDraw( oSettings, json );
+ }, oSettings );
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+
+ /**
+ * Build up the parameters in an object needed for a server-side processing request
+ * @param {object} oSettings dataTables settings object
+ * @returns {bool} block the table drawing or not
+ * @memberof DataTable#oApi
+ */
+ function _fnAjaxParameters( oSettings )
+ {
+ var iColumns = oSettings.aoColumns.length;
+ var aoData = [], mDataProp, aaSort, aDataSort;
+ var i, j;
+
+ aoData.push( { "name": "sEcho", "value": oSettings.iDraw } );
+ aoData.push( { "name": "iColumns", "value": iColumns } );
+ aoData.push( { "name": "sColumns", "value": _fnColumnOrdering(oSettings) } );
+ aoData.push( { "name": "iDisplayStart", "value": oSettings._iDisplayStart } );
+ aoData.push( { "name": "iDisplayLength", "value": oSettings.oFeatures.bPaginate !== false ?
+ oSettings._iDisplayLength : -1 } );
+
+ for ( i=0 ; i<iColumns ; i++ )
+ {
+ mDataProp = oSettings.aoColumns[i].mData;
+ aoData.push( { "name": "mDataProp_"+i, "value": typeof(mDataProp)==="function" ? 'function' : mDataProp } );
+ }
+
+ /* Filtering */
+ if ( oSettings.oFeatures.bFilter !== false )
+ {
+ aoData.push( { "name": "sSearch", "value": oSettings.oPreviousSearch.sSearch } );
+ aoData.push( { "name": "bRegex", "value": oSettings.oPreviousSearch.bRegex } );
+ for ( i=0 ; i<iColumns ; i++ )
+ {
+ aoData.push( { "name": "sSearch_"+i, "value": oSettings.aoPreSearchCols[i].sSearch } );
+ aoData.push( { "name": "bRegex_"+i, "value": oSettings.aoPreSearchCols[i].bRegex } );
+ aoData.push( { "name": "bSearchable_"+i, "value": oSettings.aoColumns[i].bSearchable } );
+ }
+ }
+
+ /* Sorting */
+ if ( oSettings.oFeatures.bSort !== false )
+ {
+ var iCounter = 0;
+
+ aaSort = ( oSettings.aaSortingFixed !== null ) ?
+ oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :
+ oSettings.aaSorting.slice();
+
+ for ( i=0 ; i<aaSort.length ; i++ )
+ {
+ aDataSort = oSettings.aoColumns[ aaSort[i][0] ].aDataSort;
+
+ for ( j=0 ; j<aDataSort.length ; j++ )
+ {
+ aoData.push( { "name": "iSortCol_"+iCounter, "value": aDataSort[j] } );
+ aoData.push( { "name": "sSortDir_"+iCounter, "value": aaSort[i][1] } );
+ iCounter++;
+ }
+ }
+ aoData.push( { "name": "iSortingCols", "value": iCounter } );
+
+ for ( i=0 ; i<iColumns ; i++ )
+ {
+ aoData.push( { "name": "bSortable_"+i, "value": oSettings.aoColumns[i].bSortable } );
+ }
+ }
+
+ return aoData;
+ }
+
+
+ /**
+ * Add Ajax parameters from plug-ins
+ * @param {object} oSettings dataTables settings object
+ * @param array {objects} aoData name/value pairs to send to the server
+ * @memberof DataTable#oApi
+ */
+ function _fnServerParams( oSettings, aoData )
+ {
+ _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [aoData] );
+ }
+
+
+ /**
+ * Data the data from the server (nuking the old) and redraw the table
+ * @param {object} oSettings dataTables settings object
+ * @param {object} json json data return from the server.
+ * @param {string} json.sEcho Tracking flag for DataTables to match requests
+ * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
+ * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
+ * @param {array} json.aaData The data to display on this page
+ * @param {string} [json.sColumns] Column ordering (sName, comma separated)
+ * @memberof DataTable#oApi
+ */
+ function _fnAjaxUpdateDraw ( oSettings, json )
+ {
+ if ( json.sEcho !== undefined )
+ {
+ /* Protect against old returns over-writing a new one. Possible when you get
+ * very fast interaction, and later queries are completed much faster
+ */
+ if ( json.sEcho*1 < oSettings.iDraw )
+ {
+ return;
+ }
+ else
+ {
+ oSettings.iDraw = json.sEcho * 1;
+ }
+ }
+
+ if ( !oSettings.oScroll.bInfinite ||
+ (oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered)) )
+ {
+ _fnClearTable( oSettings );
+ }
+ oSettings._iRecordsTotal = parseInt(json.iTotalRecords, 10);
+ oSettings._iRecordsDisplay = parseInt(json.iTotalDisplayRecords, 10);
+
+ /* Determine if reordering is required */
+ var sOrdering = _fnColumnOrdering(oSettings);
+ var bReOrder = (json.sColumns !== undefined && sOrdering !== "" && json.sColumns != sOrdering );
+ var aiIndex;
+ if ( bReOrder )
+ {
+ aiIndex = _fnReOrderIndex( oSettings, json.sColumns );
+ }
+
+ var aData = _fnGetObjectDataFn( oSettings.sAjaxDataProp )( json );
+ for ( var i=0, iLen=aData.length ; i<iLen ; i++ )
+ {
+ if ( bReOrder )
+ {
+ /* If we need to re-order, then create a new array with the correct order and add it */
+ var aDataSorted = [];
+ for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
+ {
+ aDataSorted.push( aData[i][ aiIndex[j] ] );
+ }
+ _fnAddData( oSettings, aDataSorted );
+ }
+ else
+ {
+ /* No re-order required, sever got it "right" - just straight add */
+ _fnAddData( oSettings, aData[i] );
+ }
+ }
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+
+ oSettings.bAjaxDataGet = false;
+ _fnDraw( oSettings );
+ oSettings.bAjaxDataGet = true;
+ _fnProcessingDisplay( oSettings, false );
+ }
+
+
+
+ /**
+ * Generate the node required for filtering text
+ * @returns {node} Filter control element
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlFilter ( oSettings )
+ {
+ var oPreviousSearch = oSettings.oPreviousSearch;
+
+ var sSearchStr = oSettings.oLanguage.sSearch;
+ sSearchStr = (sSearchStr.indexOf('_INPUT_') !== -1) ?
+ sSearchStr.replace('_INPUT_', '<input type="text" />') :
+ sSearchStr==="" ? '<input type="text" />' : sSearchStr+' <input type="text" />';
+
+ var nFilter = document.createElement( 'div' );
+ nFilter.className = oSettings.oClasses.sFilter;
+ nFilter.innerHTML = '<label>'+sSearchStr+'</label>';
+ if ( !oSettings.aanFeatures.f )
+ {
+ nFilter.id = oSettings.sTableId+'_filter';
+ }
+
+ var jqFilter = $('input[type="text"]', nFilter);
+
+ // Store a reference to the input element, so other input elements could be
+ // added to the filter wrapper if needed (submit button for example)
+ nFilter._DT_Input = jqFilter[0];
+
+ jqFilter.val( oPreviousSearch.sSearch.replace('"','&quot;') );
+ jqFilter.bind( 'keyup.DT', function(e) {
+ /* Update all other filter input elements for the new display */
+ var n = oSettings.aanFeatures.f;
+ var val = this.value==="" ? "" : this.value; // mental IE8 fix :-(
+
+ for ( var i=0, iLen=n.length ; i<iLen ; i++ )
+ {
+ if ( n[i] != $(this).parents('div.dataTables_filter')[0] )
+ {
+ $(n[i]._DT_Input).val( val );
+ }
+ }
+
+ /* Now do the filter */
+ if ( val != oPreviousSearch.sSearch )
+ {
+ _fnFilterComplete( oSettings, {
+ "sSearch": val,
+ "bRegex": oPreviousSearch.bRegex,
+ "bSmart": oPreviousSearch.bSmart ,
+ "bCaseInsensitive": oPreviousSearch.bCaseInsensitive
+ } );
+ }
+ } );
+
+ jqFilter
+ .attr('aria-controls', oSettings.sTableId)
+ .bind( 'keypress.DT', function(e) {
+ /* Prevent form submission */
+ if ( e.keyCode == 13 )
+ {
+ return false;
+ }
+ }
+ );
+
+ return nFilter;
+ }
+
+
+ /**
+ * Filter the table using both the global filter and column based filtering
+ * @param {object} oSettings dataTables settings object
+ * @param {object} oSearch search information
+ * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
+ * @memberof DataTable#oApi
+ */
+ function _fnFilterComplete ( oSettings, oInput, iForce )
+ {
+ var oPrevSearch = oSettings.oPreviousSearch;
+ var aoPrevSearch = oSettings.aoPreSearchCols;
+ var fnSaveFilter = function ( oFilter ) {
+ /* Save the filtering values */
+ oPrevSearch.sSearch = oFilter.sSearch;
+ oPrevSearch.bRegex = oFilter.bRegex;
+ oPrevSearch.bSmart = oFilter.bSmart;
+ oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
+ };
+
+ /* In server-side processing all filtering is done by the server, so no point hanging around here */
+ if ( !oSettings.oFeatures.bServerSide )
+ {
+ /* Global filter */
+ _fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart, oInput.bCaseInsensitive );
+ fnSaveFilter( oInput );
+
+ /* Now do the individual column filter */
+ for ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )
+ {
+ _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, aoPrevSearch[i].bRegex,
+ aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
+ }
+
+ /* Custom filtering */
+ _fnFilterCustom( oSettings );
+ }
+ else
+ {
+ fnSaveFilter( oInput );
+ }
+
+ /* Tell the draw function we have been filtering */
+ oSettings.bFiltered = true;
+ $(oSettings.oInstance).trigger('filter', oSettings);
+
+ /* Redraw the table */
+ oSettings._iDisplayStart = 0;
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+
+ /* Rebuild search array 'offline' */
+ _fnBuildSearchArray( oSettings, 0 );
+ }
+
+
+ /**
+ * Apply custom filtering functions
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnFilterCustom( oSettings )
+ {
+ var afnFilters = DataTable.ext.afnFiltering;
+ var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );
+
+ for ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )
+ {
+ var iCorrector = 0;
+ for ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )
+ {
+ var iDisIndex = oSettings.aiDisplay[j-iCorrector];
+ var bTest = afnFilters[i](
+ oSettings,
+ _fnGetRowData( oSettings, iDisIndex, 'filter', aiFilterColumns ),
+ iDisIndex
+ );
+
+ /* Check if we should use this row based on the filtering function */
+ if ( !bTest )
+ {
+ oSettings.aiDisplay.splice( j-iCorrector, 1 );
+ iCorrector++;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Filter the table on a per-column basis
+ * @param {object} oSettings dataTables settings object
+ * @param {string} sInput string to filter on
+ * @param {int} iColumn column to filter
+ * @param {bool} bRegex treat search string as a regular expression or not
+ * @param {bool} bSmart use smart filtering or not
+ * @param {bool} bCaseInsensitive Do case insenstive matching or not
+ * @memberof DataTable#oApi
+ */
+ function _fnFilterColumn ( oSettings, sInput, iColumn, bRegex, bSmart, bCaseInsensitive )
+ {
+ if ( sInput === "" )
+ {
+ return;
+ }
+
+ var iIndexCorrector = 0;
+ var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
+
+ for ( var i=oSettings.aiDisplay.length-1 ; i>=0 ; i-- )
+ {
+ var sData = _fnDataToSearch( _fnGetCellData( oSettings, oSettings.aiDisplay[i], iColumn, 'filter' ),
+ oSettings.aoColumns[iColumn].sType );
+ if ( ! rpSearch.test( sData ) )
+ {
+ oSettings.aiDisplay.splice( i, 1 );
+ iIndexCorrector++;
+ }
+ }
+ }
+
+
+ /**
+ * Filter the data table based on user input and draw the table
+ * @param {object} oSettings dataTables settings object
+ * @param {string} sInput string to filter on
+ * @param {int} iForce optional - force a research of the master array (1) or not (undefined or 0)
+ * @param {bool} bRegex treat as a regular expression or not
+ * @param {bool} bSmart perform smart filtering or not
+ * @param {bool} bCaseInsensitive Do case insenstive matching or not
+ * @memberof DataTable#oApi
+ */
+ function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart, bCaseInsensitive )
+ {
+ var i;
+ var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
+ var oPrevSearch = oSettings.oPreviousSearch;
+
+ /* Check if we are forcing or not - optional parameter */
+ if ( !iForce )
+ {
+ iForce = 0;
+ }
+
+ /* Need to take account of custom filtering functions - always filter */
+ if ( DataTable.ext.afnFiltering.length !== 0 )
+ {
+ iForce = 1;
+ }
+
+ /*
+ * If the input is blank - we want the full data set
+ */
+ if ( sInput.length <= 0 )
+ {
+ oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+ }
+ else
+ {
+ /*
+ * We are starting a new search or the new search string is smaller
+ * then the old one (i.e. delete). Search from the master array
+ */
+ if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length ||
+ oPrevSearch.sSearch.length > sInput.length || iForce == 1 ||
+ sInput.indexOf(oPrevSearch.sSearch) !== 0 )
+ {
+ /* Nuke the old display array - we are going to rebuild it */
+ oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
+
+ /* Force a rebuild of the search array */
+ _fnBuildSearchArray( oSettings, 1 );
+
+ /* Search through all records to populate the search array
+ * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1
+ * mapping
+ */
+ for ( i=0 ; i<oSettings.aiDisplayMaster.length ; i++ )
+ {
+ if ( rpSearch.test(oSettings.asDataSearch[i]) )
+ {
+ oSettings.aiDisplay.push( oSettings.aiDisplayMaster[i] );
+ }
+ }
+ }
+ else
+ {
+ /* Using old search array - refine it - do it this way for speed
+ * Don't have to search the whole master array again
+ */
+ var iIndexCorrector = 0;
+
+ /* Search the current results */
+ for ( i=0 ; i<oSettings.asDataSearch.length ; i++ )
+ {
+ if ( ! rpSearch.test(oSettings.asDataSearch[i]) )
+ {
+ oSettings.aiDisplay.splice( i-iIndexCorrector, 1 );
+ iIndexCorrector++;
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Create an array which can be quickly search through
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iMaster use the master data array - optional
+ * @memberof DataTable#oApi
+ */
+ function _fnBuildSearchArray ( oSettings, iMaster )
+ {
+ if ( !oSettings.oFeatures.bServerSide )
+ {
+ /* Clear out the old data */
+ oSettings.asDataSearch = [];
+
+ var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );
+ var aiIndex = (iMaster===1) ?
+ oSettings.aiDisplayMaster :
+ oSettings.aiDisplay;
+
+ for ( var i=0, iLen=aiIndex.length ; i<iLen ; i++ )
+ {
+ oSettings.asDataSearch[i] = _fnBuildSearchRow(
+ oSettings,
+ _fnGetRowData( oSettings, aiIndex[i], 'filter', aiFilterColumns )
+ );
+ }
+ }
+ }
+
+
+ /**
+ * Create a searchable string from a single data row
+ * @param {object} oSettings dataTables settings object
+ * @param {array} aData Row data array to use for the data to search
+ * @memberof DataTable#oApi
+ */
+ function _fnBuildSearchRow( oSettings, aData )
+ {
+ var sSearch = aData.join(' ');
+
+ /* If it looks like there is an HTML entity in the string, attempt to decode it */
+ if ( sSearch.indexOf('&') !== -1 )
+ {
+ sSearch = $('<div>').html(sSearch).text();
+ }
+
+ // Strip newline characters
+ return sSearch.replace( /[\n\r]/g, " " );
+ }
+
+ /**
+ * Build a regular expression object suitable for searching a table
+ * @param {string} sSearch string to search for
+ * @param {bool} bRegex treat as a regular expression or not
+ * @param {bool} bSmart perform smart filtering or not
+ * @param {bool} bCaseInsensitive Do case insensitive matching or not
+ * @returns {RegExp} constructed object
+ * @memberof DataTable#oApi
+ */
+ function _fnFilterCreateSearch( sSearch, bRegex, bSmart, bCaseInsensitive )
+ {
+ var asSearch, sRegExpString;
+
+ if ( bSmart )
+ {
+ /* Generate the regular expression to use. Something along the lines of:
+ * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
+ */
+ asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' );
+ sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';
+ return new RegExp( sRegExpString, bCaseInsensitive ? "i" : "" );
+ }
+ else
+ {
+ sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch );
+ return new RegExp( sSearch, bCaseInsensitive ? "i" : "" );
+ }
+ }
+
+
+ /**
+ * Convert raw data into something that the user can search on
+ * @param {string} sData data to be modified
+ * @param {string} sType data type
+ * @returns {string} search string
+ * @memberof DataTable#oApi
+ */
+ function _fnDataToSearch ( sData, sType )
+ {
+ if ( typeof DataTable.ext.ofnSearch[sType] === "function" )
+ {
+ return DataTable.ext.ofnSearch[sType]( sData );
+ }
+ else if ( sData === null )
+ {
+ return '';
+ }
+ else if ( sType == "html" )
+ {
+ return sData.replace(/[\r\n]/g," ").replace( /<.*?>/g, "" );
+ }
+ else if ( typeof sData === "string" )
+ {
+ return sData.replace(/[\r\n]/g," ");
+ }
+ return sData;
+ }
+
+
+ /**
+ * scape a string such that it can be used in a regular expression
+ * @param {string} sVal string to escape
+ * @returns {string} escaped string
+ * @memberof DataTable#oApi
+ */
+ function _fnEscapeRegex ( sVal )
+ {
+ var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ];
+ var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' );
+ return sVal.replace(reReplace, '\\$1');
+ }
+
+
+ /**
+ * Generate the node required for the info display
+ * @param {object} oSettings dataTables settings object
+ * @returns {node} Information element
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlInfo ( oSettings )
+ {
+ var nInfo = document.createElement( 'div' );
+ nInfo.className = oSettings.oClasses.sInfo;
+
+ /* Actions that are to be taken once only for this feature */
+ if ( !oSettings.aanFeatures.i )
+ {
+ /* Add draw callback */
+ oSettings.aoDrawCallback.push( {
+ "fn": _fnUpdateInfo,
+ "sName": "information"
+ } );
+
+ /* Add id */
+ nInfo.id = oSettings.sTableId+'_info';
+ }
+ oSettings.nTable.setAttribute( 'aria-describedby', oSettings.sTableId+'_info' );
+
+ return nInfo;
+ }
+
+
+ /**
+ * Update the information elements in the display
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnUpdateInfo ( oSettings )
+ {
+ /* Show information about the table */
+ if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 )
+ {
+ return;
+ }
+
+ var
+ oLang = oSettings.oLanguage,
+ iStart = oSettings._iDisplayStart+1,
+ iEnd = oSettings.fnDisplayEnd(),
+ iMax = oSettings.fnRecordsTotal(),
+ iTotal = oSettings.fnRecordsDisplay(),
+ sOut;
+
+ if ( iTotal === 0 )
+ {
+ /* Empty record set */
+ sOut = oLang.sInfoEmpty;
+ }
+ else {
+ /* Normal record set */
+ sOut = oLang.sInfo;
+ }
+
+ if ( iTotal != iMax )
+ {
+ /* Record set after filtering */
+ sOut += ' ' + oLang.sInfoFiltered;
+ }
+
+ // Convert the macros
+ sOut += oLang.sInfoPostFix;
+ sOut = _fnInfoMacros( oSettings, sOut );
+
+ if ( oLang.fnInfoCallback !== null )
+ {
+ sOut = oLang.fnInfoCallback.call( oSettings.oInstance,
+ oSettings, iStart, iEnd, iMax, iTotal, sOut );
+ }
+
+ var n = oSettings.aanFeatures.i;
+ for ( var i=0, iLen=n.length ; i<iLen ; i++ )
+ {
+ $(n[i]).html( sOut );
+ }
+ }
+
+
+ function _fnInfoMacros ( oSettings, str )
+ {
+ var
+ iStart = oSettings._iDisplayStart+1,
+ sStart = oSettings.fnFormatNumber( iStart ),
+ iEnd = oSettings.fnDisplayEnd(),
+ sEnd = oSettings.fnFormatNumber( iEnd ),
+ iTotal = oSettings.fnRecordsDisplay(),
+ sTotal = oSettings.fnFormatNumber( iTotal ),
+ iMax = oSettings.fnRecordsTotal(),
+ sMax = oSettings.fnFormatNumber( iMax );
+
+ // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
+ // internally
+ if ( oSettings.oScroll.bInfinite )
+ {
+ sStart = oSettings.fnFormatNumber( 1 );
+ }
+
+ return str.
+ replace(/_START_/g, sStart).
+ replace(/_END_/g, sEnd).
+ replace(/_TOTAL_/g, sTotal).
+ replace(/_MAX_/g, sMax);
+ }
+
+
+
+ /**
+ * Draw the table for the first time, adding all required features
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnInitialise ( oSettings )
+ {
+ var i, iLen, iAjaxStart=oSettings.iInitDisplayStart;
+
+ /* Ensure that the table data is fully initialised */
+ if ( oSettings.bInitialised === false )
+ {
+ setTimeout( function(){ _fnInitialise( oSettings ); }, 200 );
+ return;
+ }
+
+ /* Show the display HTML options */
+ _fnAddOptionsHtml( oSettings );
+
+ /* Build and draw the header / footer for the table */
+ _fnBuildHead( oSettings );
+ _fnDrawHead( oSettings, oSettings.aoHeader );
+ if ( oSettings.nTFoot )
+ {
+ _fnDrawHead( oSettings, oSettings.aoFooter );
+ }
+
+ /* Okay to show that something is going on now */
+ _fnProcessingDisplay( oSettings, true );
+
+ /* Calculate sizes for columns */
+ if ( oSettings.oFeatures.bAutoWidth )
+ {
+ _fnCalculateColumnWidths( oSettings );
+ }
+
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ if ( oSettings.aoColumns[i].sWidth !== null )
+ {
+ oSettings.aoColumns[i].nTh.style.width = _fnStringToCss( oSettings.aoColumns[i].sWidth );
+ }
+ }
+
+ /* If there is default sorting required - let's do it. The sort function will do the
+ * drawing for us. Otherwise we draw the table regardless of the Ajax source - this allows
+ * the table to look initialised for Ajax sourcing data (show 'loading' message possibly)
+ */
+ if ( oSettings.oFeatures.bSort )
+ {
+ _fnSort( oSettings );
+ }
+ else if ( oSettings.oFeatures.bFilter )
+ {
+ _fnFilterComplete( oSettings, oSettings.oPreviousSearch );
+ }
+ else
+ {
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+
+ /* if there is an ajax source load the data */
+ if ( oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
+ {
+ var aoData = [];
+ _fnServerParams( oSettings, aoData );
+ oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData, function(json) {
+ var aData = (oSettings.sAjaxDataProp !== "") ?
+ _fnGetObjectDataFn( oSettings.sAjaxDataProp )(json) : json;
+
+ /* Got the data - add it to the table */
+ for ( i=0 ; i<aData.length ; i++ )
+ {
+ _fnAddData( oSettings, aData[i] );
+ }
+
+ /* Reset the init display for cookie saving. We've already done a filter, and
+ * therefore cleared it before. So we need to make it appear 'fresh'
+ */
+ oSettings.iInitDisplayStart = iAjaxStart;
+
+ if ( oSettings.oFeatures.bSort )
+ {
+ _fnSort( oSettings );
+ }
+ else
+ {
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+
+ _fnProcessingDisplay( oSettings, false );
+ _fnInitComplete( oSettings, json );
+ }, oSettings );
+ return;
+ }
+
+ /* Server-side processing initialisation complete is done at the end of _fnDraw */
+ if ( !oSettings.oFeatures.bServerSide )
+ {
+ _fnProcessingDisplay( oSettings, false );
+ _fnInitComplete( oSettings );
+ }
+ }
+
+
+ /**
+ * Draw the table for the first time, adding all required features
+ * @param {object} oSettings dataTables settings object
+ * @param {object} [json] JSON from the server that completed the table, if using Ajax source
+ * with client-side processing (optional)
+ * @memberof DataTable#oApi
+ */
+ function _fnInitComplete ( oSettings, json )
+ {
+ oSettings._bInitComplete = true;
+ _fnCallbackFire( oSettings, 'aoInitComplete', 'init', [oSettings, json] );
+ }
+
+
+ /**
+ * Language compatibility - when certain options are given, and others aren't, we
+ * need to duplicate the values over, in order to provide backwards compatibility
+ * with older language files.
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnLanguageCompat( oLanguage )
+ {
+ var oDefaults = DataTable.defaults.oLanguage;
+
+ /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
+ * sZeroRecords - assuming that is given.
+ */
+ if ( !oLanguage.sEmptyTable && oLanguage.sZeroRecords &&
+ oDefaults.sEmptyTable === "No data available in table" )
+ {
+ _fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );
+ }
+
+ /* Likewise with loading records */
+ if ( !oLanguage.sLoadingRecords && oLanguage.sZeroRecords &&
+ oDefaults.sLoadingRecords === "Loading..." )
+ {
+ _fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords' );
+ }
+ }
+
+
+
+ /**
+ * Generate the node required for user display length changing
+ * @param {object} oSettings dataTables settings object
+ * @returns {node} Display length feature node
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlLength ( oSettings )
+ {
+ if ( oSettings.oScroll.bInfinite )
+ {
+ return null;
+ }
+
+ /* This can be overruled by not using the _MENU_ var/macro in the language variable */
+ var sName = 'name="'+oSettings.sTableId+'_length"';
+ var sStdMenu = '<select size="1" '+sName+'>';
+ var i, iLen;
+ var aLengthMenu = oSettings.aLengthMenu;
+
+ if ( aLengthMenu.length == 2 && typeof aLengthMenu[0] === 'object' &&
+ typeof aLengthMenu[1] === 'object' )
+ {
+ for ( i=0, iLen=aLengthMenu[0].length ; i<iLen ; i++ )
+ {
+ sStdMenu += '<option value="'+aLengthMenu[0][i]+'">'+aLengthMenu[1][i]+'</option>';
+ }
+ }
+ else
+ {
+ for ( i=0, iLen=aLengthMenu.length ; i<iLen ; i++ )
+ {
+ sStdMenu += '<option value="'+aLengthMenu[i]+'">'+aLengthMenu[i]+'</option>';
+ }
+ }
+ sStdMenu += '</select>';
+
+ var nLength = document.createElement( 'div' );
+ if ( !oSettings.aanFeatures.l )
+ {
+ nLength.id = oSettings.sTableId+'_length';
+ }
+ nLength.className = oSettings.oClasses.sLength;
+ nLength.innerHTML = '<label>'+oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu )+'</label>';
+
+ /*
+ * Set the length to the current display length - thanks to Andrea Pavlovic for this fix,
+ * and Stefan Skopnik for fixing the fix!
+ */
+ $('select option[value="'+oSettings._iDisplayLength+'"]', nLength).attr("selected", true);
+
+ $('select', nLength).bind( 'change.DT', function(e) {
+ var iVal = $(this).val();
+
+ /* Update all other length options for the new display */
+ var n = oSettings.aanFeatures.l;
+ for ( i=0, iLen=n.length ; i<iLen ; i++ )
+ {
+ if ( n[i] != this.parentNode )
+ {
+ $('select', n[i]).val( iVal );
+ }
+ }
+
+ /* Redraw the table */
+ oSettings._iDisplayLength = parseInt(iVal, 10);
+ _fnCalculateEnd( oSettings );
+
+ /* If we have space to show extra rows (backing up from the end point - then do so */
+ if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() )
+ {
+ oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength;
+ if ( oSettings._iDisplayStart < 0 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+
+ if ( oSettings._iDisplayLength == -1 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+
+ _fnDraw( oSettings );
+ } );
+
+
+ $('select', nLength).attr('aria-controls', oSettings.sTableId);
+
+ return nLength;
+ }
+
+
+ /**
+ * Recalculate the end point based on the start point
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnCalculateEnd( oSettings )
+ {
+ if ( oSettings.oFeatures.bPaginate === false )
+ {
+ oSettings._iDisplayEnd = oSettings.aiDisplay.length;
+ }
+ else
+ {
+ /* Set the end point of the display - based on how many elements there are
+ * still to display
+ */
+ if ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length ||
+ oSettings._iDisplayLength == -1 )
+ {
+ oSettings._iDisplayEnd = oSettings.aiDisplay.length;
+ }
+ else
+ {
+ oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;
+ }
+ }
+ }
+
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Note that most of the paging logic is done in
+ * DataTable.ext.oPagination
+ */
+
+ /**
+ * Generate the node required for default pagination
+ * @param {object} oSettings dataTables settings object
+ * @returns {node} Pagination feature node
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlPaginate ( oSettings )
+ {
+ if ( oSettings.oScroll.bInfinite )
+ {
+ return null;
+ }
+
+ var nPaginate = document.createElement( 'div' );
+ nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType;
+
+ DataTable.ext.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate,
+ function( oSettings ) {
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+ );
+
+ /* Add a draw callback for the pagination on first instance, to update the paging display */
+ if ( !oSettings.aanFeatures.p )
+ {
+ oSettings.aoDrawCallback.push( {
+ "fn": function( oSettings ) {
+ DataTable.ext.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) {
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ } );
+ },
+ "sName": "pagination"
+ } );
+ }
+ return nPaginate;
+ }
+
+
+ /**
+ * Alter the display settings to change the page
+ * @param {object} oSettings dataTables settings object
+ * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
+ * or page number to jump to (integer)
+ * @returns {bool} true page has changed, false - no change (no effect) eg 'first' on page 1
+ * @memberof DataTable#oApi
+ */
+ function _fnPageChange ( oSettings, mAction )
+ {
+ var iOldStart = oSettings._iDisplayStart;
+
+ if ( typeof mAction === "number" )
+ {
+ oSettings._iDisplayStart = mAction * oSettings._iDisplayLength;
+ if ( oSettings._iDisplayStart > oSettings.fnRecordsDisplay() )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+ else if ( mAction == "first" )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ else if ( mAction == "previous" )
+ {
+ oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ?
+ oSettings._iDisplayStart - oSettings._iDisplayLength :
+ 0;
+
+ /* Correct for under-run */
+ if ( oSettings._iDisplayStart < 0 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+ else if ( mAction == "next" )
+ {
+ if ( oSettings._iDisplayLength >= 0 )
+ {
+ /* Make sure we are not over running the display array */
+ if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )
+ {
+ oSettings._iDisplayStart += oSettings._iDisplayLength;
+ }
+ }
+ else
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+ else if ( mAction == "last" )
+ {
+ if ( oSettings._iDisplayLength >= 0 )
+ {
+ var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;
+ oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;
+ }
+ else
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+ else
+ {
+ _fnLog( oSettings, 0, "Unknown paging action: "+mAction );
+ }
+ $(oSettings.oInstance).trigger('page', oSettings);
+
+ return iOldStart != oSettings._iDisplayStart;
+ }
+
+
+
+ /**
+ * Generate the node required for the processing node
+ * @param {object} oSettings dataTables settings object
+ * @returns {node} Processing element
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlProcessing ( oSettings )
+ {
+ var nProcessing = document.createElement( 'div' );
+
+ if ( !oSettings.aanFeatures.r )
+ {
+ nProcessing.id = oSettings.sTableId+'_processing';
+ }
+ nProcessing.innerHTML = oSettings.oLanguage.sProcessing;
+ nProcessing.className = oSettings.oClasses.sProcessing;
+ oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable );
+
+ return nProcessing;
+ }
+
+
+ /**
+ * Display or hide the processing indicator
+ * @param {object} oSettings dataTables settings object
+ * @param {bool} bShow Show the processing indicator (true) or not (false)
+ * @memberof DataTable#oApi
+ */
+ function _fnProcessingDisplay ( oSettings, bShow )
+ {
+ if ( oSettings.oFeatures.bProcessing )
+ {
+ var an = oSettings.aanFeatures.r;
+ for ( var i=0, iLen=an.length ; i<iLen ; i++ )
+ {
+ an[i].style.visibility = bShow ? "visible" : "hidden";
+ }
+ }
+
+ $(oSettings.oInstance).trigger('processing', [oSettings, bShow]);
+ }
+
+ /**
+ * Add any control elements for the table - specifically scrolling
+ * @param {object} oSettings dataTables settings object
+ * @returns {node} Node to add to the DOM
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlTable ( oSettings )
+ {
+ /* Check if scrolling is enabled or not - if not then leave the DOM unaltered */
+ if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
+ {
+ return oSettings.nTable;
+ }
+
+ /*
+ * The HTML structure that we want to generate in this function is:
+ * div - nScroller
+ * div - nScrollHead
+ * div - nScrollHeadInner
+ * table - nScrollHeadTable
+ * thead - nThead
+ * div - nScrollBody
+ * table - oSettings.nTable
+ * thead - nTheadSize
+ * tbody - nTbody
+ * div - nScrollFoot
+ * div - nScrollFootInner
+ * table - nScrollFootTable
+ * tfoot - nTfoot
+ */
+ var
+ nScroller = document.createElement('div'),
+ nScrollHead = document.createElement('div'),
+ nScrollHeadInner = document.createElement('div'),
+ nScrollBody = document.createElement('div'),
+ nScrollFoot = document.createElement('div'),
+ nScrollFootInner = document.createElement('div'),
+ nScrollHeadTable = oSettings.nTable.cloneNode(false),
+ nScrollFootTable = oSettings.nTable.cloneNode(false),
+ nThead = oSettings.nTable.getElementsByTagName('thead')[0],
+ nTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null :
+ oSettings.nTable.getElementsByTagName('tfoot')[0],
+ oClasses = oSettings.oClasses;
+
+ nScrollHead.appendChild( nScrollHeadInner );
+ nScrollFoot.appendChild( nScrollFootInner );
+ nScrollBody.appendChild( oSettings.nTable );
+ nScroller.appendChild( nScrollHead );
+ nScroller.appendChild( nScrollBody );
+ nScrollHeadInner.appendChild( nScrollHeadTable );
+ nScrollHeadTable.appendChild( nThead );
+ if ( nTfoot !== null )
+ {
+ nScroller.appendChild( nScrollFoot );
+ nScrollFootInner.appendChild( nScrollFootTable );
+ nScrollFootTable.appendChild( nTfoot );
+ }
+
+ nScroller.className = oClasses.sScrollWrapper;
+ nScrollHead.className = oClasses.sScrollHead;
+ nScrollHeadInner.className = oClasses.sScrollHeadInner;
+ nScrollBody.className = oClasses.sScrollBody;
+ nScrollFoot.className = oClasses.sScrollFoot;
+ nScrollFootInner.className = oClasses.sScrollFootInner;
+
+ if ( oSettings.oScroll.bAutoCss )
+ {
+ nScrollHead.style.overflow = "hidden";
+ nScrollHead.style.position = "relative";
+ nScrollFoot.style.overflow = "hidden";
+ nScrollBody.style.overflow = "auto";
+ }
+
+ nScrollHead.style.border = "0";
+ nScrollHead.style.width = "100%";
+ nScrollFoot.style.border = "0";
+ nScrollHeadInner.style.width = oSettings.oScroll.sXInner !== "" ?
+ oSettings.oScroll.sXInner : "100%"; /* will be overwritten */
+
+ /* Modify attributes to respect the clones */
+ nScrollHeadTable.removeAttribute('id');
+ nScrollHeadTable.style.marginLeft = "0";
+ oSettings.nTable.style.marginLeft = "0";
+ if ( nTfoot !== null )
+ {
+ nScrollFootTable.removeAttribute('id');
+ nScrollFootTable.style.marginLeft = "0";
+ }
+
+ /* Move caption elements from the body to the header, footer or leave where it is
+ * depending on the configuration. Note that the DTD says there can be only one caption */
+ var nCaption = $(oSettings.nTable).children('caption');
+ if ( nCaption.length > 0 )
+ {
+ nCaption = nCaption[0];
+ if ( nCaption._captionSide === "top" )
+ {
+ nScrollHeadTable.appendChild( nCaption );
+ }
+ else if ( nCaption._captionSide === "bottom" && nTfoot )
+ {
+ nScrollFootTable.appendChild( nCaption );
+ }
+ }
+
+ /*
+ * Sizing
+ */
+ /* When x-scrolling add the width and a scroller to move the header with the body */
+ if ( oSettings.oScroll.sX !== "" )
+ {
+ nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX );
+ nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX );
+
+ if ( nTfoot !== null )
+ {
+ nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX );
+ }
+
+ /* When the body is scrolled, then we also want to scroll the headers */
+ $(nScrollBody).scroll( function (e) {
+ nScrollHead.scrollLeft = this.scrollLeft;
+
+ if ( nTfoot !== null )
+ {
+ nScrollFoot.scrollLeft = this.scrollLeft;
+ }
+ } );
+ }
+
+ /* When yscrolling, add the height */
+ if ( oSettings.oScroll.sY !== "" )
+ {
+ nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY );
+ }
+
+ /* Redraw - align columns across the tables */
+ oSettings.aoDrawCallback.push( {
+ "fn": _fnScrollDraw,
+ "sName": "scrolling"
+ } );
+
+ /* Infinite scrolling event handlers */
+ if ( oSettings.oScroll.bInfinite )
+ {
+ $(nScrollBody).scroll( function() {
+ /* Use a blocker to stop scrolling from loading more data while other data is still loading */
+ if ( !oSettings.bDrawing && $(this).scrollTop() !== 0 )
+ {
+ /* Check if we should load the next data set */
+ if ( $(this).scrollTop() + $(this).height() >
+ $(oSettings.nTable).height() - oSettings.oScroll.iLoadGap )
+ {
+ /* Only do the redraw if we have to - we might be at the end of the data */
+ if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() )
+ {
+ _fnPageChange( oSettings, 'next' );
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+ }
+ }
+ } );
+ }
+
+ oSettings.nScrollHead = nScrollHead;
+ oSettings.nScrollFoot = nScrollFoot;
+
+ return nScroller;
+ }
+
+
+ /**
+ * Update the various tables for resizing. It's a bit of a pig this function, but
+ * basically the idea to:
+ * 1. Re-create the table inside the scrolling div
+ * 2. Take live measurements from the DOM
+ * 3. Apply the measurements
+ * 4. Clean up
+ * @param {object} o dataTables settings object
+ * @returns {node} Node to add to the DOM
+ * @memberof DataTable#oApi
+ */
+ function _fnScrollDraw ( o )
+ {
+ var
+ nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0],
+ nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
+ nScrollBody = o.nTable.parentNode,
+ i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis,
+ nTheadSize, nTfootSize,
+ iWidth, aApplied=[], aAppliedFooter=[], iSanityWidth,
+ nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null,
+ nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null,
+ ie67 = o.oBrowser.bScrollOversize,
+ zeroOut = function(nSizer) {
+ oStyle = nSizer.style;
+ oStyle.paddingTop = "0";
+ oStyle.paddingBottom = "0";
+ oStyle.borderTopWidth = "0";
+ oStyle.borderBottomWidth = "0";
+ oStyle.height = 0;
+ };
+
+ /*
+ * 1. Re-create the table inside the scrolling div
+ */
+
+ /* Remove the old minimised thead and tfoot elements in the inner table */
+ $(o.nTable).children('thead, tfoot').remove();
+
+ /* Clone the current header and footer elements and then place it into the inner table */
+ nTheadSize = $(o.nTHead).clone()[0];
+ o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] );
+ anHeadToSize = o.nTHead.getElementsByTagName('tr');
+ anHeadSizers = nTheadSize.getElementsByTagName('tr');
+
+ if ( o.nTFoot !== null )
+ {
+ nTfootSize = $(o.nTFoot).clone()[0];
+ o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] );
+ anFootToSize = o.nTFoot.getElementsByTagName('tr');
+ anFootSizers = nTfootSize.getElementsByTagName('tr');
+ }
+
+ /*
+ * 2. Take live measurements from the DOM - do not alter the DOM itself!
+ */
+
+ /* Remove old sizing and apply the calculated column widths
+ * Get the unique column headers in the newly created (cloned) header. We want to apply the
+ * calculated sizes to this header
+ */
+ if ( o.oScroll.sX === "" )
+ {
+ nScrollBody.style.width = '100%';
+ nScrollHeadInner.parentNode.style.width = '100%';
+ }
+
+ var nThs = _fnGetUniqueThs( o, nTheadSize );
+ for ( i=0, iLen=nThs.length ; i<iLen ; i++ )
+ {
+ iVis = _fnVisibleToColumnIndex( o, i );
+ nThs[i].style.width = o.aoColumns[iVis].sWidth;
+ }
+
+ if ( o.nTFoot !== null )
+ {
+ _fnApplyToChildren( function(n) {
+ n.style.width = "";
+ }, anFootSizers );
+ }
+
+ // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
+ // will end up forcing the scrollbar to appear, making our measurements wrong for when we
+ // then hide it (end of this function), so add the header height to the body scroller.
+ if ( o.oScroll.bCollapse && o.oScroll.sY !== "" )
+ {
+ nScrollBody.style.height = (nScrollBody.offsetHeight + o.nTHead.offsetHeight)+"px";
+ }
+
+ /* Size the table as a whole */
+ iSanityWidth = $(o.nTable).outerWidth();
+ if ( o.oScroll.sX === "" )
+ {
+ /* No x scrolling */
+ o.nTable.style.width = "100%";
+
+ /* I know this is rubbish - but IE7 will make the width of the table when 100% include
+ * the scrollbar - which is shouldn't. When there is a scrollbar we need to take this
+ * into account.
+ */
+ if ( ie67 && ($('tbody', nScrollBody).height() > nScrollBody.offsetHeight ||
+ $(nScrollBody).css('overflow-y') == "scroll") )
+ {
+ o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth() - o.oScroll.iBarWidth);
+ }
+ }
+ else
+ {
+ if ( o.oScroll.sXInner !== "" )
+ {
+ /* x scroll inner has been given - use it */
+ o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner);
+ }
+ else if ( iSanityWidth == $(nScrollBody).width() &&
+ $(nScrollBody).height() < $(o.nTable).height() )
+ {
+ /* There is y-scrolling - try to take account of the y scroll bar */
+ o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth );
+ if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth )
+ {
+ /* Not possible to take account of it */
+ o.nTable.style.width = _fnStringToCss( iSanityWidth );
+ }
+ }
+ else
+ {
+ /* All else fails */
+ o.nTable.style.width = _fnStringToCss( iSanityWidth );
+ }
+ }
+
+ /* Recalculate the sanity width - now that we've applied the required width, before it was
+ * a temporary variable. This is required because the column width calculation is done
+ * before this table DOM is created.
+ */
+ iSanityWidth = $(o.nTable).outerWidth();
+
+ /* We want the hidden header to have zero height, so remove padding and borders. Then
+ * set the width based on the real headers
+ */
+
+ // Apply all styles in one pass. Invalidates layout only once because we don't read any
+ // DOM properties.
+ _fnApplyToChildren( zeroOut, anHeadSizers );
+
+ // Read all widths in next pass. Forces layout only once because we do not change
+ // any DOM properties.
+ _fnApplyToChildren( function(nSizer) {
+ aApplied.push( _fnStringToCss( $(nSizer).width() ) );
+ }, anHeadSizers );
+
+ // Apply all widths in final pass. Invalidates layout only once because we do not
+ // read any DOM properties.
+ _fnApplyToChildren( function(nToSize, i) {
+ nToSize.style.width = aApplied[i];
+ }, anHeadToSize );
+
+ $(anHeadSizers).height(0);
+
+ /* Same again with the footer if we have one */
+ if ( o.nTFoot !== null )
+ {
+ _fnApplyToChildren( zeroOut, anFootSizers );
+
+ _fnApplyToChildren( function(nSizer) {
+ aAppliedFooter.push( _fnStringToCss( $(nSizer).width() ) );
+ }, anFootSizers );
+
+ _fnApplyToChildren( function(nToSize, i) {
+ nToSize.style.width = aAppliedFooter[i];
+ }, anFootToSize );
+
+ $(anFootSizers).height(0);
+ }
+
+ /*
+ * 3. Apply the measurements
+ */
+
+ /* "Hide" the header and footer that we used for the sizing. We want to also fix their width
+ * to what they currently are
+ */
+ _fnApplyToChildren( function(nSizer, i) {
+ nSizer.innerHTML = "";
+ nSizer.style.width = aApplied[i];
+ }, anHeadSizers );
+
+ if ( o.nTFoot !== null )
+ {
+ _fnApplyToChildren( function(nSizer, i) {
+ nSizer.innerHTML = "";
+ nSizer.style.width = aAppliedFooter[i];
+ }, anFootSizers );
+ }
+
+ /* Sanity check that the table is of a sensible width. If not then we are going to get
+ * misalignment - try to prevent this by not allowing the table to shrink below its min width
+ */
+ if ( $(o.nTable).outerWidth() < iSanityWidth )
+ {
+ /* The min width depends upon if we have a vertical scrollbar visible or not */
+ var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight ||
+ $(nScrollBody).css('overflow-y') == "scroll")) ?
+ iSanityWidth+o.oScroll.iBarWidth : iSanityWidth;
+
+ /* IE6/7 are a law unto themselves... */
+ if ( ie67 && (nScrollBody.scrollHeight >
+ nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll") )
+ {
+ o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth );
+ }
+
+ /* Apply the calculated minimum width to the table wrappers */
+ nScrollBody.style.width = _fnStringToCss( iCorrection );
+ o.nScrollHead.style.width = _fnStringToCss( iCorrection );
+
+ if ( o.nTFoot !== null )
+ {
+ o.nScrollFoot.style.width = _fnStringToCss( iCorrection );
+ }
+
+ /* And give the user a warning that we've stopped the table getting too small */
+ if ( o.oScroll.sX === "" )
+ {
+ _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
+ " misalignment. The table has been drawn at its minimum possible width." );
+ }
+ else if ( o.oScroll.sXInner !== "" )
+ {
+ _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
+ " misalignment. Increase the sScrollXInner value or remove it to allow automatic"+
+ " calculation" );
+ }
+ }
+ else
+ {
+ nScrollBody.style.width = _fnStringToCss( '100%' );
+ o.nScrollHead.style.width = _fnStringToCss( '100%' );
+
+ if ( o.nTFoot !== null )
+ {
+ o.nScrollFoot.style.width = _fnStringToCss( '100%' );
+ }
+ }
+
+
+ /*
+ * 4. Clean up
+ */
+ if ( o.oScroll.sY === "" )
+ {
+ /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
+ * the scrollbar height from the visible display, rather than adding it on. We need to
+ * set the height in order to sort this. Don't want to do it in any other browsers.
+ */
+ if ( ie67 )
+ {
+ nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth );
+ }
+ }
+
+ if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )
+ {
+ nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );
+
+ var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?
+ o.oScroll.iBarWidth : 0;
+ if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
+ {
+ nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+iExtra );
+ }
+ }
+
+ /* Finally set the width's of the header and footer tables */
+ var iOuterWidth = $(o.nTable).outerWidth();
+ nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth );
+ nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth );
+
+ // Figure out if there are scrollbar present - if so then we need a the header and footer to
+ // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
+ var bScrolling = $(o.nTable).height() > nScrollBody.clientHeight || $(nScrollBody).css('overflow-y') == "scroll";
+ nScrollHeadInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
+
+ if ( o.nTFoot !== null )
+ {
+ nScrollFootTable.style.width = _fnStringToCss( iOuterWidth );
+ nScrollFootInner.style.width = _fnStringToCss( iOuterWidth );
+ nScrollFootInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
+ }
+
+ /* Adjust the position of the header in case we loose the y-scrollbar */
+ $(nScrollBody).scroll();
+
+ /* If sorting or filtering has occurred, jump the scrolling back to the top */
+ if ( o.bSorted || o.bFiltered )
+ {
+ nScrollBody.scrollTop = 0;
+ }
+ }
+
+
+ /**
+ * Apply a given function to the display child nodes of an element array (typically
+ * TD children of TR rows
+ * @param {function} fn Method to apply to the objects
+ * @param array {nodes} an1 List of elements to look through for display children
+ * @param array {nodes} an2 Another list (identical structure to the first) - optional
+ * @memberof DataTable#oApi
+ */
+ function _fnApplyToChildren( fn, an1, an2 )
+ {
+ var index=0, i=0, iLen=an1.length;
+ var nNode1, nNode2;
+
+ while ( i < iLen )
+ {
+ nNode1 = an1[i].firstChild;
+ nNode2 = an2 ? an2[i].firstChild : null;
+ while ( nNode1 )
+ {
+ if ( nNode1.nodeType === 1 )
+ {
+ if ( an2 )
+ {
+ fn( nNode1, nNode2, index );
+ }
+ else
+ {
+ fn( nNode1, index );
+ }
+ index++;
+ }
+ nNode1 = nNode1.nextSibling;
+ nNode2 = an2 ? nNode2.nextSibling : null;
+ }
+ i++;
+ }
+ }
+
+ /**
+ * Convert a CSS unit width to pixels (e.g. 2em)
+ * @param {string} sWidth width to be converted
+ * @param {node} nParent parent to get the with for (required for relative widths) - optional
+ * @returns {int} iWidth width in pixels
+ * @memberof DataTable#oApi
+ */
+ function _fnConvertToWidth ( sWidth, nParent )
+ {
+ if ( !sWidth || sWidth === null || sWidth === '' )
+ {
+ return 0;
+ }
+
+ if ( !nParent )
+ {
+ nParent = document.body;
+ }
+
+ var iWidth;
+ var nTmp = document.createElement( "div" );
+ nTmp.style.width = _fnStringToCss( sWidth );
+
+ nParent.appendChild( nTmp );
+ iWidth = nTmp.offsetWidth;
+ nParent.removeChild( nTmp );
+
+ return ( iWidth );
+ }
+
+
+ /**
+ * Calculate the width of columns for the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnCalculateColumnWidths ( oSettings )
+ {
+ var iTableWidth = oSettings.nTable.offsetWidth;
+ var iUserInputs = 0;
+ var iTmpWidth;
+ var iVisibleColumns = 0;
+ var iColums = oSettings.aoColumns.length;
+ var i, iIndex, iCorrector, iWidth;
+ var oHeaders = $('th', oSettings.nTHead);
+ var widthAttr = oSettings.nTable.getAttribute('width');
+ var nWrapper = oSettings.nTable.parentNode;
+
+ /* Convert any user input sizes into pixel sizes */
+ for ( i=0 ; i<iColums ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bVisible )
+ {
+ iVisibleColumns++;
+
+ if ( oSettings.aoColumns[i].sWidth !== null )
+ {
+ iTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig,
+ nWrapper );
+ if ( iTmpWidth !== null )
+ {
+ oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
+ }
+
+ iUserInputs++;
+ }
+ }
+ }
+
+ /* If the number of columns in the DOM equals the number that we have to process in
+ * DataTables, then we can use the offsets that are created by the web-browser. No custom
+ * sizes can be set in order for this to happen, nor scrolling used
+ */
+ if ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums &&
+ oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
+ {
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ iTmpWidth = $(oHeaders[i]).width();
+ if ( iTmpWidth !== null )
+ {
+ oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
+ }
+ }
+ }
+ else
+ {
+ /* Otherwise we are going to have to do some calculations to get the width of each column.
+ * Construct a 1 row table with the widest node in the data, and any user defined widths,
+ * then insert it into the DOM and allow the browser to do all the hard work of
+ * calculating table widths.
+ */
+ var
+ nCalcTmp = oSettings.nTable.cloneNode( false ),
+ nTheadClone = oSettings.nTHead.cloneNode(true),
+ nBody = document.createElement( 'tbody' ),
+ nTr = document.createElement( 'tr' ),
+ nDivSizing;
+
+ nCalcTmp.removeAttribute( "id" );
+ nCalcTmp.appendChild( nTheadClone );
+ if ( oSettings.nTFoot !== null )
+ {
+ nCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) );
+ _fnApplyToChildren( function(n) {
+ n.style.width = "";
+ }, nCalcTmp.getElementsByTagName('tr') );
+ }
+
+ nCalcTmp.appendChild( nBody );
+ nBody.appendChild( nTr );
+
+ /* Remove any sizing that was previously applied by the styles */
+ var jqColSizing = $('thead th', nCalcTmp);
+ if ( jqColSizing.length === 0 )
+ {
+ jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp);
+ }
+
+ /* Apply custom sizing to the cloned header */
+ var nThs = _fnGetUniqueThs( oSettings, nTheadClone );
+ iCorrector = 0;
+ for ( i=0 ; i<iColums ; i++ )
+ {
+ var oColumn = oSettings.aoColumns[i];
+ if ( oColumn.bVisible && oColumn.sWidthOrig !== null && oColumn.sWidthOrig !== "" )
+ {
+ nThs[i-iCorrector].style.width = _fnStringToCss( oColumn.sWidthOrig );
+ }
+ else if ( oColumn.bVisible )
+ {
+ nThs[i-iCorrector].style.width = "";
+ }
+ else
+ {
+ iCorrector++;
+ }
+ }
+
+ /* Find the biggest td for each column and put it into the table */
+ for ( i=0 ; i<iColums ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bVisible )
+ {
+ var nTd = _fnGetWidestNode( oSettings, i );
+ if ( nTd !== null )
+ {
+ nTd = nTd.cloneNode(true);
+ if ( oSettings.aoColumns[i].sContentPadding !== "" )
+ {
+ nTd.innerHTML += oSettings.aoColumns[i].sContentPadding;
+ }
+ nTr.appendChild( nTd );
+ }
+ }
+ }
+
+ /* Build the table and 'display' it */
+ nWrapper.appendChild( nCalcTmp );
+
+ /* When scrolling (X or Y) we want to set the width of the table as appropriate. However,
+ * when not scrolling leave the table width as it is. This results in slightly different,
+ * but I think correct behaviour
+ */
+ if ( oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "" )
+ {
+ nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner);
+ }
+ else if ( oSettings.oScroll.sX !== "" )
+ {
+ nCalcTmp.style.width = "";
+ if ( $(nCalcTmp).width() < nWrapper.offsetWidth )
+ {
+ nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
+ }
+ }
+ else if ( oSettings.oScroll.sY !== "" )
+ {
+ nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
+ }
+ else if ( widthAttr )
+ {
+ nCalcTmp.style.width = _fnStringToCss( widthAttr );
+ }
+ nCalcTmp.style.visibility = "hidden";
+
+ /* Scrolling considerations */
+ _fnScrollingWidthAdjust( oSettings, nCalcTmp );
+
+ /* Read the width's calculated by the browser and store them for use by the caller. We
+ * first of all try to use the elements in the body, but it is possible that there are
+ * no elements there, under which circumstances we use the header elements
+ */
+ var oNodes = $("tbody tr:eq(0)", nCalcTmp).children();
+ if ( oNodes.length === 0 )
+ {
+ oNodes = _fnGetUniqueThs( oSettings, $('thead', nCalcTmp)[0] );
+ }
+
+ /* Browsers need a bit of a hand when a width is assigned to any columns when
+ * x-scrolling as they tend to collapse the table to the min-width, even if
+ * we sent the column widths. So we need to keep track of what the table width
+ * should be by summing the user given values, and the automatic values
+ */
+ if ( oSettings.oScroll.sX !== "" )
+ {
+ var iTotal = 0;
+ iCorrector = 0;
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bVisible )
+ {
+ if ( oSettings.aoColumns[i].sWidthOrig === null )
+ {
+ iTotal += $(oNodes[iCorrector]).outerWidth();
+ }
+ else
+ {
+ iTotal += parseInt(oSettings.aoColumns[i].sWidth.replace('px',''), 10) +
+ ($(oNodes[iCorrector]).outerWidth() - $(oNodes[iCorrector]).width());
+ }
+ iCorrector++;
+ }
+ }
+
+ nCalcTmp.style.width = _fnStringToCss( iTotal );
+ oSettings.nTable.style.width = _fnStringToCss( iTotal );
+ }
+
+ iCorrector = 0;
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bVisible )
+ {
+ iWidth = $(oNodes[iCorrector]).width();
+ if ( iWidth !== null && iWidth > 0 )
+ {
+ oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );
+ }
+ iCorrector++;
+ }
+ }
+
+ var cssWidth = $(nCalcTmp).css('width');
+ oSettings.nTable.style.width = (cssWidth.indexOf('%') !== -1) ?
+ cssWidth : _fnStringToCss( $(nCalcTmp).outerWidth() );
+ nCalcTmp.parentNode.removeChild( nCalcTmp );
+ }
+
+ if ( widthAttr )
+ {
+ oSettings.nTable.style.width = _fnStringToCss( widthAttr );
+ }
+ }
+
+
+ /**
+ * Adjust a table's width to take account of scrolling
+ * @param {object} oSettings dataTables settings object
+ * @param {node} n table node
+ * @memberof DataTable#oApi
+ */
+ function _fnScrollingWidthAdjust ( oSettings, n )
+ {
+ if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" )
+ {
+ /* When y-scrolling only, we want to remove the width of the scroll bar so the table
+ * + scroll bar will fit into the area avaialble.
+ */
+ var iOrigWidth = $(n).width();
+ n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );
+ }
+ else if ( oSettings.oScroll.sX !== "" )
+ {
+ /* When x-scrolling both ways, fix the table at it's current size, without adjusting */
+ n.style.width = _fnStringToCss( $(n).outerWidth() );
+ }
+ }
+
+
+ /**
+ * Get the widest node
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iCol column of interest
+ * @returns {node} widest table node
+ * @memberof DataTable#oApi
+ */
+ function _fnGetWidestNode( oSettings, iCol )
+ {
+ var iMaxIndex = _fnGetMaxLenString( oSettings, iCol );
+ if ( iMaxIndex < 0 )
+ {
+ return null;
+ }
+
+ if ( oSettings.aoData[iMaxIndex].nTr === null )
+ {
+ var n = document.createElement('td');
+ n.innerHTML = _fnGetCellData( oSettings, iMaxIndex, iCol, '' );
+ return n;
+ }
+ return _fnGetTdNodes(oSettings, iMaxIndex)[iCol];
+ }
+
+
+ /**
+ * Get the maximum strlen for each data column
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iCol column of interest
+ * @returns {string} max string length for each column
+ * @memberof DataTable#oApi
+ */
+ function _fnGetMaxLenString( oSettings, iCol )
+ {
+ var iMax = -1;
+ var iMaxIndex = -1;
+
+ for ( var i=0 ; i<oSettings.aoData.length ; i++ )
+ {
+ var s = _fnGetCellData( oSettings, i, iCol, 'display' )+"";
+ s = s.replace( /<.*?>/g, "" );
+ if ( s.length > iMax )
+ {
+ iMax = s.length;
+ iMaxIndex = i;
+ }
+ }
+
+ return iMaxIndex;
+ }
+
+
+ /**
+ * Append a CSS unit (only if required) to a string
+ * @param {array} aArray1 first array
+ * @param {array} aArray2 second array
+ * @returns {int} 0 if match, 1 if length is different, 2 if no match
+ * @memberof DataTable#oApi
+ */
+ function _fnStringToCss( s )
+ {
+ if ( s === null )
+ {
+ return "0px";
+ }
+
+ if ( typeof s == 'number' )
+ {
+ if ( s < 0 )
+ {
+ return "0px";
+ }
+ return s+"px";
+ }
+
+ /* Check if the last character is not 0-9 */
+ var c = s.charCodeAt( s.length-1 );
+ if (c < 0x30 || c > 0x39)
+ {
+ return s;
+ }
+ return s+"px";
+ }
+
+
+ /**
+ * Get the width of a scroll bar in this browser being used
+ * @returns {int} width in pixels
+ * @memberof DataTable#oApi
+ */
+ function _fnScrollBarWidth ()
+ {
+ var inner = document.createElement('p');
+ var style = inner.style;
+ style.width = "100%";
+ style.height = "200px";
+ style.padding = "0px";
+
+ var outer = document.createElement('div');
+ style = outer.style;
+ style.position = "absolute";
+ style.top = "0px";
+ style.left = "0px";
+ style.visibility = "hidden";
+ style.width = "200px";
+ style.height = "150px";
+ style.padding = "0px";
+ style.overflow = "hidden";
+ outer.appendChild(inner);
+
+ document.body.appendChild(outer);
+ var w1 = inner.offsetWidth;
+ outer.style.overflow = 'scroll';
+ var w2 = inner.offsetWidth;
+ if ( w1 == w2 )
+ {
+ w2 = outer.clientWidth;
+ }
+
+ document.body.removeChild(outer);
+ return (w1 - w2);
+ }
+
+ /**
+ * Change the order of the table
+ * @param {object} oSettings dataTables settings object
+ * @param {bool} bApplyClasses optional - should we apply classes or not
+ * @memberof DataTable#oApi
+ */
+ function _fnSort ( oSettings, bApplyClasses )
+ {
+ var
+ i, iLen, j, jLen, k, kLen,
+ sDataType, nTh,
+ aaSort = [],
+ aiOrig = [],
+ oSort = DataTable.ext.oSort,
+ aoData = oSettings.aoData,
+ aoColumns = oSettings.aoColumns,
+ oAria = oSettings.oLanguage.oAria;
+
+ /* No sorting required if server-side or no sorting array */
+ if ( !oSettings.oFeatures.bServerSide &&
+ (oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) )
+ {
+ aaSort = ( oSettings.aaSortingFixed !== null ) ?
+ oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :
+ oSettings.aaSorting.slice();
+
+ /* If there is a sorting data type, and a function belonging to it, then we need to
+ * get the data from the developer's function and apply it for this column
+ */
+ for ( i=0 ; i<aaSort.length ; i++ )
+ {
+ var iColumn = aaSort[i][0];
+ var iVisColumn = _fnColumnIndexToVisible( oSettings, iColumn );
+ sDataType = oSettings.aoColumns[ iColumn ].sSortDataType;
+ if ( DataTable.ext.afnSortData[sDataType] )
+ {
+ var aData = DataTable.ext.afnSortData[sDataType].call(
+ oSettings.oInstance, oSettings, iColumn, iVisColumn
+ );
+ if ( aData.length === aoData.length )
+ {
+ for ( j=0, jLen=aoData.length ; j<jLen ; j++ )
+ {
+ _fnSetCellData( oSettings, j, iColumn, aData[j] );
+ }
+ }
+ else
+ {
+ _fnLog( oSettings, 0, "Returned data sort array (col "+iColumn+") is the wrong length" );
+ }
+ }
+ }
+
+ /* Create a value - key array of the current row positions such that we can use their
+ * current position during the sort, if values match, in order to perform stable sorting
+ */
+ for ( i=0, iLen=oSettings.aiDisplayMaster.length ; i<iLen ; i++ )
+ {
+ aiOrig[ oSettings.aiDisplayMaster[i] ] = i;
+ }
+
+ /* Build an internal data array which is specific to the sort, so we can get and prep
+ * the data to be sorted only once, rather than needing to do it every time the sorting
+ * function runs. This make the sorting function a very simple comparison
+ */
+ var iSortLen = aaSort.length;
+ var fnSortFormat, aDataSort;
+ for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+ {
+ for ( j=0 ; j<iSortLen ; j++ )
+ {
+ aDataSort = aoColumns[ aaSort[j][0] ].aDataSort;
+
+ for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
+ {
+ sDataType = aoColumns[ aDataSort[k] ].sType;
+ fnSortFormat = oSort[ (sDataType ? sDataType : 'string')+"-pre" ];
+
+ aoData[i]._aSortData[ aDataSort[k] ] = fnSortFormat ?
+ fnSortFormat( _fnGetCellData( oSettings, i, aDataSort[k], 'sort' ) ) :
+ _fnGetCellData( oSettings, i, aDataSort[k], 'sort' );
+ }
+ }
+ }
+
+ /* Do the sort - here we want multi-column sorting based on a given data source (column)
+ * and sorting function (from oSort) in a certain direction. It's reasonably complex to
+ * follow on it's own, but this is what we want (example two column sorting):
+ * fnLocalSorting = function(a,b){
+ * var iTest;
+ * iTest = oSort['string-asc']('data11', 'data12');
+ * if (iTest !== 0)
+ * return iTest;
+ * iTest = oSort['numeric-desc']('data21', 'data22');
+ * if (iTest !== 0)
+ * return iTest;
+ * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
+ * }
+ * Basically we have a test for each sorting column, if the data in that column is equal,
+ * test the next column. If all columns match, then we use a numeric sort on the row
+ * positions in the original data array to provide a stable sort.
+ */
+ oSettings.aiDisplayMaster.sort( function ( a, b ) {
+ var k, l, lLen, iTest, aDataSort, sDataType;
+ for ( k=0 ; k<iSortLen ; k++ )
+ {
+ aDataSort = aoColumns[ aaSort[k][0] ].aDataSort;
+
+ for ( l=0, lLen=aDataSort.length ; l<lLen ; l++ )
+ {
+ sDataType = aoColumns[ aDataSort[l] ].sType;
+
+ iTest = oSort[ (sDataType ? sDataType : 'string')+"-"+aaSort[k][1] ](
+ aoData[a]._aSortData[ aDataSort[l] ],
+ aoData[b]._aSortData[ aDataSort[l] ]
+ );
+
+ if ( iTest !== 0 )
+ {
+ return iTest;
+ }
+ }
+ }
+
+ return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
+ } );
+ }
+
+ /* Alter the sorting classes to take account of the changes */
+ if ( (bApplyClasses === undefined || bApplyClasses) && !oSettings.oFeatures.bDeferRender )
+ {
+ _fnSortingClasses( oSettings );
+ }
+
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ var sTitle = aoColumns[i].sTitle.replace( /<.*?>/g, "" );
+ nTh = aoColumns[i].nTh;
+ nTh.removeAttribute('aria-sort');
+ nTh.removeAttribute('aria-label');
+
+ /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
+ if ( aoColumns[i].bSortable )
+ {
+ if ( aaSort.length > 0 && aaSort[0][0] == i )
+ {
+ nTh.setAttribute('aria-sort', aaSort[0][1]=="asc" ? "ascending" : "descending" );
+
+ var nextSort = (aoColumns[i].asSorting[ aaSort[0][2]+1 ]) ?
+ aoColumns[i].asSorting[ aaSort[0][2]+1 ] : aoColumns[i].asSorting[0];
+ nTh.setAttribute('aria-label', sTitle+
+ (nextSort=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
+ }
+ else
+ {
+ nTh.setAttribute('aria-label', sTitle+
+ (aoColumns[i].asSorting[0]=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
+ }
+ }
+ else
+ {
+ nTh.setAttribute('aria-label', sTitle);
+ }
+ }
+
+ /* Tell the draw function that we have sorted the data */
+ oSettings.bSorted = true;
+ $(oSettings.oInstance).trigger('sort', oSettings);
+
+ /* Copy the master data into the draw array and re-draw */
+ if ( oSettings.oFeatures.bFilter )
+ {
+ /* _fnFilter() will redraw the table for us */
+ _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
+ }
+ else
+ {
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+ oSettings._iDisplayStart = 0; /* reset display back to page 0 */
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+ }
+
+
+ /**
+ * Attach a sort handler (click) to a node
+ * @param {object} oSettings dataTables settings object
+ * @param {node} nNode node to attach the handler to
+ * @param {int} iDataIndex column sorting index
+ * @param {function} [fnCallback] callback function
+ * @memberof DataTable#oApi
+ */
+ function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback )
+ {
+ _fnBindAction( nNode, {}, function (e) {
+ /* If the column is not sortable - don't to anything */
+ if ( oSettings.aoColumns[iDataIndex].bSortable === false )
+ {
+ return;
+ }
+
+ /*
+ * This is a little bit odd I admit... I declare a temporary function inside the scope of
+ * _fnBuildHead and the click handler in order that the code presented here can be used
+ * twice - once for when bProcessing is enabled, and another time for when it is
+ * disabled, as we need to perform slightly different actions.
+ * Basically the issue here is that the Javascript engine in modern browsers don't
+ * appear to allow the rendering engine to update the display while it is still executing
+ * it's thread (well - it does but only after long intervals). This means that the
+ * 'processing' display doesn't appear for a table sort. To break the js thread up a bit
+ * I force an execution break by using setTimeout - but this breaks the expected
+ * thread continuation for the end-developer's point of view (their code would execute
+ * too early), so we only do it when we absolutely have to.
+ */
+ var fnInnerSorting = function () {
+ var iColumn, iNextSort;
+
+ /* If the shift key is pressed then we are multiple column sorting */
+ if ( e.shiftKey )
+ {
+ /* Are we already doing some kind of sort on this column? */
+ var bFound = false;
+ for ( var i=0 ; i<oSettings.aaSorting.length ; i++ )
+ {
+ if ( oSettings.aaSorting[i][0] == iDataIndex )
+ {
+ bFound = true;
+ iColumn = oSettings.aaSorting[i][0];
+ iNextSort = oSettings.aaSorting[i][2]+1;
+
+ if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
+ {
+ /* Reached the end of the sorting options, remove from multi-col sort */
+ oSettings.aaSorting.splice( i, 1 );
+ }
+ else
+ {
+ /* Move onto next sorting direction */
+ oSettings.aaSorting[i][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
+ oSettings.aaSorting[i][2] = iNextSort;
+ }
+ break;
+ }
+ }
+
+ /* No sort yet - add it in */
+ if ( bFound === false )
+ {
+ oSettings.aaSorting.push( [ iDataIndex,
+ oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
+ }
+ }
+ else
+ {
+ /* If no shift key then single column sort */
+ if ( oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex )
+ {
+ iColumn = oSettings.aaSorting[0][0];
+ iNextSort = oSettings.aaSorting[0][2]+1;
+ if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
+ {
+ iNextSort = 0;
+ }
+ oSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
+ oSettings.aaSorting[0][2] = iNextSort;
+ }
+ else
+ {
+ oSettings.aaSorting.splice( 0, oSettings.aaSorting.length );
+ oSettings.aaSorting.push( [ iDataIndex,
+ oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
+ }
+ }
+
+ /* Run the sort */
+ _fnSort( oSettings );
+ }; /* /fnInnerSorting */
+
+ if ( !oSettings.oFeatures.bProcessing )
+ {
+ fnInnerSorting();
+ }
+ else
+ {
+ _fnProcessingDisplay( oSettings, true );
+ setTimeout( function() {
+ fnInnerSorting();
+ if ( !oSettings.oFeatures.bServerSide )
+ {
+ _fnProcessingDisplay( oSettings, false );
+ }
+ }, 0 );
+ }
+
+ /* Call the user specified callback function - used for async user interaction */
+ if ( typeof fnCallback == 'function' )
+ {
+ fnCallback( oSettings );
+ }
+ } );
+ }
+
+
+ /**
+ * Set the sorting classes on the header, Note: it is safe to call this function
+ * when bSort and bSortClasses are false
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnSortingClasses( oSettings )
+ {
+ var i, iLen, j, jLen, iFound;
+ var aaSort, sClass;
+ var iColumns = oSettings.aoColumns.length;
+ var oClasses = oSettings.oClasses;
+
+ for ( i=0 ; i<iColumns ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bSortable )
+ {
+ $(oSettings.aoColumns[i].nTh).removeClass( oClasses.sSortAsc +" "+ oClasses.sSortDesc +
+ " "+ oSettings.aoColumns[i].sSortingClass );
+ }
+ }
+
+ if ( oSettings.aaSortingFixed !== null )
+ {
+ aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
+ }
+ else
+ {
+ aaSort = oSettings.aaSorting.slice();
+ }
+
+ /* Apply the required classes to the header */
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bSortable )
+ {
+ sClass = oSettings.aoColumns[i].sSortingClass;
+ iFound = -1;
+ for ( j=0 ; j<aaSort.length ; j++ )
+ {
+ if ( aaSort[j][0] == i )
+ {
+ sClass = ( aaSort[j][1] == "asc" ) ?
+ oClasses.sSortAsc : oClasses.sSortDesc;
+ iFound = j;
+ break;
+ }
+ }
+ $(oSettings.aoColumns[i].nTh).addClass( sClass );
+
+ if ( oSettings.bJUI )
+ {
+ /* jQuery UI uses extra markup */
+ var jqSpan = $("span."+oClasses.sSortIcon, oSettings.aoColumns[i].nTh);
+ jqSpan.removeClass(oClasses.sSortJUIAsc +" "+ oClasses.sSortJUIDesc +" "+
+ oClasses.sSortJUI +" "+ oClasses.sSortJUIAscAllowed +" "+ oClasses.sSortJUIDescAllowed );
+
+ var sSpanClass;
+ if ( iFound == -1 )
+ {
+ sSpanClass = oSettings.aoColumns[i].sSortingClassJUI;
+ }
+ else if ( aaSort[iFound][1] == "asc" )
+ {
+ sSpanClass = oClasses.sSortJUIAsc;
+ }
+ else
+ {
+ sSpanClass = oClasses.sSortJUIDesc;
+ }
+
+ jqSpan.addClass( sSpanClass );
+ }
+ }
+ else
+ {
+ /* No sorting on this column, so add the base class. This will have been assigned by
+ * _fnAddColumn
+ */
+ $(oSettings.aoColumns[i].nTh).addClass( oSettings.aoColumns[i].sSortingClass );
+ }
+ }
+
+ /*
+ * Apply the required classes to the table body
+ * Note that this is given as a feature switch since it can significantly slow down a sort
+ * on large data sets (adding and removing of classes is always slow at the best of times..)
+ * Further to this, note that this code is admittedly fairly ugly. It could be made a lot
+ * simpler using jQuery selectors and add/removeClass, but that is significantly slower
+ * (on the order of 5 times slower) - hence the direct DOM manipulation here.
+ * Note that for deferred drawing we do use jQuery - the reason being that taking the first
+ * row found to see if the whole column needs processed can miss classes since the first
+ * column might be new.
+ */
+ sClass = oClasses.sSortColumn;
+
+ if ( oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses )
+ {
+ var nTds = _fnGetTdNodes( oSettings );
+
+ /* Determine what the sorting class for each column should be */
+ var iClass, iTargetCol;
+ var asClasses = [];
+ for (i = 0; i < iColumns; i++)
+ {
+ asClasses.push("");
+ }
+ for (i = 0, iClass = 1; i < aaSort.length; i++)
+ {
+ iTargetCol = parseInt( aaSort[i][0], 10 );
+ asClasses[iTargetCol] = sClass + iClass;
+
+ if ( iClass < 3 )
+ {
+ iClass++;
+ }
+ }
+
+ /* Make changes to the classes for each cell as needed */
+ var reClass = new RegExp(sClass + "[123]");
+ var sTmpClass, sCurrentClass, sNewClass;
+ for ( i=0, iLen=nTds.length; i<iLen; i++ )
+ {
+ /* Determine which column we're looking at */
+ iTargetCol = i % iColumns;
+
+ /* What is the full list of classes now */
+ sCurrentClass = nTds[i].className;
+ /* What sorting class should be applied? */
+ sNewClass = asClasses[iTargetCol];
+ /* What would the new full list be if we did a replacement? */
+ sTmpClass = sCurrentClass.replace(reClass, sNewClass);
+
+ if ( sTmpClass != sCurrentClass )
+ {
+ /* We changed something */
+ nTds[i].className = $.trim( sTmpClass );
+ }
+ else if ( sNewClass.length > 0 && sCurrentClass.indexOf(sNewClass) == -1 )
+ {
+ /* We need to add a class */
+ nTds[i].className = sCurrentClass + " " + sNewClass;
+ }
+ }
+ }
+ }
+
+
+
+ /**
+ * Save the state of a table in a cookie such that the page can be reloaded
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnSaveState ( oSettings )
+ {
+ if ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying )
+ {
+ return;
+ }
+
+ /* Store the interesting variables */
+ var i, iLen, bInfinite=oSettings.oScroll.bInfinite;
+ var oState = {
+ "iCreate": new Date().getTime(),
+ "iStart": (bInfinite ? 0 : oSettings._iDisplayStart),
+ "iEnd": (bInfinite ? oSettings._iDisplayLength : oSettings._iDisplayEnd),
+ "iLength": oSettings._iDisplayLength,
+ "aaSorting": $.extend( true, [], oSettings.aaSorting ),
+ "oSearch": $.extend( true, {}, oSettings.oPreviousSearch ),
+ "aoSearchCols": $.extend( true, [], oSettings.aoPreSearchCols ),
+ "abVisCols": []
+ };
+
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ oState.abVisCols.push( oSettings.aoColumns[i].bVisible );
+ }
+
+ _fnCallbackFire( oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState] );
+
+ oSettings.fnStateSave.call( oSettings.oInstance, oSettings, oState );
+ }
+
+
+ /**
+ * Attempt to load a saved table state from a cookie
+ * @param {object} oSettings dataTables settings object
+ * @param {object} oInit DataTables init object so we can override settings
+ * @memberof DataTable#oApi
+ */
+ function _fnLoadState ( oSettings, oInit )
+ {
+ if ( !oSettings.oFeatures.bStateSave )
+ {
+ return;
+ }
+
+ var oData = oSettings.fnStateLoad.call( oSettings.oInstance, oSettings );
+ if ( !oData )
+ {
+ return;
+ }
+
+ /* Allow custom and plug-in manipulation functions to alter the saved data set and
+ * cancelling of loading by returning false
+ */
+ var abStateLoad = _fnCallbackFire( oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData] );
+ if ( $.inArray( false, abStateLoad ) !== -1 )
+ {
+ return;
+ }
+
+ /* Store the saved state so it might be accessed at any time */
+ oSettings.oLoadedState = $.extend( true, {}, oData );
+
+ /* Restore key features */
+ oSettings._iDisplayStart = oData.iStart;
+ oSettings.iInitDisplayStart = oData.iStart;
+ oSettings._iDisplayEnd = oData.iEnd;
+ oSettings._iDisplayLength = oData.iLength;
+ oSettings.aaSorting = oData.aaSorting.slice();
+ oSettings.saved_aaSorting = oData.aaSorting.slice();
+
+ /* Search filtering */
+ $.extend( oSettings.oPreviousSearch, oData.oSearch );
+ $.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols );
+
+ /* Column visibility state
+ * Pass back visibility settings to the init handler, but to do not here override
+ * the init object that the user might have passed in
+ */
+ oInit.saved_aoColumns = [];
+ for ( var i=0 ; i<oData.abVisCols.length ; i++ )
+ {
+ oInit.saved_aoColumns[i] = {};
+ oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i];
+ }
+
+ _fnCallbackFire( oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData] );
+ }
+
+
+ /**
+ * Create a new cookie with a value to store the state of a table
+ * @param {string} sName name of the cookie to create
+ * @param {string} sValue the value the cookie should take
+ * @param {int} iSecs duration of the cookie
+ * @param {string} sBaseName sName is made up of the base + file name - this is the base
+ * @param {function} fnCallback User definable function to modify the cookie
+ * @memberof DataTable#oApi
+ */
+ function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )
+ {
+ var date = new Date();
+ date.setTime( date.getTime()+(iSecs*1000) );
+
+ /*
+ * Shocking but true - it would appear IE has major issues with having the path not having
+ * a trailing slash on it. We need the cookie to be available based on the path, so we
+ * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
+ * patch to use at least some of the path
+ */
+ var aParts = window.location.pathname.split('/');
+ var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
+ var sFullCookie, oData;
+
+ if ( fnCallback !== null )
+ {
+ oData = (typeof $.parseJSON === 'function') ?
+ $.parseJSON( sValue ) : eval( '('+sValue+')' );
+ sFullCookie = fnCallback( sNameFile, oData, date.toGMTString(),
+ aParts.join('/')+"/" );
+ }
+ else
+ {
+ sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) +
+ "; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/";
+ }
+
+ /* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies
+ * belonging to DataTables.
+ */
+ var
+ aCookies =document.cookie.split(';'),
+ iNewCookieLen = sFullCookie.split(';')[0].length,
+ aOldCookies = [];
+
+ if ( iNewCookieLen+document.cookie.length+10 > 4096 ) /* Magic 10 for padding */
+ {
+ for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )
+ {
+ if ( aCookies[i].indexOf( sBaseName ) != -1 )
+ {
+ /* It's a DataTables cookie, so eval it and check the time stamp */
+ var aSplitCookie = aCookies[i].split('=');
+ try {
+ oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' );
+
+ if ( oData && oData.iCreate )
+ {
+ aOldCookies.push( {
+ "name": aSplitCookie[0],
+ "time": oData.iCreate
+ } );
+ }
+ }
+ catch( e ) {}
+ }
+ }
+
+ // Make sure we delete the oldest ones first
+ aOldCookies.sort( function (a, b) {
+ return b.time - a.time;
+ } );
+
+ // Eliminate as many old DataTables cookies as we need to
+ while ( iNewCookieLen + document.cookie.length + 10 > 4096 ) {
+ if ( aOldCookies.length === 0 ) {
+ // Deleted all DT cookies and still not enough space. Can't state save
+ return;
+ }
+
+ var old = aOldCookies.pop();
+ document.cookie = old.name+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
+ aParts.join('/') + "/";
+ }
+ }
+
+ document.cookie = sFullCookie;
+ }
+
+
+ /**
+ * Read an old cookie to get a cookie with an old table state
+ * @param {string} sName name of the cookie to read
+ * @returns {string} contents of the cookie - or null if no cookie with that name found
+ * @memberof DataTable#oApi
+ */
+ function _fnReadCookie ( sName )
+ {
+ var
+ aParts = window.location.pathname.split('/'),
+ sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=',
+ sCookieContents = document.cookie.split(';');
+
+ for( var i=0 ; i<sCookieContents.length ; i++ )
+ {
+ var c = sCookieContents[i];
+
+ while (c.charAt(0)==' ')
+ {
+ c = c.substring(1,c.length);
+ }
+
+ if (c.indexOf(sNameEQ) === 0)
+ {
+ return decodeURIComponent( c.substring(sNameEQ.length,c.length) );
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Return the settings object for a particular table
+ * @param {node} nTable table we are using as a dataTable
+ * @returns {object} Settings object - or null if not found
+ * @memberof DataTable#oApi
+ */
+ function _fnSettingsFromNode ( nTable )
+ {
+ for ( var i=0 ; i<DataTable.settings.length ; i++ )
+ {
+ if ( DataTable.settings[i].nTable === nTable )
+ {
+ return DataTable.settings[i];
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Return an array with the TR nodes for the table
+ * @param {object} oSettings dataTables settings object
+ * @returns {array} TR array
+ * @memberof DataTable#oApi
+ */
+ function _fnGetTrNodes ( oSettings )
+ {
+ var aNodes = [];
+ var aoData = oSettings.aoData;
+ for ( var i=0, iLen=aoData.length ; i<iLen ; i++ )
+ {
+ if ( aoData[i].nTr !== null )
+ {
+ aNodes.push( aoData[i].nTr );
+ }
+ }
+ return aNodes;
+ }
+
+
+ /**
+ * Return an flat array with all TD nodes for the table, or row
+ * @param {object} oSettings dataTables settings object
+ * @param {int} [iIndividualRow] aoData index to get the nodes for - optional
+ * if not given then the return array will contain all nodes for the table
+ * @returns {array} TD array
+ * @memberof DataTable#oApi
+ */
+ function _fnGetTdNodes ( oSettings, iIndividualRow )
+ {
+ var anReturn = [];
+ var iCorrector;
+ var anTds, nTd;
+ var iRow, iRows=oSettings.aoData.length,
+ iColumn, iColumns, oData, sNodeName, iStart=0, iEnd=iRows;
+
+ /* Allow the collection to be limited to just one row */
+ if ( iIndividualRow !== undefined )
+ {
+ iStart = iIndividualRow;
+ iEnd = iIndividualRow+1;
+ }
+
+ for ( iRow=iStart ; iRow<iEnd ; iRow++ )
+ {
+ oData = oSettings.aoData[iRow];
+ if ( oData.nTr !== null )
+ {
+ /* get the TD child nodes - taking into account text etc nodes */
+ anTds = [];
+ nTd = oData.nTr.firstChild;
+ while ( nTd )
+ {
+ sNodeName = nTd.nodeName.toLowerCase();
+ if ( sNodeName == 'td' || sNodeName == 'th' )
+ {
+ anTds.push( nTd );
+ }
+ nTd = nTd.nextSibling;
+ }
+
+ iCorrector = 0;
+ for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
+ {
+ if ( oSettings.aoColumns[iColumn].bVisible )
+ {
+ anReturn.push( anTds[iColumn-iCorrector] );
+ }
+ else
+ {
+ anReturn.push( oData._anHidden[iColumn] );
+ iCorrector++;
+ }
+ }
+ }
+ }
+
+ return anReturn;
+ }
+
+
+ /**
+ * Log an error message
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iLevel log error messages, or display them to the user
+ * @param {string} sMesg error message
+ * @memberof DataTable#oApi
+ */
+ function _fnLog( oSettings, iLevel, sMesg )
+ {
+ var sAlert = (oSettings===null) ?
+ "DataTables warning: "+sMesg :
+ "DataTables warning (table id = '"+oSettings.sTableId+"'): "+sMesg;
+
+ if ( iLevel === 0 )
+ {
+ if ( DataTable.ext.sErrMode == 'alert' )
+ {
+ alert( sAlert );
+ }
+ else
+ {
+ throw new Error(sAlert);
+ }
+ return;
+ }
+ else if ( window.console && console.log )
+ {
+ console.log( sAlert );
+ }
+ }
+
+
+ /**
+ * See if a property is defined on one object, if so assign it to the other object
+ * @param {object} oRet target object
+ * @param {object} oSrc source object
+ * @param {string} sName property
+ * @param {string} [sMappedName] name to map too - optional, sName used if not given
+ * @memberof DataTable#oApi
+ */
+ function _fnMap( oRet, oSrc, sName, sMappedName )
+ {
+ if ( sMappedName === undefined )
+ {
+ sMappedName = sName;
+ }
+ if ( oSrc[sName] !== undefined )
+ {
+ oRet[sMappedName] = oSrc[sName];
+ }
+ }
+
+
+ /**
+ * Extend objects - very similar to jQuery.extend, but deep copy objects, and shallow
+ * copy arrays. The reason we need to do this, is that we don't want to deep copy array
+ * init values (such as aaSorting) since the dev wouldn't be able to override them, but
+ * we do want to deep copy arrays.
+ * @param {object} oOut Object to extend
+ * @param {object} oExtender Object from which the properties will be applied to oOut
+ * @returns {object} oOut Reference, just for convenience - oOut === the return.
+ * @memberof DataTable#oApi
+ * @todo This doesn't take account of arrays inside the deep copied objects.
+ */
+ function _fnExtend( oOut, oExtender )
+ {
+ var val;
+
+ for ( var prop in oExtender )
+ {
+ if ( oExtender.hasOwnProperty(prop) )
+ {
+ val = oExtender[prop];
+
+ if ( typeof oInit[prop] === 'object' && val !== null && $.isArray(val) === false )
+ {
+ $.extend( true, oOut[prop], val );
+ }
+ else
+ {
+ oOut[prop] = val;
+ }
+ }
+ }
+
+ return oOut;
+ }
+
+
+ /**
+ * Bind an event handers to allow a click or return key to activate the callback.
+ * This is good for accessibility since a return on the keyboard will have the
+ * same effect as a click, if the element has focus.
+ * @param {element} n Element to bind the action to
+ * @param {object} oData Data object to pass to the triggered function
+ * @param {function} fn Callback function for when the event is triggered
+ * @memberof DataTable#oApi
+ */
+ function _fnBindAction( n, oData, fn )
+ {
+ $(n)
+ .bind( 'click.DT', oData, function (e) {
+ n.blur(); // Remove focus outline for mouse users
+ fn(e);
+ } )
+ .bind( 'keypress.DT', oData, function (e){
+ if ( e.which === 13 ) {
+ fn(e);
+ } } )
+ .bind( 'selectstart.DT', function () {
+ /* Take the brutal approach to cancelling text selection */
+ return false;
+ } );
+ }
+
+
+ /**
+ * Register a callback function. Easily allows a callback function to be added to
+ * an array store of callback functions that can then all be called together.
+ * @param {object} oSettings dataTables settings object
+ * @param {string} sStore Name of the array storage for the callbacks in oSettings
+ * @param {function} fn Function to be called back
+ * @param {string} sName Identifying name for the callback (i.e. a label)
+ * @memberof DataTable#oApi
+ */
+ function _fnCallbackReg( oSettings, sStore, fn, sName )
+ {
+ if ( fn )
+ {
+ oSettings[sStore].push( {
+ "fn": fn,
+ "sName": sName
+ } );
+ }
+ }
+
+
+ /**
+ * Fire callback functions and trigger events. Note that the loop over the callback
+ * array store is done backwards! Further note that you do not want to fire off triggers
+ * in time sensitive applications (for example cell creation) as its slow.
+ * @param {object} oSettings dataTables settings object
+ * @param {string} sStore Name of the array storage for the callbacks in oSettings
+ * @param {string} sTrigger Name of the jQuery custom event to trigger. If null no trigger
+ * is fired
+ * @param {array} aArgs Array of arguments to pass to the callback function / trigger
+ * @memberof DataTable#oApi
+ */
+ function _fnCallbackFire( oSettings, sStore, sTrigger, aArgs )
+ {
+ var aoStore = oSettings[sStore];
+ var aRet =[];
+
+ for ( var i=aoStore.length-1 ; i>=0 ; i-- )
+ {
+ aRet.push( aoStore[i].fn.apply( oSettings.oInstance, aArgs ) );
+ }
+
+ if ( sTrigger !== null )
+ {
+ $(oSettings.oInstance).trigger(sTrigger, aArgs);
+ }
+
+ return aRet;
+ }
+
+
+ /**
+ * JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other
+ * library, then we use that as it is fast, safe and accurate. If the function isn't
+ * available then we need to built it ourselves - the inspiration for this function comes
+ * from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is
+ * not perfect and absolutely should not be used as a replacement to json2.js - but it does
+ * do what we need, without requiring a dependency for DataTables.
+ * @param {object} o JSON object to be converted
+ * @returns {string} JSON string
+ * @memberof DataTable#oApi
+ */
+ var _fnJsonString = (window.JSON) ? JSON.stringify : function( o )
+ {
+ /* Not an object or array */
+ var sType = typeof o;
+ if (sType !== "object" || o === null)
+ {
+ // simple data type
+ if (sType === "string")
+ {
+ o = '"'+o+'"';
+ }
+ return o+"";
+ }
+
+ /* If object or array, need to recurse over it */
+ var
+ sProp, mValue,
+ json = [],
+ bArr = $.isArray(o);
+
+ for (sProp in o)
+ {
+ mValue = o[sProp];
+ sType = typeof mValue;
+
+ if (sType === "string")
+ {
+ mValue = '"'+mValue+'"';
+ }
+ else if (sType === "object" && mValue !== null)
+ {
+ mValue = _fnJsonString(mValue);
+ }
+
+ json.push((bArr ? "" : '"'+sProp+'":') + mValue);
+ }
+
+ return (bArr ? "[" : "{") + json + (bArr ? "]" : "}");
+ };
+
+
+ /**
+ * From some browsers (specifically IE6/7) we need special handling to work around browser
+ * bugs - this function is used to detect when these workarounds are needed.
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnBrowserDetect( oSettings )
+ {
+ /* IE6/7 will oversize a width 100% element inside a scrolling element, to include the
+ * width of the scrollbar, while other browsers ensure the inner element is contained
+ * without forcing scrolling
+ */
+ var n = $(
+ '<div style="position:absolute; top:0; left:0; height:1px; width:1px; overflow:hidden">'+
+ '<div style="position:absolute; top:1px; left:1px; width:100px; overflow:scroll;">'+
+ '<div id="DT_BrowserTest" style="width:100%; height:10px;"></div>'+
+ '</div>'+
+ '</div>')[0];
+
+ document.body.appendChild( n );
+ oSettings.oBrowser.bScrollOversize = $('#DT_BrowserTest', n)[0].offsetWidth === 100 ? true : false;
+ document.body.removeChild( n );
+ }
+
+
+ /**
+ * Perform a jQuery selector action on the table's TR elements (from the tbody) and
+ * return the resulting jQuery object.
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
+ * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
+ * criterion ("applied") or all TR elements (i.e. no filter).
+ * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
+ * Can be either 'current', whereby the current sorting of the table is used, or
+ * 'original' whereby the original order the data was read into the table is used.
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
+ * 'current' and filter is 'applied', regardless of what they might be given as.
+ * @returns {object} jQuery object, filtered by the given selector.
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Highlight every second row
+ * oTable.$('tr:odd').css('backgroundColor', 'blue');
+ * } );
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Filter to rows with 'Webkit' in them, add a background colour and then
+ * // remove the filter, thus highlighting the 'Webkit' rows only.
+ * oTable.fnFilter('Webkit');
+ * oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue');
+ * oTable.fnFilter('');
+ * } );
+ */
+ this.$ = function ( sSelector, oOpts )
+ {
+ var i, iLen, a = [], tr;
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var aoData = oSettings.aoData;
+ var aiDisplay = oSettings.aiDisplay;
+ var aiDisplayMaster = oSettings.aiDisplayMaster;
+
+ if ( !oOpts )
+ {
+ oOpts = {};
+ }
+
+ oOpts = $.extend( {}, {
+ "filter": "none", // applied
+ "order": "current", // "original"
+ "page": "all" // current
+ }, oOpts );
+
+ // Current page implies that order=current and fitler=applied, since it is fairly
+ // senseless otherwise
+ if ( oOpts.page == 'current' )
+ {
+ for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i<iLen ; i++ )
+ {
+ tr = aoData[ aiDisplay[i] ].nTr;
+ if ( tr )
+ {
+ a.push( tr );
+ }
+ }
+ }
+ else if ( oOpts.order == "current" && oOpts.filter == "none" )
+ {
+ for ( i=0, iLen=aiDisplayMaster.length ; i<iLen ; i++ )
+ {
+ tr = aoData[ aiDisplayMaster[i] ].nTr;
+ if ( tr )
+ {
+ a.push( tr );
+ }
+ }
+ }
+ else if ( oOpts.order == "current" && oOpts.filter == "applied" )
+ {
+ for ( i=0, iLen=aiDisplay.length ; i<iLen ; i++ )
+ {
+ tr = aoData[ aiDisplay[i] ].nTr;
+ if ( tr )
+ {
+ a.push( tr );
+ }
+ }
+ }
+ else if ( oOpts.order == "original" && oOpts.filter == "none" )
+ {
+ for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+ {
+ tr = aoData[ i ].nTr ;
+ if ( tr )
+ {
+ a.push( tr );
+ }
+ }
+ }
+ else if ( oOpts.order == "original" && oOpts.filter == "applied" )
+ {
+ for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+ {
+ tr = aoData[ i ].nTr;
+ if ( $.inArray( i, aiDisplay ) !== -1 && tr )
+ {
+ a.push( tr );
+ }
+ }
+ }
+ else
+ {
+ _fnLog( oSettings, 1, "Unknown selection options" );
+ }
+
+ /* We need to filter on the TR elements and also 'find' in their descendants
+ * to make the selector act like it would in a full table - so we need
+ * to build both results and then combine them together
+ */
+ var jqA = $(a);
+ var jqTRs = jqA.filter( sSelector );
+ var jqDescendants = jqA.find( sSelector );
+
+ return $( [].concat($.makeArray(jqTRs), $.makeArray(jqDescendants)) );
+ };
+
+
+ /**
+ * Almost identical to $ in operation, but in this case returns the data for the matched
+ * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
+ * rather than any descendants, so the data can be obtained for the row/cell. If matching
+ * rows are found, the data returned is the original data array/object that was used to
+ * create the row (or a generated array if from a DOM source).
+ *
+ * This method is often useful in-combination with $ where both functions are given the
+ * same parameters and the array indexes will match identically.
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
+ * @param {string} [oOpts.filter=none] Select elements that meet the current filter
+ * criterion ("applied") or all elements (i.e. no filter).
+ * @param {string} [oOpts.order=current] Order of the data in the processed array.
+ * Can be either 'current', whereby the current sorting of the table is used, or
+ * 'original' whereby the original order the data was read into the table is used.
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
+ * 'current' and filter is 'applied', regardless of what they might be given as.
+ * @returns {array} Data for the matched elements. If any elements, as a result of the
+ * selector, were not TR, TD or TH elements in the DataTable, they will have a null
+ * entry in the array.
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Get the data from the first row in the table
+ * var data = oTable._('tr:first');
+ *
+ * // Do something useful with the data
+ * alert( "First cell is: "+data[0] );
+ * } );
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Filter to 'Webkit' and get all data for
+ * oTable.fnFilter('Webkit');
+ * var data = oTable._('tr', {"filter": "applied"});
+ *
+ * // Do something with the data
+ * alert( data.length+" rows matched the filter" );
+ * } );
+ */
+ this._ = function ( sSelector, oOpts )
+ {
+ var aOut = [];
+ var i, iLen, iIndex;
+ var aTrs = this.$( sSelector, oOpts );
+
+ for ( i=0, iLen=aTrs.length ; i<iLen ; i++ )
+ {
+ aOut.push( this.fnGetData(aTrs[i]) );
+ }
+
+ return aOut;
+ };
+
+
+ /**
+ * Add a single new row or multiple rows of data to the table. Please note
+ * that this is suitable for client-side processing only - if you are using
+ * server-side processing (i.e. "bServerSide": true), then to add data, you
+ * must add it to the data source, i.e. the server-side, through an Ajax call.
+ * @param {array|object} mData The data to be added to the table. This can be:
+ * <ul>
+ * <li>1D array of data - add a single row with the data provided</li>
+ * <li>2D array of arrays - add multiple rows in a single call</li>
+ * <li>object - data object when using <i>mData</i></li>
+ * <li>array of objects - multiple data objects when using <i>mData</i></li>
+ * </ul>
+ * @param {bool} [bRedraw=true] redraw the table or not
+ * @returns {array} An array of integers, representing the list of indexes in
+ * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
+ * the table.
+ * @dtopt API
+ *
+ * @example
+ * // Global var for counter
+ * var giCount = 2;
+ *
+ * $(document).ready(function() {
+ * $('#example').dataTable();
+ * } );
+ *
+ * function fnClickAddRow() {
+ * $('#example').dataTable().fnAddData( [
+ * giCount+".1",
+ * giCount+".2",
+ * giCount+".3",
+ * giCount+".4" ]
+ * );
+ *
+ * giCount++;
+ * }
+ */
+ this.fnAddData = function( mData, bRedraw )
+ {
+ if ( mData.length === 0 )
+ {
+ return [];
+ }
+
+ var aiReturn = [];
+ var iTest;
+
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+
+ /* Check if we want to add multiple rows or not */
+ if ( typeof mData[0] === "object" && mData[0] !== null )
+ {
+ for ( var i=0 ; i<mData.length ; i++ )
+ {
+ iTest = _fnAddData( oSettings, mData[i] );
+ if ( iTest == -1 )
+ {
+ return aiReturn;
+ }
+ aiReturn.push( iTest );
+ }
+ }
+ else
+ {
+ iTest = _fnAddData( oSettings, mData );
+ if ( iTest == -1 )
+ {
+ return aiReturn;
+ }
+ aiReturn.push( iTest );
+ }
+
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+
+ if ( bRedraw === undefined || bRedraw )
+ {
+ _fnReDraw( oSettings );
+ }
+ return aiReturn;
+ };
+
+
+ /**
+ * This function will make DataTables recalculate the column sizes, based on the data
+ * contained in the table and the sizes applied to the columns (in the DOM, CSS or
+ * through the sWidth parameter). This can be useful when the width of the table's
+ * parent element changes (for example a window resize).
+ * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable( {
+ * "sScrollY": "200px",
+ * "bPaginate": false
+ * } );
+ *
+ * $(window).bind('resize', function () {
+ * oTable.fnAdjustColumnSizing();
+ * } );
+ * } );
+ */
+ this.fnAdjustColumnSizing = function ( bRedraw )
+ {
+ var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]);
+ _fnAdjustColumnSizing( oSettings );
+
+ if ( bRedraw === undefined || bRedraw )
+ {
+ this.fnDraw( false );
+ }
+ else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
+ {
+ /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
+ this.oApi._fnScrollDraw(oSettings);
+ }
+ };
+
+
+ /**
+ * Quickly and simply clear a table
+ * @param {bool} [bRedraw=true] redraw the table or not
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
+ * oTable.fnClearTable();
+ * } );
+ */
+ this.fnClearTable = function( bRedraw )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ _fnClearTable( oSettings );
+
+ if ( bRedraw === undefined || bRedraw )
+ {
+ _fnDraw( oSettings );
+ }
+ };
+
+
+ /**
+ * The exact opposite of 'opening' a row, this function will close any rows which
+ * are currently 'open'.
+ * @param {node} nTr the table row to 'close'
+ * @returns {int} 0 on success, or 1 if failed (can't find the row)
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable;
+ *
+ * // 'open' an information row when a row is clicked on
+ * $('#example tbody tr').click( function () {
+ * if ( oTable.fnIsOpen(this) ) {
+ * oTable.fnClose( this );
+ * } else {
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
+ * }
+ * } );
+ *
+ * oTable = $('#example').dataTable();
+ * } );
+ */
+ this.fnClose = function( nTr )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+
+ for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
+ {
+ if ( oSettings.aoOpenRows[i].nParent == nTr )
+ {
+ var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;
+ if ( nTrParent )
+ {
+ /* Remove it if it is currently on display */
+ nTrParent.removeChild( oSettings.aoOpenRows[i].nTr );
+ }
+ oSettings.aoOpenRows.splice( i, 1 );
+ return 0;
+ }
+ }
+ return 1;
+ };
+
+
+ /**
+ * Remove a row for the table
+ * @param {mixed} mTarget The index of the row from aoData to be deleted, or
+ * the TR element you want to delete
+ * @param {function|null} [fnCallBack] Callback function
+ * @param {bool} [bRedraw=true] Redraw the table or not
+ * @returns {array} The row that was deleted
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Immediately remove the first row
+ * oTable.fnDeleteRow( 0 );
+ * } );
+ */
+ this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var i, iLen, iAODataIndex;
+
+ iAODataIndex = (typeof mTarget === 'object') ?
+ _fnNodeToDataIndex(oSettings, mTarget) : mTarget;
+
+ /* Return the data array from this row */
+ var oData = oSettings.aoData.splice( iAODataIndex, 1 );
+
+ /* Update the _DT_RowIndex parameter */
+ for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+ {
+ if ( oSettings.aoData[i].nTr !== null )
+ {
+ oSettings.aoData[i].nTr._DT_RowIndex = i;
+ }
+ }
+
+ /* Remove the target row from the search array */
+ var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay );
+ oSettings.asDataSearch.splice( iDisplayIndex, 1 );
+
+ /* Delete from the display arrays */
+ _fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );
+ _fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );
+
+ /* If there is a user callback function - call it */
+ if ( typeof fnCallBack === "function" )
+ {
+ fnCallBack.call( this, oSettings, oData );
+ }
+
+ /* Check for an 'overflow' they case for displaying the table */
+ if ( oSettings._iDisplayStart >= oSettings.fnRecordsDisplay() )
+ {
+ oSettings._iDisplayStart -= oSettings._iDisplayLength;
+ if ( oSettings._iDisplayStart < 0 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+
+ if ( bRedraw === undefined || bRedraw )
+ {
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+
+ return oData;
+ };
+
+
+ /**
+ * Restore the table to it's original state in the DOM by removing all of DataTables
+ * enhancements, alterations to the DOM structure of the table and event listeners.
+ * @param {boolean} [bRemove=false] Completely remove the table from the DOM
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * // This example is fairly pointless in reality, but shows how fnDestroy can be used
+ * var oTable = $('#example').dataTable();
+ * oTable.fnDestroy();
+ * } );
+ */
+ this.fnDestroy = function ( bRemove )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var nOrig = oSettings.nTableWrapper.parentNode;
+ var nBody = oSettings.nTBody;
+ var i, iLen;
+
+ bRemove = (bRemove===undefined) ? false : bRemove;
+
+ /* Flag to note that the table is currently being destroyed - no action should be taken */
+ oSettings.bDestroying = true;
+
+ /* Fire off the destroy callbacks for plug-ins etc */
+ _fnCallbackFire( oSettings, "aoDestroyCallback", "destroy", [oSettings] );
+
+ /* If the table is not being removed, restore the hidden columns */
+ if ( !bRemove )
+ {
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ if ( oSettings.aoColumns[i].bVisible === false )
+ {
+ this.fnSetColumnVis( i, true );
+ }
+ }
+ }
+
+ /* Blitz all DT events */
+ $(oSettings.nTableWrapper).find('*').andSelf().unbind('.DT');
+
+ /* If there is an 'empty' indicator row, remove it */
+ $('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();
+
+ /* When scrolling we had to break the table up - restore it */
+ if ( oSettings.nTable != oSettings.nTHead.parentNode )
+ {
+ $(oSettings.nTable).children('thead').remove();
+ oSettings.nTable.appendChild( oSettings.nTHead );
+ }
+
+ if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )
+ {
+ $(oSettings.nTable).children('tfoot').remove();
+ oSettings.nTable.appendChild( oSettings.nTFoot );
+ }
+
+ /* Remove the DataTables generated nodes, events and classes */
+ oSettings.nTable.parentNode.removeChild( oSettings.nTable );
+ $(oSettings.nTableWrapper).remove();
+
+ oSettings.aaSorting = [];
+ oSettings.aaSortingFixed = [];
+ _fnSortingClasses( oSettings );
+
+ $(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') );
+
+ $('th, td', oSettings.nTHead).removeClass( [
+ oSettings.oClasses.sSortable,
+ oSettings.oClasses.sSortableAsc,
+ oSettings.oClasses.sSortableDesc,
+ oSettings.oClasses.sSortableNone ].join(' ')
+ );
+ if ( oSettings.bJUI )
+ {
+ $('th span.'+oSettings.oClasses.sSortIcon
+ + ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove();
+
+ $('th, td', oSettings.nTHead).each( function () {
+ var jqWrapper = $('div.'+oSettings.oClasses.sSortJUIWrapper, this);
+ var kids = jqWrapper.contents();
+ $(this).append( kids );
+ jqWrapper.remove();
+ } );
+ }
+
+ /* Add the TR elements back into the table in their original order */
+ if ( !bRemove && oSettings.nTableReinsertBefore )
+ {
+ nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore );
+ }
+ else if ( !bRemove )
+ {
+ nOrig.appendChild( oSettings.nTable );
+ }
+
+ for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+ {
+ if ( oSettings.aoData[i].nTr !== null )
+ {
+ nBody.appendChild( oSettings.aoData[i].nTr );
+ }
+ }
+
+ /* Restore the width of the original table */
+ if ( oSettings.oFeatures.bAutoWidth === true )
+ {
+ oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);
+ }
+
+ /* If the were originally stripe classes - then we add them back here. Note
+ * this is not fool proof (for example if not all rows had stripe classes - but
+ * it's a good effort without getting carried away
+ */
+ iLen = oSettings.asDestroyStripes.length;
+ if (iLen)
+ {
+ var anRows = $(nBody).children('tr');
+ for ( i=0 ; i<iLen ; i++ )
+ {
+ anRows.filter(':nth-child(' + iLen + 'n + ' + i + ')').addClass( oSettings.asDestroyStripes[i] );
+ }
+ }
+
+ /* Remove the settings object from the settings array */
+ for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
+ {
+ if ( DataTable.settings[i] == oSettings )
+ {
+ DataTable.settings.splice( i, 1 );
+ }
+ }
+
+ /* End it all */
+ oSettings = null;
+ oInit = null;
+ };
+
+
+ /**
+ * Redraw the table
+ * @param {bool} [bComplete=true] Re-filter and resort (if enabled) the table before the draw.
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
+ * oTable.fnDraw();
+ * } );
+ */
+ this.fnDraw = function( bComplete )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ if ( bComplete === false )
+ {
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+ else
+ {
+ _fnReDraw( oSettings );
+ }
+ };
+
+
+ /**
+ * Filter the input based on data
+ * @param {string} sInput String to filter the table on
+ * @param {int|null} [iColumn] Column to limit filtering to
+ * @param {bool} [bRegex=false] Treat as regular expression or not
+ * @param {bool} [bSmart=true] Perform smart filtering or not
+ * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
+ * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Sometime later - filter...
+ * oTable.fnFilter( 'test string' );
+ * } );
+ */
+ this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+
+ if ( !oSettings.oFeatures.bFilter )
+ {
+ return;
+ }
+
+ if ( bRegex === undefined || bRegex === null )
+ {
+ bRegex = false;
+ }
+
+ if ( bSmart === undefined || bSmart === null )
+ {
+ bSmart = true;
+ }
+
+ if ( bShowGlobal === undefined || bShowGlobal === null )
+ {
+ bShowGlobal = true;
+ }
+
+ if ( bCaseInsensitive === undefined || bCaseInsensitive === null )
+ {
+ bCaseInsensitive = true;
+ }
+
+ if ( iColumn === undefined || iColumn === null )
+ {
+ /* Global filter */
+ _fnFilterComplete( oSettings, {
+ "sSearch":sInput+"",
+ "bRegex": bRegex,
+ "bSmart": bSmart,
+ "bCaseInsensitive": bCaseInsensitive
+ }, 1 );
+
+ if ( bShowGlobal && oSettings.aanFeatures.f )
+ {
+ var n = oSettings.aanFeatures.f;
+ for ( var i=0, iLen=n.length ; i<iLen ; i++ )
+ {
+ // IE9 throws an 'unknown error' if document.activeElement is used
+ // inside an iframe or frame...
+ try {
+ if ( n[i]._DT_Input != document.activeElement )
+ {
+ $(n[i]._DT_Input).val( sInput );
+ }
+ }
+ catch ( e ) {
+ $(n[i]._DT_Input).val( sInput );
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Single column filter */
+ $.extend( oSettings.aoPreSearchCols[ iColumn ], {
+ "sSearch": sInput+"",
+ "bRegex": bRegex,
+ "bSmart": bSmart,
+ "bCaseInsensitive": bCaseInsensitive
+ } );
+ _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
+ }
+ };
+
+
+ /**
+ * Get the data for the whole table, an individual row or an individual cell based on the
+ * provided parameters.
+ * @param {int|node} [mRow] A TR row node, TD/TH cell node or an integer. If given as
+ * a TR node then the data source for the whole row will be returned. If given as a
+ * TD/TH cell node then iCol will be automatically calculated and the data for the
+ * cell returned. If given as an integer, then this is treated as the aoData internal
+ * data index for the row (see fnGetPosition) and the data for that row used.
+ * @param {int} [iCol] Optional column index that you want the data of.
+ * @returns {array|object|string} If mRow is undefined, then the data for all rows is
+ * returned. If mRow is defined, just data for that row, and is iCol is
+ * defined, only data for the designated cell is returned.
+ * @dtopt API
+ *
+ * @example
+ * // Row data
+ * $(document).ready(function() {
+ * oTable = $('#example').dataTable();
+ *
+ * oTable.$('tr').click( function () {
+ * var data = oTable.fnGetData( this );
+ * // ... do something with the array / object of data for the row
+ * } );
+ * } );
+ *
+ * @example
+ * // Individual cell data
+ * $(document).ready(function() {
+ * oTable = $('#example').dataTable();
+ *
+ * oTable.$('td').click( function () {
+ * var sData = oTable.fnGetData( this );
+ * alert( 'The cell clicked on had the value of '+sData );
+ * } );
+ * } );
+ */
+ this.fnGetData = function( mRow, iCol )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+
+ if ( mRow !== undefined )
+ {
+ var iRow = mRow;
+ if ( typeof mRow === 'object' )
+ {
+ var sNode = mRow.nodeName.toLowerCase();
+ if (sNode === "tr" )
+ {
+ iRow = _fnNodeToDataIndex(oSettings, mRow);
+ }
+ else if ( sNode === "td" )
+ {
+ iRow = _fnNodeToDataIndex(oSettings, mRow.parentNode);
+ iCol = _fnNodeToColumnIndex( oSettings, iRow, mRow );
+ }
+ }
+
+ if ( iCol !== undefined )
+ {
+ return _fnGetCellData( oSettings, iRow, iCol, '' );
+ }
+ return (oSettings.aoData[iRow]!==undefined) ?
+ oSettings.aoData[iRow]._aData : null;
+ }
+ return _fnGetDataMaster( oSettings );
+ };
+
+
+ /**
+ * Get an array of the TR nodes that are used in the table's body. Note that you will
+ * typically want to use the '$' API method in preference to this as it is more
+ * flexible.
+ * @param {int} [iRow] Optional row index for the TR element you want
+ * @returns {array|node} If iRow is undefined, returns an array of all TR elements
+ * in the table's body, or iRow is defined, just the TR element requested.
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Get the nodes from the table
+ * var nNodes = oTable.fnGetNodes( );
+ * } );
+ */
+ this.fnGetNodes = function( iRow )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+
+ if ( iRow !== undefined ) {
+ return (oSettings.aoData[iRow]!==undefined) ?
+ oSettings.aoData[iRow].nTr : null;
+ }
+ return _fnGetTrNodes( oSettings );
+ };
+
+
+ /**
+ * Get the array indexes of a particular cell from it's DOM element
+ * and column index including hidden columns
+ * @param {node} nNode this can either be a TR, TD or TH in the table's body
+ * @returns {int} If nNode is given as a TR, then a single index is returned, or
+ * if given as a cell, an array of [row index, column index (visible),
+ * column index (all)] is given.
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * $('#example tbody td').click( function () {
+ * // Get the position of the current data from the node
+ * var aPos = oTable.fnGetPosition( this );
+ *
+ * // Get the data array for this row
+ * var aData = oTable.fnGetData( aPos[0] );
+ *
+ * // Update the data array and return the value
+ * aData[ aPos[1] ] = 'clicked';
+ * this.innerHTML = 'clicked';
+ * } );
+ *
+ * // Init DataTables
+ * oTable = $('#example').dataTable();
+ * } );
+ */
+ this.fnGetPosition = function( nNode )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var sNodeName = nNode.nodeName.toUpperCase();
+
+ if ( sNodeName == "TR" )
+ {
+ return _fnNodeToDataIndex(oSettings, nNode);
+ }
+ else if ( sNodeName == "TD" || sNodeName == "TH" )
+ {
+ var iDataIndex = _fnNodeToDataIndex( oSettings, nNode.parentNode );
+ var iColumnIndex = _fnNodeToColumnIndex( oSettings, iDataIndex, nNode );
+ return [ iDataIndex, _fnColumnIndexToVisible(oSettings, iColumnIndex ), iColumnIndex ];
+ }
+ return null;
+ };
+
+
+ /**
+ * Check to see if a row is 'open' or not.
+ * @param {node} nTr the table row to check
+ * @returns {boolean} true if the row is currently open, false otherwise
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable;
+ *
+ * // 'open' an information row when a row is clicked on
+ * $('#example tbody tr').click( function () {
+ * if ( oTable.fnIsOpen(this) ) {
+ * oTable.fnClose( this );
+ * } else {
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
+ * }
+ * } );
+ *
+ * oTable = $('#example').dataTable();
+ * } );
+ */
+ this.fnIsOpen = function( nTr )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var aoOpenRows = oSettings.aoOpenRows;
+
+ for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
+ {
+ if ( oSettings.aoOpenRows[i].nParent == nTr )
+ {
+ return true;
+ }
+ }
+ return false;
+ };
+
+
+ /**
+ * This function will place a new row directly after a row which is currently
+ * on display on the page, with the HTML contents that is passed into the
+ * function. This can be used, for example, to ask for confirmation that a
+ * particular record should be deleted.
+ * @param {node} nTr The table row to 'open'
+ * @param {string|node|jQuery} mHtml The HTML to put into the row
+ * @param {string} sClass Class to give the new TD cell
+ * @returns {node} The row opened. Note that if the table row passed in as the
+ * first parameter, is not found in the table, this method will silently
+ * return.
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable;
+ *
+ * // 'open' an information row when a row is clicked on
+ * $('#example tbody tr').click( function () {
+ * if ( oTable.fnIsOpen(this) ) {
+ * oTable.fnClose( this );
+ * } else {
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
+ * }
+ * } );
+ *
+ * oTable = $('#example').dataTable();
+ * } );
+ */
+ this.fnOpen = function( nTr, mHtml, sClass )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+
+ /* Check that the row given is in the table */
+ var nTableRows = _fnGetTrNodes( oSettings );
+ if ( $.inArray(nTr, nTableRows) === -1 )
+ {
+ return;
+ }
+
+ /* the old open one if there is one */
+ this.fnClose( nTr );
+
+ var nNewRow = document.createElement("tr");
+ var nNewCell = document.createElement("td");
+ nNewRow.appendChild( nNewCell );
+ nNewCell.className = sClass;
+ nNewCell.colSpan = _fnVisbleColumns( oSettings );
+
+ if (typeof mHtml === "string")
+ {
+ nNewCell.innerHTML = mHtml;
+ }
+ else
+ {
+ $(nNewCell).html( mHtml );
+ }
+
+ /* If the nTr isn't on the page at the moment - then we don't insert at the moment */
+ var nTrs = $('tr', oSettings.nTBody);
+ if ( $.inArray(nTr, nTrs) != -1 )
+ {
+ $(nNewRow).insertAfter(nTr);
+ }
+
+ oSettings.aoOpenRows.push( {
+ "nTr": nNewRow,
+ "nParent": nTr
+ } );
+
+ return nNewRow;
+ };
+
+
+ /**
+ * Change the pagination - provides the internal logic for pagination in a simple API
+ * function. With this function you can have a DataTables table go to the next,
+ * previous, first or last pages.
+ * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
+ * or page number to jump to (integer), note that page 0 is the first page.
+ * @param {bool} [bRedraw=true] Redraw the table or not
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * oTable.fnPageChange( 'next' );
+ * } );
+ */
+ this.fnPageChange = function ( mAction, bRedraw )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ _fnPageChange( oSettings, mAction );
+ _fnCalculateEnd( oSettings );
+
+ if ( bRedraw === undefined || bRedraw )
+ {
+ _fnDraw( oSettings );
+ }
+ };
+
+
+ /**
+ * Show a particular column
+ * @param {int} iCol The column whose display should be changed
+ * @param {bool} bShow Show (true) or hide (false) the column
+ * @param {bool} [bRedraw=true] Redraw the table or not
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Hide the second column after initialisation
+ * oTable.fnSetColumnVis( 1, false );
+ * } );
+ */
+ this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var i, iLen;
+ var aoColumns = oSettings.aoColumns;
+ var aoData = oSettings.aoData;
+ var nTd, bAppend, iBefore;
+
+ /* No point in doing anything if we are requesting what is already true */
+ if ( aoColumns[iCol].bVisible == bShow )
+ {
+ return;
+ }
+
+ /* Show the column */
+ if ( bShow )
+ {
+ var iInsert = 0;
+ for ( i=0 ; i<iCol ; i++ )
+ {
+ if ( aoColumns[i].bVisible )
+ {
+ iInsert++;
+ }
+ }
+
+ /* Need to decide if we should use appendChild or insertBefore */
+ bAppend = (iInsert >= _fnVisbleColumns( oSettings ));
+
+ /* Which coloumn should we be inserting before? */
+ if ( !bAppend )
+ {
+ for ( i=iCol ; i<aoColumns.length ; i++ )
+ {
+ if ( aoColumns[i].bVisible )
+ {
+ iBefore = i;
+ break;
+ }
+ }
+ }
+
+ for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+ {
+ if ( aoData[i].nTr !== null )
+ {
+ if ( bAppend )
+ {
+ aoData[i].nTr.appendChild(
+ aoData[i]._anHidden[iCol]
+ );
+ }
+ else
+ {
+ aoData[i].nTr.insertBefore(
+ aoData[i]._anHidden[iCol],
+ _fnGetTdNodes( oSettings, i )[iBefore] );
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Remove a column from display */
+ for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+ {
+ if ( aoData[i].nTr !== null )
+ {
+ nTd = _fnGetTdNodes( oSettings, i )[iCol];
+ aoData[i]._anHidden[iCol] = nTd;
+ nTd.parentNode.removeChild( nTd );
+ }
+ }
+ }
+
+ /* Clear to set the visible flag */
+ aoColumns[iCol].bVisible = bShow;
+
+ /* Redraw the header and footer based on the new column visibility */
+ _fnDrawHead( oSettings, oSettings.aoHeader );
+ if ( oSettings.nTFoot )
+ {
+ _fnDrawHead( oSettings, oSettings.aoFooter );
+ }
+
+ /* If there are any 'open' rows, then we need to alter the colspan for this col change */
+ for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ )
+ {
+ oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );
+ }
+
+ /* Do a redraw incase anything depending on the table columns needs it
+ * (built-in: scrolling)
+ */
+ if ( bRedraw === undefined || bRedraw )
+ {
+ _fnAdjustColumnSizing( oSettings );
+ _fnDraw( oSettings );
+ }
+
+ _fnSaveState( oSettings );
+ };
+
+
+ /**
+ * Get the settings for a particular table for external manipulation
+ * @returns {object} DataTables settings object. See
+ * {@link DataTable.models.oSettings}
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * var oSettings = oTable.fnSettings();
+ *
+ * // Show an example parameter from the settings
+ * alert( oSettings._iDisplayStart );
+ * } );
+ */
+ this.fnSettings = function()
+ {
+ return _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ };
+
+
+ /**
+ * Sort the table by a particular column
+ * @param {int} iCol the data index to sort on. Note that this will not match the
+ * 'display index' if you have hidden data entries
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Sort immediately with columns 0 and 1
+ * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
+ * } );
+ */
+ this.fnSort = function( aaSort )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ oSettings.aaSorting = aaSort;
+ _fnSort( oSettings );
+ };
+
+
+ /**
+ * Attach a sort listener to an element for a given column
+ * @param {node} nNode the element to attach the sort listener to
+ * @param {int} iColumn the column that a click on this node will sort on
+ * @param {function} [fnCallback] callback function when sort is run
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Sort on column 1, when 'sorter' is clicked on
+ * oTable.fnSortListener( document.getElementById('sorter'), 1 );
+ * } );
+ */
+ this.fnSortListener = function( nNode, iColumn, fnCallback )
+ {
+ _fnSortAttachListener( _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ), nNode, iColumn,
+ fnCallback );
+ };
+
+
+ /**
+ * Update a table cell or row - this method will accept either a single value to
+ * update the cell with, an array of values with one element for each column or
+ * an object in the same format as the original data source. The function is
+ * self-referencing in order to make the multi column updates easier.
+ * @param {object|array|string} mData Data to update the cell/row with
+ * @param {node|int} mRow TR element you want to update or the aoData index
+ * @param {int} [iColumn] The column to update (not used of mData is an array or object)
+ * @param {bool} [bRedraw=true] Redraw the table or not
+ * @param {bool} [bAction=true] Perform pre-draw actions or not
+ * @returns {int} 0 on success, 1 on error
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
+ * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], 1, 0 ); // Row
+ * } );
+ */
+ this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
+ {
+ var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var i, iLen, sDisplay;
+ var iRow = (typeof mRow === 'object') ?
+ _fnNodeToDataIndex(oSettings, mRow) : mRow;
+
+ if ( $.isArray(mData) && iColumn === undefined )
+ {
+ /* Array update - update the whole row */
+ oSettings.aoData[iRow]._aData = mData.slice();
+
+ /* Flag to the function that we are recursing */
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
+ }
+ }
+ else if ( $.isPlainObject(mData) && iColumn === undefined )
+ {
+ /* Object update - update the whole row - assume the developer gets the object right */
+ oSettings.aoData[iRow]._aData = $.extend( true, {}, mData );
+
+ for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+ {
+ this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
+ }
+ }
+ else
+ {
+ /* Individual cell update */
+ _fnSetCellData( oSettings, iRow, iColumn, mData );
+ sDisplay = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
+
+ var oCol = oSettings.aoColumns[iColumn];
+ if ( oCol.fnRender !== null )
+ {
+ sDisplay = _fnRender( oSettings, iRow, iColumn );
+ if ( oCol.bUseRendered )
+ {
+ _fnSetCellData( oSettings, iRow, iColumn, sDisplay );
+ }
+ }
+
+ if ( oSettings.aoData[iRow].nTr !== null )
+ {
+ /* Do the actual HTML update */
+ _fnGetTdNodes( oSettings, iRow )[iColumn].innerHTML = sDisplay;
+ }
+ }
+
+ /* Modify the search index for this row (strictly this is likely not needed, since fnReDraw
+ * will rebuild the search array - however, the redraw might be disabled by the user)
+ */
+ var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );
+ oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow(
+ oSettings,
+ _fnGetRowData( oSettings, iRow, 'filter', _fnGetColumns( oSettings, 'bSearchable' ) )
+ );
+
+ /* Perform pre-draw actions */
+ if ( bAction === undefined || bAction )
+ {
+ _fnAdjustColumnSizing( oSettings );
+ }
+
+ /* Redraw the table */
+ if ( bRedraw === undefined || bRedraw )
+ {
+ _fnReDraw( oSettings );
+ }
+ return 0;
+ };
+
+
+ /**
+ * Provide a common method for plug-ins to check the version of DataTables being used, in order
+ * to ensure compatibility.
+ * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
+ * formats "X" and "X.Y" are also acceptable.
+ * @returns {boolean} true if this version of DataTables is greater or equal to the required
+ * version, or false if this version of DataTales is not suitable
+ * @method
+ * @dtopt API
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * alert( oTable.fnVersionCheck( '1.9.0' ) );
+ * } );
+ */
+ this.fnVersionCheck = DataTable.ext.fnVersionCheck;
+
+
+ /*
+ * This is really a good bit rubbish this method of exposing the internal methods
+ * publicly... - To be fixed in 2.0 using methods on the prototype
+ */
+
+
+ /**
+ * Create a wrapper function for exporting an internal functions to an external API.
+ * @param {string} sFunc API function name
+ * @returns {function} wrapped function
+ * @memberof DataTable#oApi
+ */
+ function _fnExternApiFunc (sFunc)
+ {
+ return function() {
+ var aArgs = [_fnSettingsFromNode(this[DataTable.ext.iApiIndex])].concat(
+ Array.prototype.slice.call(arguments) );
+ return DataTable.ext.oApi[sFunc].apply( this, aArgs );
+ };
+ }
+
+
+ /**
+ * Reference to internal functions for use by plug-in developers. Note that these
+ * methods are references to internal functions and are considered to be private.
+ * If you use these methods, be aware that they are liable to change between versions
+ * (check the upgrade notes).
+ * @namespace
+ */
+ this.oApi = {
+ "_fnExternApiFunc": _fnExternApiFunc,
+ "_fnInitialise": _fnInitialise,
+ "_fnInitComplete": _fnInitComplete,
+ "_fnLanguageCompat": _fnLanguageCompat,
+ "_fnAddColumn": _fnAddColumn,
+ "_fnColumnOptions": _fnColumnOptions,
+ "_fnAddData": _fnAddData,
+ "_fnCreateTr": _fnCreateTr,
+ "_fnGatherData": _fnGatherData,
+ "_fnBuildHead": _fnBuildHead,
+ "_fnDrawHead": _fnDrawHead,
+ "_fnDraw": _fnDraw,
+ "_fnReDraw": _fnReDraw,
+ "_fnAjaxUpdate": _fnAjaxUpdate,
+ "_fnAjaxParameters": _fnAjaxParameters,
+ "_fnAjaxUpdateDraw": _fnAjaxUpdateDraw,
+ "_fnServerParams": _fnServerParams,
+ "_fnAddOptionsHtml": _fnAddOptionsHtml,
+ "_fnFeatureHtmlTable": _fnFeatureHtmlTable,
+ "_fnScrollDraw": _fnScrollDraw,
+ "_fnAdjustColumnSizing": _fnAdjustColumnSizing,
+ "_fnFeatureHtmlFilter": _fnFeatureHtmlFilter,
+ "_fnFilterComplete": _fnFilterComplete,
+ "_fnFilterCustom": _fnFilterCustom,
+ "_fnFilterColumn": _fnFilterColumn,
+ "_fnFilter": _fnFilter,
+ "_fnBuildSearchArray": _fnBuildSearchArray,
+ "_fnBuildSearchRow": _fnBuildSearchRow,
+ "_fnFilterCreateSearch": _fnFilterCreateSearch,
+ "_fnDataToSearch": _fnDataToSearch,
+ "_fnSort": _fnSort,
+ "_fnSortAttachListener": _fnSortAttachListener,
+ "_fnSortingClasses": _fnSortingClasses,
+ "_fnFeatureHtmlPaginate": _fnFeatureHtmlPaginate,
+ "_fnPageChange": _fnPageChange,
+ "_fnFeatureHtmlInfo": _fnFeatureHtmlInfo,
+ "_fnUpdateInfo": _fnUpdateInfo,
+ "_fnFeatureHtmlLength": _fnFeatureHtmlLength,
+ "_fnFeatureHtmlProcessing": _fnFeatureHtmlProcessing,
+ "_fnProcessingDisplay": _fnProcessingDisplay,
+ "_fnVisibleToColumnIndex": _fnVisibleToColumnIndex,
+ "_fnColumnIndexToVisible": _fnColumnIndexToVisible,
+ "_fnNodeToDataIndex": _fnNodeToDataIndex,
+ "_fnVisbleColumns": _fnVisbleColumns,
+ "_fnCalculateEnd": _fnCalculateEnd,
+ "_fnConvertToWidth": _fnConvertToWidth,
+ "_fnCalculateColumnWidths": _fnCalculateColumnWidths,
+ "_fnScrollingWidthAdjust": _fnScrollingWidthAdjust,
+ "_fnGetWidestNode": _fnGetWidestNode,
+ "_fnGetMaxLenString": _fnGetMaxLenString,
+ "_fnStringToCss": _fnStringToCss,
+ "_fnDetectType": _fnDetectType,
+ "_fnSettingsFromNode": _fnSettingsFromNode,
+ "_fnGetDataMaster": _fnGetDataMaster,
+ "_fnGetTrNodes": _fnGetTrNodes,
+ "_fnGetTdNodes": _fnGetTdNodes,
+ "_fnEscapeRegex": _fnEscapeRegex,
+ "_fnDeleteIndex": _fnDeleteIndex,
+ "_fnReOrderIndex": _fnReOrderIndex,
+ "_fnColumnOrdering": _fnColumnOrdering,
+ "_fnLog": _fnLog,
+ "_fnClearTable": _fnClearTable,
+ "_fnSaveState": _fnSaveState,
+ "_fnLoadState": _fnLoadState,
+ "_fnCreateCookie": _fnCreateCookie,
+ "_fnReadCookie": _fnReadCookie,
+ "_fnDetectHeader": _fnDetectHeader,
+ "_fnGetUniqueThs": _fnGetUniqueThs,
+ "_fnScrollBarWidth": _fnScrollBarWidth,
+ "_fnApplyToChildren": _fnApplyToChildren,
+ "_fnMap": _fnMap,
+ "_fnGetRowData": _fnGetRowData,
+ "_fnGetCellData": _fnGetCellData,
+ "_fnSetCellData": _fnSetCellData,
+ "_fnGetObjectDataFn": _fnGetObjectDataFn,
+ "_fnSetObjectDataFn": _fnSetObjectDataFn,
+ "_fnApplyColumnDefs": _fnApplyColumnDefs,
+ "_fnBindAction": _fnBindAction,
+ "_fnExtend": _fnExtend,
+ "_fnCallbackReg": _fnCallbackReg,
+ "_fnCallbackFire": _fnCallbackFire,
+ "_fnJsonString": _fnJsonString,
+ "_fnRender": _fnRender,
+ "_fnNodeToColumnIndex": _fnNodeToColumnIndex,
+ "_fnInfoMacros": _fnInfoMacros,
+ "_fnBrowserDetect": _fnBrowserDetect,
+ "_fnGetColumns": _fnGetColumns
+ };
+
+ $.extend( DataTable.ext.oApi, this.oApi );
+
+ for ( var sFunc in DataTable.ext.oApi )
+ {
+ if ( sFunc )
+ {
+ this[sFunc] = _fnExternApiFunc(sFunc);
+ }
+ }
+
+
+ var _that = this;
+ this.each(function() {
+ var i=0, iLen, j, jLen, k, kLen;
+ var sId = this.getAttribute( 'id' );
+ var bInitHandedOff = false;
+ var bUsePassedData = false;
+
+
+ /* Sanity check */
+ if ( this.nodeName.toLowerCase() != 'table' )
+ {
+ _fnLog( null, 0, "Attempted to initialise DataTables on a node which is not a "+
+ "table: "+this.nodeName );
+ return;
+ }
+
+ /* Check to see if we are re-initialising a table */
+ for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
+ {
+ /* Base check on table node */
+ if ( DataTable.settings[i].nTable == this )
+ {
+ if ( oInit === undefined || oInit.bRetrieve )
+ {
+ return DataTable.settings[i].oInstance;
+ }
+ else if ( oInit.bDestroy )
+ {
+ DataTable.settings[i].oInstance.fnDestroy();
+ break;
+ }
+ else
+ {
+ _fnLog( DataTable.settings[i], 0, "Cannot reinitialise DataTable.\n\n"+
+ "To retrieve the DataTables object for this table, pass no arguments or see "+
+ "the docs for bRetrieve and bDestroy" );
+ return;
+ }
+ }
+
+ /* If the element we are initialising has the same ID as a table which was previously
+ * initialised, but the table nodes don't match (from before) then we destroy the old
+ * instance by simply deleting it. This is under the assumption that the table has been
+ * destroyed by other methods. Anyone using non-id selectors will need to do this manually
+ */
+ if ( DataTable.settings[i].sTableId == this.id )
+ {
+ DataTable.settings.splice( i, 1 );
+ break;
+ }
+ }
+
+ /* Ensure the table has an ID - required for accessibility */
+ if ( sId === null || sId === "" )
+ {
+ sId = "DataTables_Table_"+(DataTable.ext._oExternConfig.iNextUnique++);
+ this.id = sId;
+ }
+
+ /* Create the settings object for this table and set some of the default parameters */
+ var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
+ "nTable": this,
+ "oApi": _that.oApi,
+ "oInit": oInit,
+ "sDestroyWidth": $(this).width(),
+ "sInstance": sId,
+ "sTableId": sId
+ } );
+ DataTable.settings.push( oSettings );
+
+ // Need to add the instance after the instance after the settings object has been added
+ // to the settings array, so we can self reference the table instance if more than one
+ oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
+
+ /* Setting up the initialisation object */
+ if ( !oInit )
+ {
+ oInit = {};
+ }
+
+ // Backwards compatibility, before we apply all the defaults
+ if ( oInit.oLanguage )
+ {
+ _fnLanguageCompat( oInit.oLanguage );
+ }
+
+ oInit = _fnExtend( $.extend(true, {}, DataTable.defaults), oInit );
+
+ // Map the initialisation options onto the settings object
+ _fnMap( oSettings.oFeatures, oInit, "bPaginate" );
+ _fnMap( oSettings.oFeatures, oInit, "bLengthChange" );
+ _fnMap( oSettings.oFeatures, oInit, "bFilter" );
+ _fnMap( oSettings.oFeatures, oInit, "bSort" );
+ _fnMap( oSettings.oFeatures, oInit, "bInfo" );
+ _fnMap( oSettings.oFeatures, oInit, "bProcessing" );
+ _fnMap( oSettings.oFeatures, oInit, "bAutoWidth" );
+ _fnMap( oSettings.oFeatures, oInit, "bSortClasses" );
+ _fnMap( oSettings.oFeatures, oInit, "bServerSide" );
+ _fnMap( oSettings.oFeatures, oInit, "bDeferRender" );
+ _fnMap( oSettings.oScroll, oInit, "sScrollX", "sX" );
+ _fnMap( oSettings.oScroll, oInit, "sScrollXInner", "sXInner" );
+ _fnMap( oSettings.oScroll, oInit, "sScrollY", "sY" );
+ _fnMap( oSettings.oScroll, oInit, "bScrollCollapse", "bCollapse" );
+ _fnMap( oSettings.oScroll, oInit, "bScrollInfinite", "bInfinite" );
+ _fnMap( oSettings.oScroll, oInit, "iScrollLoadGap", "iLoadGap" );
+ _fnMap( oSettings.oScroll, oInit, "bScrollAutoCss", "bAutoCss" );
+ _fnMap( oSettings, oInit, "asStripeClasses" );
+ _fnMap( oSettings, oInit, "asStripClasses", "asStripeClasses" ); // legacy
+ _fnMap( oSettings, oInit, "fnServerData" );
+ _fnMap( oSettings, oInit, "fnFormatNumber" );
+ _fnMap( oSettings, oInit, "sServerMethod" );
+ _fnMap( oSettings, oInit, "aaSorting" );
+ _fnMap( oSettings, oInit, "aaSortingFixed" );
+ _fnMap( oSettings, oInit, "aLengthMenu" );
+ _fnMap( oSettings, oInit, "sPaginationType" );
+ _fnMap( oSettings, oInit, "sAjaxSource" );
+ _fnMap( oSettings, oInit, "sAjaxDataProp" );
+ _fnMap( oSettings, oInit, "iCookieDuration" );
+ _fnMap( oSettings, oInit, "sCookiePrefix" );
+ _fnMap( oSettings, oInit, "sDom" );
+ _fnMap( oSettings, oInit, "bSortCellsTop" );
+ _fnMap( oSettings, oInit, "iTabIndex" );
+ _fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" );
+ _fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" );
+ _fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" );
+ _fnMap( oSettings, oInit, "bJQueryUI", "bJUI" );
+ _fnMap( oSettings, oInit, "fnCookieCallback" );
+ _fnMap( oSettings, oInit, "fnStateLoad" );
+ _fnMap( oSettings, oInit, "fnStateSave" );
+ _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
+
+ /* Callback functions which are array driven */
+ _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
+ _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
+ _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
+ _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
+ _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
+ _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
+ _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
+ _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
+ _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
+ _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
+ _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
+
+ if ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort &&
+ oSettings.oFeatures.bSortClasses )
+ {
+ /* Enable sort classes for server-side processing. Safe to do it here, since server-side
+ * processing must be enabled by the developer
+ */
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'server_side_sort_classes' );
+ }
+ else if ( oSettings.oFeatures.bDeferRender )
+ {
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'defer_sort_classes' );
+ }
+
+ if ( oInit.bJQueryUI )
+ {
+ /* Use the JUI classes object for display. You could clone the oStdClasses object if
+ * you want to have multiple tables with multiple independent classes
+ */
+ $.extend( oSettings.oClasses, DataTable.ext.oJUIClasses );
+
+ if ( oInit.sDom === DataTable.defaults.sDom && DataTable.defaults.sDom === "lfrtip" )
+ {
+ /* Set the DOM to use a layout suitable for jQuery UI's theming */
+ oSettings.sDom = '<"H"lfr>t<"F"ip>';
+ }
+ }
+ else
+ {
+ $.extend( oSettings.oClasses, DataTable.ext.oStdClasses );
+ }
+ $(this).addClass( oSettings.oClasses.sTable );
+
+ /* Calculate the scroll bar width and cache it for use later on */
+ if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
+ {
+ oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
+ }
+
+ if ( oSettings.iInitDisplayStart === undefined )
+ {
+ /* Display start point, taking into account the save saving */
+ oSettings.iInitDisplayStart = oInit.iDisplayStart;
+ oSettings._iDisplayStart = oInit.iDisplayStart;
+ }
+
+ /* Must be done after everything which can be overridden by a cookie! */
+ if ( oInit.bStateSave )
+ {
+ oSettings.oFeatures.bStateSave = true;
+ _fnLoadState( oSettings, oInit );
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
+ }
+
+ if ( oInit.iDeferLoading !== null )
+ {
+ oSettings.bDeferLoading = true;
+ var tmp = $.isArray( oInit.iDeferLoading );
+ oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
+ oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
+ }
+
+ if ( oInit.aaData !== null )
+ {
+ bUsePassedData = true;
+ }
+
+ /* Language definitions */
+ if ( oInit.oLanguage.sUrl !== "" )
+ {
+ /* Get the language definitions from a file - because this Ajax call makes the language
+ * get async to the remainder of this function we use bInitHandedOff to indicate that
+ * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
+ */
+ oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
+ $.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
+ _fnLanguageCompat( json );
+ $.extend( true, oSettings.oLanguage, oInit.oLanguage, json );
+ _fnInitialise( oSettings );
+ } );
+ bInitHandedOff = true;
+ }
+ else
+ {
+ $.extend( true, oSettings.oLanguage, oInit.oLanguage );
+ }
+
+
+ /*
+ * Stripes
+ */
+ if ( oInit.asStripeClasses === null )
+ {
+ oSettings.asStripeClasses =[
+ oSettings.oClasses.sStripeOdd,
+ oSettings.oClasses.sStripeEven
+ ];
+ }
+
+ /* Remove row stripe classes if they are already on the table row */
+ iLen=oSettings.asStripeClasses.length;
+ oSettings.asDestroyStripes = [];
+ if (iLen)
+ {
+ var bStripeRemove = false;
+ var anRows = $(this).children('tbody').children('tr:lt(' + iLen + ')');
+ for ( i=0 ; i<iLen ; i++ )
+ {
+ if ( anRows.hasClass( oSettings.asStripeClasses[i] ) )
+ {
+ bStripeRemove = true;
+
+ /* Store the classes which we are about to remove so they can be re-added on destroy */
+ oSettings.asDestroyStripes.push( oSettings.asStripeClasses[i] );
+ }
+ }
+
+ if ( bStripeRemove )
+ {
+ anRows.removeClass( oSettings.asStripeClasses.join(' ') );
+ }
+ }
+
+ /*
+ * Columns
+ * See if we should load columns automatically or use defined ones
+ */
+ var anThs = [];
+ var aoColumnsInit;
+ var nThead = this.getElementsByTagName('thead');
+ if ( nThead.length !== 0 )
+ {
+ _fnDetectHeader( oSettings.aoHeader, nThead[0] );
+ anThs = _fnGetUniqueThs( oSettings );
+ }
+
+ /* If not given a column array, generate one with nulls */
+ if ( oInit.aoColumns === null )
+ {
+ aoColumnsInit = [];
+ for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
+ {
+ aoColumnsInit.push( null );
+ }
+ }
+ else
+ {
+ aoColumnsInit = oInit.aoColumns;
+ }
+
+ /* Add the columns */
+ for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
+ {
+ /* Short cut - use the loop to check if we have column visibility state to restore */
+ if ( oInit.saved_aoColumns !== undefined && oInit.saved_aoColumns.length == iLen )
+ {
+ if ( aoColumnsInit[i] === null )
+ {
+ aoColumnsInit[i] = {};
+ }
+ aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible;
+ }
+
+ _fnAddColumn( oSettings, anThs ? anThs[i] : null );
+ }
+
+ /* Apply the column definitions */
+ _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
+ _fnColumnOptions( oSettings, iCol, oDef );
+ } );
+
+
+ /*
+ * Sorting
+ * Check the aaSorting array
+ */
+ for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
+ {
+ if ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length )
+ {
+ oSettings.aaSorting[i][0] = 0;
+ }
+ var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];
+
+ /* Add a default sorting index */
+ if ( oSettings.aaSorting[i][2] === undefined )
+ {
+ oSettings.aaSorting[i][2] = 0;
+ }
+
+ /* If aaSorting is not defined, then we use the first indicator in asSorting */
+ if ( oInit.aaSorting === undefined && oSettings.saved_aaSorting === undefined )
+ {
+ oSettings.aaSorting[i][1] = oColumn.asSorting[0];
+ }
+
+ /* Set the current sorting index based on aoColumns.asSorting */
+ for ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ )
+ {
+ if ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] )
+ {
+ oSettings.aaSorting[i][2] = j;
+ break;
+ }
+ }
+ }
+
+ /* Do a first pass on the sorting classes (allows any size changes to be taken into
+ * account, and also will apply sorting disabled classes if disabled
+ */
+ _fnSortingClasses( oSettings );
+
+
+ /*
+ * Final init
+ * Cache the header, body and footer as required, creating them if needed
+ */
+
+ /* Browser support detection */
+ _fnBrowserDetect( oSettings );
+
+ // Work around for Webkit bug 83867 - store the caption-side before removing from doc
+ var captions = $(this).children('caption').each( function () {
+ this._captionSide = $(this).css('caption-side');
+ } );
+
+ var thead = $(this).children('thead');
+ if ( thead.length === 0 )
+ {
+ thead = [ document.createElement( 'thead' ) ];
+ this.appendChild( thead[0] );
+ }
+ oSettings.nTHead = thead[0];
+
+ var tbody = $(this).children('tbody');
+ if ( tbody.length === 0 )
+ {
+ tbody = [ document.createElement( 'tbody' ) ];
+ this.appendChild( tbody[0] );
+ }
+ oSettings.nTBody = tbody[0];
+ oSettings.nTBody.setAttribute( "role", "alert" );
+ oSettings.nTBody.setAttribute( "aria-live", "polite" );
+ oSettings.nTBody.setAttribute( "aria-relevant", "all" );
+
+ var tfoot = $(this).children('tfoot');
+ if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
+ {
+ // If we are a scrolling table, and no footer has been given, then we need to create
+ // a tfoot element for the caption element to be appended to
+ tfoot = [ document.createElement( 'tfoot' ) ];
+ this.appendChild( tfoot[0] );
+ }
+
+ if ( tfoot.length > 0 )
+ {
+ oSettings.nTFoot = tfoot[0];
+ _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
+ }
+
+ /* Check if there is data passing into the constructor */
+ if ( bUsePassedData )
+ {
+ for ( i=0 ; i<oInit.aaData.length ; i++ )
+ {
+ _fnAddData( oSettings, oInit.aaData[ i ] );
+ }
+ }
+ else
+ {
+ /* Grab the data from the page */
+ _fnGatherData( oSettings );
+ }
+
+ /* Copy the data index array */
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+
+ /* Initialisation complete - table can be drawn */
+ oSettings.bInitialised = true;
+
+ /* Check if we need to initialise the table (it might not have been handed off to the
+ * language processor)
+ */
+ if ( bInitHandedOff === false )
+ {
+ _fnInitialise( oSettings );
+ }
+ } );
+ _that = null;
+ return this;
+ };
+
+
+
+ /**
+ * Provide a common method for plug-ins to check the version of DataTables being used, in order
+ * to ensure compatibility.
+ * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
+ * formats "X" and "X.Y" are also acceptable.
+ * @returns {boolean} true if this version of DataTables is greater or equal to the required
+ * version, or false if this version of DataTales is not suitable
+ * @static
+ * @dtopt API-Static
+ *
+ * @example
+ * alert( $.fn.dataTable.fnVersionCheck( '1.9.0' ) );
+ */
+ DataTable.fnVersionCheck = function( sVersion )
+ {
+ /* This is cheap, but effective */
+ var fnZPad = function (Zpad, count)
+ {
+ while(Zpad.length < count) {
+ Zpad += '0';
+ }
+ return Zpad;
+ };
+ var aThis = DataTable.ext.sVersion.split('.');
+ var aThat = sVersion.split('.');
+ var sThis = '', sThat = '';
+
+ for ( var i=0, iLen=aThat.length ; i<iLen ; i++ )
+ {
+ sThis += fnZPad( aThis[i], 3 );
+ sThat += fnZPad( aThat[i], 3 );
+ }
+
+ return parseInt(sThis, 10) >= parseInt(sThat, 10);
+ };
+
+
+ /**
+ * Check if a TABLE node is a DataTable table already or not.
+ * @param {node} nTable The TABLE node to check if it is a DataTable or not (note that other
+ * node types can be passed in, but will always return false).
+ * @returns {boolean} true the table given is a DataTable, or false otherwise
+ * @static
+ * @dtopt API-Static
+ *
+ * @example
+ * var ex = document.getElementById('example');
+ * if ( ! $.fn.DataTable.fnIsDataTable( ex ) ) {
+ * $(ex).dataTable();
+ * }
+ */
+ DataTable.fnIsDataTable = function ( nTable )
+ {
+ var o = DataTable.settings;
+
+ for ( var i=0 ; i<o.length ; i++ )
+ {
+ if ( o[i].nTable === nTable || o[i].nScrollHead === nTable || o[i].nScrollFoot === nTable )
+ {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+
+ /**
+ * Get all DataTable tables that have been initialised - optionally you can select to
+ * get only currently visible tables.
+ * @param {boolean} [bVisible=false] Flag to indicate if you want all (default) or
+ * visible tables only.
+ * @returns {array} Array of TABLE nodes (not DataTable instances) which are DataTables
+ * @static
+ * @dtopt API-Static
+ *
+ * @example
+ * var table = $.fn.dataTable.fnTables(true);
+ * if ( table.length > 0 ) {
+ * $(table).dataTable().fnAdjustColumnSizing();
+ * }
+ */
+ DataTable.fnTables = function ( bVisible )
+ {
+ var out = [];
+
+ jQuery.each( DataTable.settings, function (i, o) {
+ if ( !bVisible || (bVisible === true && $(o.nTable).is(':visible')) )
+ {
+ out.push( o.nTable );
+ }
+ } );
+
+ return out;
+ };
+
+
+ /**
+ * Version string for plug-ins to check compatibility. Allowed format is
+ * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
+ * e are optional
+ * @member
+ * @type string
+ * @default Version number
+ */
+ DataTable.version = "1.9.4";
+
+ /**
+ * Private data store, containing all of the settings objects that are created for the
+ * tables on a given page.
+ *
+ * Note that the <i>DataTable.settings</i> object is aliased to <i>jQuery.fn.dataTableExt</i>
+ * through which it may be accessed and manipulated, or <i>jQuery.fn.dataTable.settings</i>.
+ * @member
+ * @type array
+ * @default []
+ * @private
+ */
+ DataTable.settings = [];
+
+ /**
+ * Object models container, for the various models that DataTables has available
+ * to it. These models define the objects that are used to hold the active state
+ * and configuration of the table.
+ * @namespace
+ */
+ DataTable.models = {};
+
+
+ /**
+ * DataTables extension options and plug-ins. This namespace acts as a collection "area"
+ * for plug-ins that can be used to extend the default DataTables behaviour - indeed many
+ * of the build in methods use this method to provide their own capabilities (sorting methods
+ * for example).
+ *
+ * Note that this namespace is aliased to jQuery.fn.dataTableExt so it can be readily accessed
+ * and modified by plug-ins.
+ * @namespace
+ */
+ DataTable.models.ext = {
+ /**
+ * Plug-in filtering functions - this method of filtering is complimentary to the default
+ * type based filtering, and a lot more comprehensive as it allows you complete control
+ * over the filtering logic. Each element in this array is a function (parameters
+ * described below) that is called for every row in the table, and your logic decides if
+ * it should be included in the filtered data set or not.
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+ * <li>{array|object} Data for the row to be processed (same as the original format
+ * that was passed in as the data source, or an array from a DOM data source</li>
+ * <li>{int} Row index in aoData ({@link DataTable.models.oSettings.aoData}), which can
+ * be useful to retrieve the TR element if you need DOM interaction.</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>{boolean} Include the row in the filtered result set (true) or not (false)</li>
+ * </ul>
+ * </il>
+ * </ul>
+ * @type array
+ * @default []
+ *
+ * @example
+ * // The following example shows custom filtering being applied to the fourth column (i.e.
+ * // the aData[3] index) based on two input values from the end-user, matching the data in
+ * // a certain range.
+ * $.fn.dataTableExt.afnFiltering.push(
+ * function( oSettings, aData, iDataIndex ) {
+ * var iMin = document.getElementById('min').value * 1;
+ * var iMax = document.getElementById('max').value * 1;
+ * var iVersion = aData[3] == "-" ? 0 : aData[3]*1;
+ * if ( iMin == "" && iMax == "" ) {
+ * return true;
+ * }
+ * else if ( iMin == "" && iVersion < iMax ) {
+ * return true;
+ * }
+ * else if ( iMin < iVersion && "" == iMax ) {
+ * return true;
+ * }
+ * else if ( iMin < iVersion && iVersion < iMax ) {
+ * return true;
+ * }
+ * return false;
+ * }
+ * );
+ */
+ "afnFiltering": [],
+
+
+ /**
+ * Plug-in sorting functions - this method of sorting is complimentary to the default type
+ * based sorting that DataTables does automatically, allowing much greater control over the
+ * the data that is being used to sort a column. This is useful if you want to do sorting
+ * based on live data (for example the contents of an 'input' element) rather than just the
+ * static string that DataTables knows of. The way these plug-ins work is that you create
+ * an array of the values you wish to be sorted for the column in question and then return
+ * that array. Which pre-sorting function is run here depends on the sSortDataType parameter
+ * that is used for the column (if any). This is the corollary of <i>ofnSearch</i> for sort
+ * data.
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+ * <li>{int} Target column index</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>{array} Data for the column to be sorted upon</li>
+ * </ul>
+ * </il>
+ * </ul>
+ *
+ * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
+ * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
+ * used as a function will give you a 'type' (sorting, filtering etc) that you can use to
+ * prepare the data as required for the different types. As such, this method is deprecated.
+ * @type array
+ * @default []
+ * @deprecated
+ *
+ * @example
+ * // Updating the cached sorting information with user entered values in HTML input elements
+ * jQuery.fn.dataTableExt.afnSortData['dom-text'] = function ( oSettings, iColumn )
+ * {
+ * var aData = [];
+ * $( 'td:eq('+iColumn+') input', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
+ * aData.push( this.value );
+ * } );
+ * return aData;
+ * }
+ */
+ "afnSortData": [],
+
+
+ /**
+ * Feature plug-ins - This is an array of objects which describe the feature plug-ins that are
+ * available to DataTables. These feature plug-ins are accessible through the sDom initialisation
+ * option. As such, each feature plug-in must describe a function that is used to initialise
+ * itself (fnInit), a character so the feature can be enabled by sDom (cFeature) and the name
+ * of the feature (sFeature). Thus the objects attached to this method must provide:
+ * <ul>
+ * <li>{function} fnInit Initialisation of the plug-in
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>{node|null} The element which contains your feature. Note that the return
+ * may also be void if your plug-in does not require to inject any DOM elements
+ * into DataTables control (sDom) - for example this might be useful when
+ * developing a plug-in which allows table control via keyboard entry.</li>
+ * </ul>
+ * </il>
+ * </ul>
+ * </li>
+ * <li>{character} cFeature Character that will be matched in sDom - case sensitive</li>
+ * <li>{string} sFeature Feature name</li>
+ * </ul>
+ * @type array
+ * @default []
+ *
+ * @example
+ * // How TableTools initialises itself.
+ * $.fn.dataTableExt.aoFeatures.push( {
+ * "fnInit": function( oSettings ) {
+ * return new TableTools( { "oDTSettings": oSettings } );
+ * },
+ * "cFeature": "T",
+ * "sFeature": "TableTools"
+ * } );
+ */
+ "aoFeatures": [],
+
+
+ /**
+ * Type detection plug-in functions - DataTables utilises types to define how sorting and
+ * filtering behave, and types can be either be defined by the developer (sType for the
+ * column) or they can be automatically detected by the methods in this array. The functions
+ * defined in the array are quite simple, taking a single parameter (the data to analyse)
+ * and returning the type if it is a known type, or null otherwise.
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{*} Data from the column cell to be analysed</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>{string|null} Data type detected, or null if unknown (and thus pass it
+ * on to the other type detection functions.</li>
+ * </ul>
+ * </il>
+ * </ul>
+ * @type array
+ * @default []
+ *
+ * @example
+ * // Currency type detection plug-in:
+ * jQuery.fn.dataTableExt.aTypes.push(
+ * function ( sData ) {
+ * var sValidChars = "0123456789.-";
+ * var Char;
+ *
+ * // Check the numeric part
+ * for ( i=1 ; i<sData.length ; i++ ) {
+ * Char = sData.charAt(i);
+ * if (sValidChars.indexOf(Char) == -1) {
+ * return null;
+ * }
+ * }
+ *
+ * // Check prefixed by currency
+ * if ( sData.charAt(0) == '$' || sData.charAt(0) == '&pound;' ) {
+ * return 'currency';
+ * }
+ * return null;
+ * }
+ * );
+ */
+ "aTypes": [],
+
+
+ /**
+ * Provide a common method for plug-ins to check the version of DataTables being used,
+ * in order to ensure compatibility.
+ * @type function
+ * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note
+ * that the formats "X" and "X.Y" are also acceptable.
+ * @returns {boolean} true if this version of DataTables is greater or equal to the
+ * required version, or false if this version of DataTales is not suitable
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * alert( oTable.fnVersionCheck( '1.9.0' ) );
+ * } );
+ */
+ "fnVersionCheck": DataTable.fnVersionCheck,
+
+
+ /**
+ * Index for what 'this' index API functions should use
+ * @type int
+ * @default 0
+ */
+ "iApiIndex": 0,
+
+
+ /**
+ * Pre-processing of filtering data plug-ins - When you assign the sType for a column
+ * (or have it automatically detected for you by DataTables or a type detection plug-in),
+ * you will typically be using this for custom sorting, but it can also be used to provide
+ * custom filtering by allowing you to pre-processing the data and returning the data in
+ * the format that should be filtered upon. This is done by adding functions this object
+ * with a parameter name which matches the sType for that target column. This is the
+ * corollary of <i>afnSortData</i> for filtering data.
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{*} Data from the column cell to be prepared for filtering</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>{string|null} Formatted string that will be used for the filtering.</li>
+ * </ul>
+ * </il>
+ * </ul>
+ *
+ * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
+ * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
+ * used as a function will give you a 'type' (sorting, filtering etc) that you can use to
+ * prepare the data as required for the different types. As such, this method is deprecated.
+ * @type object
+ * @default {}
+ * @deprecated
+ *
+ * @example
+ * $.fn.dataTableExt.ofnSearch['title-numeric'] = function ( sData ) {
+ * return sData.replace(/\n/g," ").replace( /<.*?>/g, "" );
+ * }
+ */
+ "ofnSearch": {},
+
+
+ /**
+ * Container for all private functions in DataTables so they can be exposed externally
+ * @type object
+ * @default {}
+ */
+ "oApi": {},
+
+
+ /**
+ * Storage for the various classes that DataTables uses
+ * @type object
+ * @default {}
+ */
+ "oStdClasses": {},
+
+
+ /**
+ * Storage for the various classes that DataTables uses - jQuery UI suitable
+ * @type object
+ * @default {}
+ */
+ "oJUIClasses": {},
+
+
+ /**
+ * Pagination plug-in methods - The style and controls of the pagination can significantly
+ * impact on how the end user interacts with the data in your table, and DataTables allows
+ * the addition of pagination controls by extending this object, which can then be enabled
+ * through the <i>sPaginationType</i> initialisation parameter. Each pagination type that
+ * is added is an object (the property name of which is what <i>sPaginationType</i> refers
+ * to) that has two properties, both methods that are used by DataTables to update the
+ * control's state.
+ * <ul>
+ * <li>
+ * fnInit - Initialisation of the paging controls. Called only during initialisation
+ * of the table. It is expected that this function will add the required DOM elements
+ * to the page for the paging controls to work. The element pointer
+ * 'oSettings.aanFeatures.p' array is provided by DataTables to contain the paging
+ * controls (note that this is a 2D array to allow for multiple instances of each
+ * DataTables DOM element). It is suggested that you add the controls to this element
+ * as children
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+ * <li>{node} Container into which the pagination controls must be inserted</li>
+ * <li>{function} Draw callback function - whenever the controls cause a page
+ * change, this method must be called to redraw the table.</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>No return required</li>
+ * </ul>
+ * </il>
+ * </ul>
+ * </il>
+ * <li>
+ * fnInit - This function is called whenever the paging status of the table changes and is
+ * typically used to update classes and/or text of the paging controls to reflex the new
+ * status.
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+ * <li>{function} Draw callback function - in case you need to redraw the table again
+ * or attach new event listeners</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>No return required</li>
+ * </ul>
+ * </il>
+ * </ul>
+ * </il>
+ * </ul>
+ * @type object
+ * @default {}
+ *
+ * @example
+ * $.fn.dataTableExt.oPagination.four_button = {
+ * "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) {
+ * nFirst = document.createElement( 'span' );
+ * nPrevious = document.createElement( 'span' );
+ * nNext = document.createElement( 'span' );
+ * nLast = document.createElement( 'span' );
+ *
+ * nFirst.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sFirst ) );
+ * nPrevious.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sPrevious ) );
+ * nNext.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sNext ) );
+ * nLast.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sLast ) );
+ *
+ * nFirst.className = "paginate_button first";
+ * nPrevious.className = "paginate_button previous";
+ * nNext.className="paginate_button next";
+ * nLast.className = "paginate_button last";
+ *
+ * nPaging.appendChild( nFirst );
+ * nPaging.appendChild( nPrevious );
+ * nPaging.appendChild( nNext );
+ * nPaging.appendChild( nLast );
+ *
+ * $(nFirst).click( function () {
+ * oSettings.oApi._fnPageChange( oSettings, "first" );
+ * fnCallbackDraw( oSettings );
+ * } );
+ *
+ * $(nPrevious).click( function() {
+ * oSettings.oApi._fnPageChange( oSettings, "previous" );
+ * fnCallbackDraw( oSettings );
+ * } );
+ *
+ * $(nNext).click( function() {
+ * oSettings.oApi._fnPageChange( oSettings, "next" );
+ * fnCallbackDraw( oSettings );
+ * } );
+ *
+ * $(nLast).click( function() {
+ * oSettings.oApi._fnPageChange( oSettings, "last" );
+ * fnCallbackDraw( oSettings );
+ * } );
+ *
+ * $(nFirst).bind( 'selectstart', function () { return false; } );
+ * $(nPrevious).bind( 'selectstart', function () { return false; } );
+ * $(nNext).bind( 'selectstart', function () { return false; } );
+ * $(nLast).bind( 'selectstart', function () { return false; } );
+ * },
+ *
+ * "fnUpdate": function ( oSettings, fnCallbackDraw ) {
+ * if ( !oSettings.aanFeatures.p ) {
+ * return;
+ * }
+ *
+ * // Loop over each instance of the pager
+ * var an = oSettings.aanFeatures.p;
+ * for ( var i=0, iLen=an.length ; i<iLen ; i++ ) {
+ * var buttons = an[i].getElementsByTagName('span');
+ * if ( oSettings._iDisplayStart === 0 ) {
+ * buttons[0].className = "paginate_disabled_previous";
+ * buttons[1].className = "paginate_disabled_previous";
+ * }
+ * else {
+ * buttons[0].className = "paginate_enabled_previous";
+ * buttons[1].className = "paginate_enabled_previous";
+ * }
+ *
+ * if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) {
+ * buttons[2].className = "paginate_disabled_next";
+ * buttons[3].className = "paginate_disabled_next";
+ * }
+ * else {
+ * buttons[2].className = "paginate_enabled_next";
+ * buttons[3].className = "paginate_enabled_next";
+ * }
+ * }
+ * }
+ * };
+ */
+ "oPagination": {},
+
+
+ /**
+ * Sorting plug-in methods - Sorting in DataTables is based on the detected type of the
+ * data column (you can add your own type detection functions, or override automatic
+ * detection using sType). With this specific type given to the column, DataTables will
+ * apply the required sort from the functions in the object. Each sort type must provide
+ * two mandatory methods, one each for ascending and descending sorting, and can optionally
+ * provide a pre-formatting method that will help speed up sorting by allowing DataTables
+ * to pre-format the sort data only once (rather than every time the actual sort functions
+ * are run). The two sorting functions are typical Javascript sort methods:
+ * <ul>
+ * <li>
+ * Function input parameters:
+ * <ul>
+ * <li>{*} Data to compare to the second parameter</li>
+ * <li>{*} Data to compare to the first parameter</li>
+ * </ul>
+ * </li>
+ * <li>
+ * Function return:
+ * <ul>
+ * <li>{int} Sorting match: <0 if first parameter should be sorted lower than
+ * the second parameter, ===0 if the two parameters are equal and >0 if
+ * the first parameter should be sorted height than the second parameter.</li>
+ * </ul>
+ * </il>
+ * </ul>
+ * @type object
+ * @default {}
+ *
+ * @example
+ * // Case-sensitive string sorting, with no pre-formatting method
+ * $.extend( $.fn.dataTableExt.oSort, {
+ * "string-case-asc": function(x,y) {
+ * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ * },
+ * "string-case-desc": function(x,y) {
+ * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ * }
+ * } );
+ *
+ * @example
+ * // Case-insensitive string sorting, with pre-formatting
+ * $.extend( $.fn.dataTableExt.oSort, {
+ * "string-pre": function(x) {
+ * return x.toLowerCase();
+ * },
+ * "string-asc": function(x,y) {
+ * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ * },
+ * "string-desc": function(x,y) {
+ * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ * }
+ * } );
+ */
+ "oSort": {},
+
+
+ /**
+ * Version string for plug-ins to check compatibility. Allowed format is
+ * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
+ * e are optional
+ * @type string
+ * @default Version number
+ */
+ "sVersion": DataTable.version,
+
+
+ /**
+ * How should DataTables report an error. Can take the value 'alert' or 'throw'
+ * @type string
+ * @default alert
+ */
+ "sErrMode": "alert",
+
+
+ /**
+ * Store information for DataTables to access globally about other instances
+ * @namespace
+ * @private
+ */
+ "_oExternConfig": {
+ /* int:iNextUnique - next unique number for an instance */
+ "iNextUnique": 0
+ }
+ };
+
+
+
+
+ /**
+ * Template object for the way in which DataTables holds information about
+ * search information for the global filter and individual column filters.
+ * @namespace
+ */
+ DataTable.models.oSearch = {
+ /**
+ * Flag to indicate if the filtering should be case insensitive or not
+ * @type boolean
+ * @default true
+ */
+ "bCaseInsensitive": true,
+
+ /**
+ * Applied search term
+ * @type string
+ * @default <i>Empty string</i>
+ */
+ "sSearch": "",
+
+ /**
+ * Flag to indicate if the search term should be interpreted as a
+ * regular expression (true) or not (false) and therefore and special
+ * regex characters escaped.
+ * @type boolean
+ * @default false
+ */
+ "bRegex": false,
+
+ /**
+ * Flag to indicate if DataTables is to use its smart filtering or not.
+ * @type boolean
+ * @default true
+ */
+ "bSmart": true
+ };
+
+
+
+
+ /**
+ * Template object for the way in which DataTables holds information about
+ * each individual row. This is the object format used for the settings
+ * aoData array.
+ * @namespace
+ */
+ DataTable.models.oRow = {
+ /**
+ * TR element for the row
+ * @type node
+ * @default null
+ */
+ "nTr": null,
+
+ /**
+ * Data object from the original data source for the row. This is either
+ * an array if using the traditional form of DataTables, or an object if
+ * using mData options. The exact type will depend on the passed in
+ * data from the data source, or will be an array if using DOM a data
+ * source.
+ * @type array|object
+ * @default []
+ */
+ "_aData": [],
+
+ /**
+ * Sorting data cache - this array is ostensibly the same length as the
+ * number of columns (although each index is generated only as it is
+ * needed), and holds the data that is used for sorting each column in the
+ * row. We do this cache generation at the start of the sort in order that
+ * the formatting of the sort data need be done only once for each cell
+ * per sort. This array should not be read from or written to by anything
+ * other than the master sorting methods.
+ * @type array
+ * @default []
+ * @private
+ */
+ "_aSortData": [],
+
+ /**
+ * Array of TD elements that are cached for hidden rows, so they can be
+ * reinserted into the table if a column is made visible again (or to act
+ * as a store if a column is made hidden). Only hidden columns have a
+ * reference in the array. For non-hidden columns the value is either
+ * undefined or null.
+ * @type array nodes
+ * @default []
+ * @private
+ */
+ "_anHidden": [],
+
+ /**
+ * Cache of the class name that DataTables has applied to the row, so we
+ * can quickly look at this variable rather than needing to do a DOM check
+ * on className for the nTr property.
+ * @type string
+ * @default <i>Empty string</i>
+ * @private
+ */
+ "_sRowStripe": ""
+ };
+
+
+
+ /**
+ * Template object for the column information object in DataTables. This object
+ * is held in the settings aoColumns array and contains all the information that
+ * DataTables needs about each individual column.
+ *
+ * Note that this object is related to {@link DataTable.defaults.columns}
+ * but this one is the internal data store for DataTables's cache of columns.
+ * It should NOT be manipulated outside of DataTables. Any configuration should
+ * be done through the initialisation options.
+ * @namespace
+ */
+ DataTable.models.oColumn = {
+ /**
+ * A list of the columns that sorting should occur on when this column
+ * is sorted. That this property is an array allows multi-column sorting
+ * to be defined for a column (for example first name / last name columns
+ * would benefit from this). The values are integers pointing to the
+ * columns to be sorted on (typically it will be a single integer pointing
+ * at itself, but that doesn't need to be the case).
+ * @type array
+ */
+ "aDataSort": null,
+
+ /**
+ * Define the sorting directions that are applied to the column, in sequence
+ * as the column is repeatedly sorted upon - i.e. the first value is used
+ * as the sorting direction when the column if first sorted (clicked on).
+ * Sort it again (click again) and it will move on to the next index.
+ * Repeat until loop.
+ * @type array
+ */
+ "asSorting": null,
+
+ /**
+ * Flag to indicate if the column is searchable, and thus should be included
+ * in the filtering or not.
+ * @type boolean
+ */
+ "bSearchable": null,
+
+ /**
+ * Flag to indicate if the column is sortable or not.
+ * @type boolean
+ */
+ "bSortable": null,
+
+ /**
+ * <code>Deprecated</code> When using fnRender, you have two options for what
+ * to do with the data, and this property serves as the switch. Firstly, you
+ * can have the sorting and filtering use the rendered value (true - default),
+ * or you can have the sorting and filtering us the original value (false).
+ *
+ * Please note that this option has now been deprecated and will be removed
+ * in the next version of DataTables. Please use mRender / mData rather than
+ * fnRender.
+ * @type boolean
+ * @deprecated
+ */
+ "bUseRendered": null,
+
+ /**
+ * Flag to indicate if the column is currently visible in the table or not
+ * @type boolean
+ */
+ "bVisible": null,
+
+ /**
+ * Flag to indicate to the type detection method if the automatic type
+ * detection should be used, or if a column type (sType) has been specified
+ * @type boolean
+ * @default true
+ * @private
+ */
+ "_bAutoType": true,
+
+ /**
+ * Developer definable function that is called whenever a cell is created (Ajax source,
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
+ * allowing you to modify the DOM element (add background colour for example) when the
+ * element is available.
+ * @type function
+ * @param {element} nTd The TD node that has been created
+ * @param {*} sData The Data for the cell
+ * @param {array|object} oData The data for the whole row
+ * @param {int} iRow The row index for the aoData data store
+ * @default null
+ */
+ "fnCreatedCell": null,
+
+ /**
+ * Function to get data from a cell in a column. You should <b>never</b>
+ * access data directly through _aData internally in DataTables - always use
+ * the method attached to this property. It allows mData to function as
+ * required. This function is automatically assigned by the column
+ * initialisation method
+ * @type function
+ * @param {array|object} oData The data array/object for the array
+ * (i.e. aoData[]._aData)
+ * @param {string} sSpecific The specific data type you want to get -
+ * 'display', 'type' 'filter' 'sort'
+ * @returns {*} The data for the cell from the given row's data
+ * @default null
+ */
+ "fnGetData": null,
+
+ /**
+ * <code>Deprecated</code> Custom display function that will be called for the
+ * display of each cell in this column.
+ *
+ * Please note that this option has now been deprecated and will be removed
+ * in the next version of DataTables. Please use mRender / mData rather than
+ * fnRender.
+ * @type function
+ * @param {object} o Object with the following parameters:
+ * @param {int} o.iDataRow The row in aoData
+ * @param {int} o.iDataColumn The column in question
+ * @param {array} o.aData The data for the row in question
+ * @param {object} o.oSettings The settings object for this DataTables instance
+ * @returns {string} The string you which to use in the display
+ * @default null
+ * @deprecated
+ */
+ "fnRender": null,
+
+ /**
+ * Function to set data for a cell in the column. You should <b>never</b>
+ * set the data directly to _aData internally in DataTables - always use
+ * this method. It allows mData to function as required. This function
+ * is automatically assigned by the column initialisation method
+ * @type function
+ * @param {array|object} oData The data array/object for the array
+ * (i.e. aoData[]._aData)
+ * @param {*} sValue Value to set
+ * @default null
+ */
+ "fnSetData": null,
+
+ /**
+ * Property to read the value for the cells in the column from the data
+ * source array / object. If null, then the default content is used, if a
+ * function is given then the return from the function is used.
+ * @type function|int|string|null
+ * @default null
+ */
+ "mData": null,
+
+ /**
+ * Partner property to mData which is used (only when defined) to get
+ * the data - i.e. it is basically the same as mData, but without the
+ * 'set' option, and also the data fed to it is the result from mData.
+ * This is the rendering method to match the data method of mData.
+ * @type function|int|string|null
+ * @default null
+ */
+ "mRender": null,
+
+ /**
+ * Unique header TH/TD element for this column - this is what the sorting
+ * listener is attached to (if sorting is enabled.)
+ * @type node
+ * @default null
+ */
+ "nTh": null,
+
+ /**
+ * Unique footer TH/TD element for this column (if there is one). Not used
+ * in DataTables as such, but can be used for plug-ins to reference the
+ * footer for each column.
+ * @type node
+ * @default null
+ */
+ "nTf": null,
+
+ /**
+ * The class to apply to all TD elements in the table's TBODY for the column
+ * @type string
+ * @default null
+ */
+ "sClass": null,
+
+ /**
+ * When DataTables calculates the column widths to assign to each column,
+ * it finds the longest string in each column and then constructs a
+ * temporary table and reads the widths from that. The problem with this
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
+ * string - thus the calculation can go wrong (doing it properly and putting
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
+ * a "work around" we provide this option. It will append its value to the
+ * text that is found to be the longest string for the column - i.e. padding.
+ * @type string
+ */
+ "sContentPadding": null,
+
+ /**
+ * Allows a default value to be given for a column's data, and will be used
+ * whenever a null data source is encountered (this can be because mData
+ * is set to null, or because the data source itself is null).
+ * @type string
+ * @default null
+ */
+ "sDefaultContent": null,
+
+ /**
+ * Name for the column, allowing reference to the column by name as well as
+ * by index (needs a lookup to work by name).
+ * @type string
+ */
+ "sName": null,
+
+ /**
+ * Custom sorting data type - defines which of the available plug-ins in
+ * afnSortData the custom sorting will use - if any is defined.
+ * @type string
+ * @default std
+ */
+ "sSortDataType": 'std',
+
+ /**
+ * Class to be applied to the header element when sorting on this column
+ * @type string
+ * @default null
+ */
+ "sSortingClass": null,
+
+ /**
+ * Class to be applied to the header element when sorting on this column -
+ * when jQuery UI theming is used.
+ * @type string
+ * @default null
+ */
+ "sSortingClassJUI": null,
+
+ /**
+ * Title of the column - what is seen in the TH element (nTh).
+ * @type string
+ */
+ "sTitle": null,
+
+ /**
+ * Column sorting and filtering type
+ * @type string
+ * @default null
+ */
+ "sType": null,
+
+ /**
+ * Width of the column
+ * @type string
+ * @default null
+ */
+ "sWidth": null,
+
+ /**
+ * Width of the column when it was first "encountered"
+ * @type string
+ * @default null
+ */
+ "sWidthOrig": null
+ };
+
+
+
+ /**
+ * Initialisation options that can be given to DataTables at initialisation
+ * time.
+ * @namespace
+ */
+ DataTable.defaults = {
+ /**
+ * An array of data to use for the table, passed in at initialisation which
+ * will be used in preference to any data which is already in the DOM. This is
+ * particularly useful for constructing tables purely in Javascript, for
+ * example with a custom Ajax call.
+ * @type array
+ * @default null
+ * @dtopt Option
+ *
+ * @example
+ * // Using a 2D array data source
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "aaData": [
+ * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
+ * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
+ * ],
+ * "aoColumns": [
+ * { "sTitle": "Engine" },
+ * { "sTitle": "Browser" },
+ * { "sTitle": "Platform" },
+ * { "sTitle": "Version" },
+ * { "sTitle": "Grade" }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using an array of objects as a data source (mData)
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "aaData": [
+ * {
+ * "engine": "Trident",
+ * "browser": "Internet Explorer 4.0",
+ * "platform": "Win 95+",
+ * "version": 4,
+ * "grade": "X"
+ * },
+ * {
+ * "engine": "Trident",
+ * "browser": "Internet Explorer 5.0",
+ * "platform": "Win 95+",
+ * "version": 5,
+ * "grade": "C"
+ * }
+ * ],
+ * "aoColumns": [
+ * { "sTitle": "Engine", "mData": "engine" },
+ * { "sTitle": "Browser", "mData": "browser" },
+ * { "sTitle": "Platform", "mData": "platform" },
+ * { "sTitle": "Version", "mData": "version" },
+ * { "sTitle": "Grade", "mData": "grade" }
+ * ]
+ * } );
+ * } );
+ */
+ "aaData": null,
+
+
+ /**
+ * If sorting is enabled, then DataTables will perform a first pass sort on
+ * initialisation. You can define which column(s) the sort is performed upon,
+ * and the sorting direction, with this variable. The aaSorting array should
+ * contain an array for each column to be sorted initially containing the
+ * column's index and a direction string ('asc' or 'desc').
+ * @type array
+ * @default [[0,'asc']]
+ * @dtopt Option
+ *
+ * @example
+ * // Sort by 3rd column first, and then 4th column
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aaSorting": [[2,'asc'], [3,'desc']]
+ * } );
+ * } );
+ *
+ * // No initial sorting
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aaSorting": []
+ * } );
+ * } );
+ */
+ "aaSorting": [[0,'asc']],
+
+
+ /**
+ * This parameter is basically identical to the aaSorting parameter, but
+ * cannot be overridden by user interaction with the table. What this means
+ * is that you could have a column (visible or hidden) which the sorting will
+ * always be forced on first - any sorting after that (from the user) will
+ * then be performed as required. This can be useful for grouping rows
+ * together.
+ * @type array
+ * @default null
+ * @dtopt Option
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aaSortingFixed": [[0,'asc']]
+ * } );
+ * } )
+ */
+ "aaSortingFixed": null,
+
+
+ /**
+ * This parameter allows you to readily specify the entries in the length drop
+ * down menu that DataTables shows when pagination is enabled. It can be
+ * either a 1D array of options which will be used for both the displayed
+ * option and the value, or a 2D array which will use the array in the first
+ * position as the value, and the array in the second position as the
+ * displayed options (useful for language strings such as 'All').
+ * @type array
+ * @default [ 10, 25, 50, 100 ]
+ * @dtopt Option
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
+ * } );
+ * } );
+ *
+ * @example
+ * // Setting the default display length as well as length menu
+ * // This is likely to be wanted if you remove the '10' option which
+ * // is the iDisplayLength default.
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "iDisplayLength": 25,
+ * "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]]
+ * } );
+ * } );
+ */
+ "aLengthMenu": [ 10, 25, 50, 100 ],
+
+
+ /**
+ * The aoColumns option in the initialisation parameter allows you to define
+ * details about the way individual columns behave. For a full list of
+ * column options that can be set, please see
+ * {@link DataTable.defaults.columns}. Note that if you use aoColumns to
+ * define your columns, you must have an entry in the array for every single
+ * column that you have in your table (these can be null if you don't which
+ * to specify any options).
+ * @member
+ */
+ "aoColumns": null,
+
+ /**
+ * Very similar to aoColumns, aoColumnDefs allows you to target a specific
+ * column, multiple columns, or all columns, using the aTargets property of
+ * each object in the array. This allows great flexibility when creating
+ * tables, as the aoColumnDefs arrays can be of any length, targeting the
+ * columns you specifically want. aoColumnDefs may use any of the column
+ * options available: {@link DataTable.defaults.columns}, but it _must_
+ * have aTargets defined in each object in the array. Values in the aTargets
+ * array may be:
+ * <ul>
+ * <li>a string - class name will be matched on the TH for the column</li>
+ * <li>0 or a positive integer - column index counting from the left</li>
+ * <li>a negative integer - column index counting from the right</li>
+ * <li>the string "_all" - all columns (i.e. assign a default)</li>
+ * </ul>
+ * @member
+ */
+ "aoColumnDefs": null,
+
+
+ /**
+ * Basically the same as oSearch, this parameter defines the individual column
+ * filtering state at initialisation time. The array must be of the same size
+ * as the number of columns, and each element be an object with the parameters
+ * "sSearch" and "bEscapeRegex" (the latter is optional). 'null' is also
+ * accepted and the default will be used.
+ * @type array
+ * @default []
+ * @dtopt Option
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoSearchCols": [
+ * null,
+ * { "sSearch": "My filter" },
+ * null,
+ * { "sSearch": "^[0-9]", "bEscapeRegex": false }
+ * ]
+ * } );
+ * } )
+ */
+ "aoSearchCols": [],
+
+
+ /**
+ * An array of CSS classes that should be applied to displayed rows. This
+ * array may be of any length, and DataTables will apply each class
+ * sequentially, looping when required.
+ * @type array
+ * @default null <i>Will take the values determined by the oClasses.sStripe*
+ * options</i>
+ * @dtopt Option
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "asStripeClasses": [ 'strip1', 'strip2', 'strip3' ]
+ * } );
+ * } )
+ */
+ "asStripeClasses": null,
+
+
+ /**
+ * Enable or disable automatic column width calculation. This can be disabled
+ * as an optimisation (it takes some time to calculate the widths) if the
+ * tables widths are passed in using aoColumns.
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bAutoWidth": false
+ * } );
+ * } );
+ */
+ "bAutoWidth": true,
+
+
+ /**
+ * Deferred rendering can provide DataTables with a huge speed boost when you
+ * are using an Ajax or JS data source for the table. This option, when set to
+ * true, will cause DataTables to defer the creation of the table elements for
+ * each row until they are needed for a draw - saving a significant amount of
+ * time.
+ * @type boolean
+ * @default false
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "sAjaxSource": "sources/arrays.txt",
+ * "bDeferRender": true
+ * } );
+ * } );
+ */
+ "bDeferRender": false,
+
+
+ /**
+ * Replace a DataTable which matches the given selector and replace it with
+ * one which has the properties of the new initialisation object passed. If no
+ * table matches the selector, then the new DataTable will be constructed as
+ * per normal.
+ * @type boolean
+ * @default false
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sScrollY": "200px",
+ * "bPaginate": false
+ * } );
+ *
+ * // Some time later....
+ * $('#example').dataTable( {
+ * "bFilter": false,
+ * "bDestroy": true
+ * } );
+ * } );
+ */
+ "bDestroy": false,
+
+
+ /**
+ * Enable or disable filtering of data. Filtering in DataTables is "smart" in
+ * that it allows the end user to input multiple words (space separated) and
+ * will match a row containing those words, even if not in the order that was
+ * specified (this allow matching across multiple columns). Note that if you
+ * wish to use filtering in DataTables this must remain 'true' - to remove the
+ * default filtering input box and retain filtering abilities, please use
+ * {@link DataTable.defaults.sDom}.
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bFilter": false
+ * } );
+ * } );
+ */
+ "bFilter": true,
+
+
+ /**
+ * Enable or disable the table information display. This shows information
+ * about the data that is currently visible on the page, including information
+ * about filtered data if that action is being performed.
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bInfo": false
+ * } );
+ * } );
+ */
+ "bInfo": true,
+
+
+ /**
+ * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
+ * slightly different and additional mark-up from what DataTables has
+ * traditionally used).
+ * @type boolean
+ * @default false
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bJQueryUI": true
+ * } );
+ * } );
+ */
+ "bJQueryUI": false,
+
+
+ /**
+ * Allows the end user to select the size of a formatted page from a select
+ * menu (sizes are 10, 25, 50 and 100). Requires pagination (bPaginate).
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bLengthChange": false
+ * } );
+ * } );
+ */
+ "bLengthChange": true,
+
+
+ /**
+ * Enable or disable pagination.
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bPaginate": false
+ * } );
+ * } );
+ */
+ "bPaginate": true,
+
+
+ /**
+ * Enable or disable the display of a 'processing' indicator when the table is
+ * being processed (e.g. a sort). This is particularly useful for tables with
+ * large amounts of data where it can take a noticeable amount of time to sort
+ * the entries.
+ * @type boolean
+ * @default false
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bProcessing": true
+ * } );
+ * } );
+ */
+ "bProcessing": false,
+
+
+ /**
+ * Retrieve the DataTables object for the given selector. Note that if the
+ * table has already been initialised, this parameter will cause DataTables
+ * to simply return the object that has already been set up - it will not take
+ * account of any changes you might have made to the initialisation object
+ * passed to DataTables (setting this parameter to true is an acknowledgement
+ * that you understand this). bDestroy can be used to reinitialise a table if
+ * you need.
+ * @type boolean
+ * @default false
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * initTable();
+ * tableActions();
+ * } );
+ *
+ * function initTable ()
+ * {
+ * return $('#example').dataTable( {
+ * "sScrollY": "200px",
+ * "bPaginate": false,
+ * "bRetrieve": true
+ * } );
+ * }
+ *
+ * function tableActions ()
+ * {
+ * var oTable = initTable();
+ * // perform API operations with oTable
+ * }
+ */
+ "bRetrieve": false,
+
+
+ /**
+ * Indicate if DataTables should be allowed to set the padding / margin
+ * etc for the scrolling header elements or not. Typically you will want
+ * this.
+ * @type boolean
+ * @default true
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bScrollAutoCss": false,
+ * "sScrollY": "200px"
+ * } );
+ * } );
+ */
+ "bScrollAutoCss": true,
+
+
+ /**
+ * When vertical (y) scrolling is enabled, DataTables will force the height of
+ * the table's viewport to the given height at all times (useful for layout).
+ * However, this can look odd when filtering data down to a small data set,
+ * and the footer is left "floating" further down. This parameter (when
+ * enabled) will cause DataTables to collapse the table's viewport down when
+ * the result set will fit within the given Y height.
+ * @type boolean
+ * @default false
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sScrollY": "200",
+ * "bScrollCollapse": true
+ * } );
+ * } );
+ */
+ "bScrollCollapse": false,
+
+
+ /**
+ * Enable infinite scrolling for DataTables (to be used in combination with
+ * sScrollY). Infinite scrolling means that DataTables will continually load
+ * data as a user scrolls through a table, which is very useful for large
+ * dataset. This cannot be used with pagination, which is automatically
+ * disabled. Note - the Scroller extra for DataTables is recommended in
+ * in preference to this option.
+ * @type boolean
+ * @default false
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bScrollInfinite": true,
+ * "bScrollCollapse": true,
+ * "sScrollY": "200px"
+ * } );
+ * } );
+ */
+ "bScrollInfinite": false,
+
+
+ /**
+ * Configure DataTables to use server-side processing. Note that the
+ * sAjaxSource parameter must also be given in order to give DataTables a
+ * source to obtain the required data for each draw.
+ * @type boolean
+ * @default false
+ * @dtopt Features
+ * @dtopt Server-side
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bServerSide": true,
+ * "sAjaxSource": "xhr.php"
+ * } );
+ * } );
+ */
+ "bServerSide": false,
+
+
+ /**
+ * Enable or disable sorting of columns. Sorting of individual columns can be
+ * disabled by the "bSortable" option for each column.
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bSort": false
+ * } );
+ * } );
+ */
+ "bSort": true,
+
+
+ /**
+ * Allows control over whether DataTables should use the top (true) unique
+ * cell that is found for a single column, or the bottom (false - default).
+ * This is useful when using complex headers.
+ * @type boolean
+ * @default false
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bSortCellsTop": true
+ * } );
+ * } );
+ */
+ "bSortCellsTop": false,
+
+
+ /**
+ * Enable or disable the addition of the classes 'sorting_1', 'sorting_2' and
+ * 'sorting_3' to the columns which are currently being sorted on. This is
+ * presented as a feature switch as it can increase processing time (while
+ * classes are removed and added) so for large data sets you might want to
+ * turn this off.
+ * @type boolean
+ * @default true
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bSortClasses": false
+ * } );
+ * } );
+ */
+ "bSortClasses": true,
+
+
+ /**
+ * Enable or disable state saving. When enabled a cookie will be used to save
+ * table display information such as pagination information, display length,
+ * filtering and sorting. As such when the end user reloads the page the
+ * display display will match what thy had previously set up.
+ * @type boolean
+ * @default false
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "bStateSave": true
+ * } );
+ * } );
+ */
+ "bStateSave": false,
+
+
+ /**
+ * Customise the cookie and / or the parameters being stored when using
+ * DataTables with state saving enabled. This function is called whenever
+ * the cookie is modified, and it expects a fully formed cookie string to be
+ * returned. Note that the data object passed in is a Javascript object which
+ * must be converted to a string (JSON.stringify for example).
+ * @type function
+ * @param {string} sName Name of the cookie defined by DataTables
+ * @param {object} oData Data to be stored in the cookie
+ * @param {string} sExpires Cookie expires string
+ * @param {string} sPath Path of the cookie to set
+ * @returns {string} Cookie formatted string (which should be encoded by
+ * using encodeURIComponent())
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "fnCookieCallback": function (sName, oData, sExpires, sPath) {
+ * // Customise oData or sName or whatever else here
+ * return sName + "="+JSON.stringify(oData)+"; expires=" + sExpires +"; path=" + sPath;
+ * }
+ * } );
+ * } );
+ */
+ "fnCookieCallback": null,
+
+
+ /**
+ * This function is called when a TR element is created (and all TD child
+ * elements have been inserted), or registered if using a DOM source, allowing
+ * manipulation of the TR element (adding classes etc).
+ * @type function
+ * @param {node} nRow "TR" element for the current row
+ * @param {array} aData Raw data array for this row
+ * @param {int} iDataIndex The index of this row in aoData
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnCreatedRow": function( nRow, aData, iDataIndex ) {
+ * // Bold the grade for all 'A' grade browsers
+ * if ( aData[4] == "A" )
+ * {
+ * $('td:eq(4)', nRow).html( '<b>A</b>' );
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "fnCreatedRow": null,
+
+
+ /**
+ * This function is called on every 'draw' event, and allows you to
+ * dynamically modify any aspect you want about the created DOM.
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnDrawCallback": function( oSettings ) {
+ * alert( 'DataTables has redrawn the table' );
+ * }
+ * } );
+ * } );
+ */
+ "fnDrawCallback": null,
+
+
+ /**
+ * Identical to fnHeaderCallback() but for the table footer this function
+ * allows you to modify the table footer on every 'draw' even.
+ * @type function
+ * @param {node} nFoot "TR" element for the footer
+ * @param {array} aData Full table data (as derived from the original HTML)
+ * @param {int} iStart Index for the current display starting point in the
+ * display array
+ * @param {int} iEnd Index for the current display ending point in the
+ * display array
+ * @param {array int} aiDisplay Index array to translate the visual position
+ * to the full data array
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnFooterCallback": function( nFoot, aData, iStart, iEnd, aiDisplay ) {
+ * nFoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+iStart;
+ * }
+ * } );
+ * } )
+ */
+ "fnFooterCallback": null,
+
+
+ /**
+ * When rendering large numbers in the information element for the table
+ * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
+ * to have a comma separator for the 'thousands' units (e.g. 1 million is
+ * rendered as "1,000,000") to help readability for the end user. This
+ * function will override the default method DataTables uses.
+ * @type function
+ * @member
+ * @param {int} iIn number to be formatted
+ * @returns {string} formatted string for DataTables to show the number
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnFormatNumber": function ( iIn ) {
+ * if ( iIn &lt; 1000 ) {
+ * return iIn;
+ * } else {
+ * var
+ * s=(iIn+""),
+ * a=s.split(""), out="",
+ * iLen=s.length;
+ *
+ * for ( var i=0 ; i&lt;iLen ; i++ ) {
+ * if ( i%3 === 0 &amp;&amp; i !== 0 ) {
+ * out = "'"+out;
+ * }
+ * out = a[iLen-i-1]+out;
+ * }
+ * }
+ * return out;
+ * };
+ * } );
+ * } );
+ */
+ "fnFormatNumber": function ( iIn ) {
+ if ( iIn < 1000 )
+ {
+ // A small optimisation for what is likely to be the majority of use cases
+ return iIn;
+ }
+
+ var s=(iIn+""), a=s.split(""), out="", iLen=s.length;
+
+ for ( var i=0 ; i<iLen ; i++ )
+ {
+ if ( i%3 === 0 && i !== 0 )
+ {
+ out = this.oLanguage.sInfoThousands+out;
+ }
+ out = a[iLen-i-1]+out;
+ }
+ return out;
+ },
+
+
+ /**
+ * This function is called on every 'draw' event, and allows you to
+ * dynamically modify the header row. This can be used to calculate and
+ * display useful information about the table.
+ * @type function
+ * @param {node} nHead "TR" element for the header
+ * @param {array} aData Full table data (as derived from the original HTML)
+ * @param {int} iStart Index for the current display starting point in the
+ * display array
+ * @param {int} iEnd Index for the current display ending point in the
+ * display array
+ * @param {array int} aiDisplay Index array to translate the visual position
+ * to the full data array
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnHeaderCallback": function( nHead, aData, iStart, iEnd, aiDisplay ) {
+ * nHead.getElementsByTagName('th')[0].innerHTML = "Displaying "+(iEnd-iStart)+" records";
+ * }
+ * } );
+ * } )
+ */
+ "fnHeaderCallback": null,
+
+
+ /**
+ * The information element can be used to convey information about the current
+ * state of the table. Although the internationalisation options presented by
+ * DataTables are quite capable of dealing with most customisations, there may
+ * be times where you wish to customise the string further. This callback
+ * allows you to do exactly that.
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @param {int} iStart Starting position in data for the draw
+ * @param {int} iEnd End position in data for the draw
+ * @param {int} iMax Total number of rows in the table (regardless of
+ * filtering)
+ * @param {int} iTotal Total number of rows in the data set, after filtering
+ * @param {string} sPre The string that DataTables has formatted using it's
+ * own rules
+ * @returns {string} The string to be displayed in the information element.
+ * @dtopt Callbacks
+ *
+ * @example
+ * $('#example').dataTable( {
+ * "fnInfoCallback": function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) {
+ * return iStart +" to "+ iEnd;
+ * }
+ * } );
+ */
+ "fnInfoCallback": null,
+
+
+ /**
+ * Called when the table has been initialised. Normally DataTables will
+ * initialise sequentially and there will be no need for this function,
+ * however, this does not hold true when using external language information
+ * since that is obtained using an async XHR call.
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @param {object} json The JSON object request from the server - only
+ * present if client-side Ajax sourced data is used
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnInitComplete": function(oSettings, json) {
+ * alert( 'DataTables has finished its initialisation.' );
+ * }
+ * } );
+ * } )
+ */
+ "fnInitComplete": null,
+
+
+ /**
+ * Called at the very start of each table draw and can be used to cancel the
+ * draw by returning false, any other return (including undefined) results in
+ * the full draw occurring).
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @returns {boolean} False will cancel the draw, anything else (including no
+ * return) will allow it to complete.
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnPreDrawCallback": function( oSettings ) {
+ * if ( $('#test').val() == 1 ) {
+ * return false;
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "fnPreDrawCallback": null,
+
+
+ /**
+ * This function allows you to 'post process' each row after it have been
+ * generated for each table draw, but before it is rendered on screen. This
+ * function might be used for setting the row class name etc.
+ * @type function
+ * @param {node} nRow "TR" element for the current row
+ * @param {array} aData Raw data array for this row
+ * @param {int} iDisplayIndex The display index for the current table draw
+ * @param {int} iDisplayIndexFull The index of the data in the full list of
+ * rows (after filtering)
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
+ * // Bold the grade for all 'A' grade browsers
+ * if ( aData[4] == "A" )
+ * {
+ * $('td:eq(4)', nRow).html( '<b>A</b>' );
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "fnRowCallback": null,
+
+
+ /**
+ * This parameter allows you to override the default function which obtains
+ * the data from the server ($.getJSON) so something more suitable for your
+ * application. For example you could use POST data, or pull information from
+ * a Gears or AIR database.
+ * @type function
+ * @member
+ * @param {string} sSource HTTP source to obtain the data from (sAjaxSource)
+ * @param {array} aoData A key/value pair object containing the data to send
+ * to the server
+ * @param {function} fnCallback to be called on completion of the data get
+ * process that will draw the data on the page.
+ * @param {object} oSettings DataTables settings object
+ * @dtopt Callbacks
+ * @dtopt Server-side
+ *
+ * @example
+ * // POST data to server
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bProcessing": true,
+ * "bServerSide": true,
+ * "sAjaxSource": "xhr.php",
+ * "fnServerData": function ( sSource, aoData, fnCallback, oSettings ) {
+ * oSettings.jqXHR = $.ajax( {
+ * "dataType": 'json',
+ * "type": "POST",
+ * "url": sSource,
+ * "data": aoData,
+ * "success": fnCallback
+ * } );
+ * }
+ * } );
+ * } );
+ */
+ "fnServerData": function ( sUrl, aoData, fnCallback, oSettings ) {
+ oSettings.jqXHR = $.ajax( {
+ "url": sUrl,
+ "data": aoData,
+ "success": function (json) {
+ if ( json.sError ) {
+ oSettings.oApi._fnLog( oSettings, 0, json.sError );
+ }
+
+ $(oSettings.oInstance).trigger('xhr', [oSettings, json]);
+ fnCallback( json );
+ },
+ "dataType": "json",
+ "cache": false,
+ "type": oSettings.sServerMethod,
+ "error": function (xhr, error, thrown) {
+ if ( error == "parsererror" ) {
+ oSettings.oApi._fnLog( oSettings, 0, "DataTables warning: JSON data from "+
+ "server could not be parsed. This is caused by a JSON formatting error." );
+ }
+ }
+ } );
+ },
+
+
+ /**
+ * It is often useful to send extra data to the server when making an Ajax
+ * request - for example custom filtering information, and this callback
+ * function makes it trivial to send extra information to the server. The
+ * passed in parameter is the data set that has been constructed by
+ * DataTables, and you can add to this or modify it as you require.
+ * @type function
+ * @param {array} aoData Data array (array of objects which are name/value
+ * pairs) that has been constructed by DataTables and will be sent to the
+ * server. In the case of Ajax sourced data with server-side processing
+ * this will be an empty array, for server-side processing there will be a
+ * significant number of parameters!
+ * @returns {undefined} Ensure that you modify the aoData array passed in,
+ * as this is passed by reference.
+ * @dtopt Callbacks
+ * @dtopt Server-side
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bProcessing": true,
+ * "bServerSide": true,
+ * "sAjaxSource": "scripts/server_processing.php",
+ * "fnServerParams": function ( aoData ) {
+ * aoData.push( { "name": "more_data", "value": "my_value" } );
+ * }
+ * } );
+ * } );
+ */
+ "fnServerParams": null,
+
+
+ /**
+ * Load the table state. With this function you can define from where, and how, the
+ * state of a table is loaded. By default DataTables will load from its state saving
+ * cookie, but you might wish to use local storage (HTML5) or a server-side database.
+ * @type function
+ * @member
+ * @param {object} oSettings DataTables settings object
+ * @return {object} The DataTables state object to be loaded
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bStateSave": true,
+ * "fnStateLoad": function (oSettings) {
+ * var o;
+ *
+ * // Send an Ajax request to the server to get the data. Note that
+ * // this is a synchronous request.
+ * $.ajax( {
+ * "url": "/state_load",
+ * "async": false,
+ * "dataType": "json",
+ * "success": function (json) {
+ * o = json;
+ * }
+ * } );
+ *
+ * return o;
+ * }
+ * } );
+ * } );
+ */
+ "fnStateLoad": function ( oSettings ) {
+ var sData = this.oApi._fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance );
+ var oData;
+
+ try {
+ oData = (typeof $.parseJSON === 'function') ?
+ $.parseJSON(sData) : eval( '('+sData+')' );
+ } catch (e) {
+ oData = null;
+ }
+
+ return oData;
+ },
+
+
+ /**
+ * Callback which allows modification of the saved state prior to loading that state.
+ * This callback is called when the table is loading state from the stored data, but
+ * prior to the settings object being modified by the saved state. Note that for
+ * plug-in authors, you should use the 'stateLoadParams' event to load parameters for
+ * a plug-in.
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @param {object} oData The state object that is to be loaded
+ * @dtopt Callbacks
+ *
+ * @example
+ * // Remove a saved filter, so filtering is never loaded
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bStateSave": true,
+ * "fnStateLoadParams": function (oSettings, oData) {
+ * oData.oSearch.sSearch = "";
+ * }
+ * } );
+ * } );
+ *
+ * @example
+ * // Disallow state loading by returning false
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bStateSave": true,
+ * "fnStateLoadParams": function (oSettings, oData) {
+ * return false;
+ * }
+ * } );
+ * } );
+ */
+ "fnStateLoadParams": null,
+
+
+ /**
+ * Callback that is called when the state has been loaded from the state saving method
+ * and the DataTables settings object has been modified as a result of the loaded state.
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @param {object} oData The state object that was loaded
+ * @dtopt Callbacks
+ *
+ * @example
+ * // Show an alert with the filtering value that was saved
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bStateSave": true,
+ * "fnStateLoaded": function (oSettings, oData) {
+ * alert( 'Saved filter was: '+oData.oSearch.sSearch );
+ * }
+ * } );
+ * } );
+ */
+ "fnStateLoaded": null,
+
+
+ /**
+ * Save the table state. This function allows you to define where and how the state
+ * information for the table is stored - by default it will use a cookie, but you
+ * might want to use local storage (HTML5) or a server-side database.
+ * @type function
+ * @member
+ * @param {object} oSettings DataTables settings object
+ * @param {object} oData The state object to be saved
+ * @dtopt Callbacks
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bStateSave": true,
+ * "fnStateSave": function (oSettings, oData) {
+ * // Send an Ajax request to the server with the state object
+ * $.ajax( {
+ * "url": "/state_save",
+ * "data": oData,
+ * "dataType": "json",
+ * "method": "POST"
+ * "success": function () {}
+ * } );
+ * }
+ * } );
+ * } );
+ */
+ "fnStateSave": function ( oSettings, oData ) {
+ this.oApi._fnCreateCookie(
+ oSettings.sCookiePrefix+oSettings.sInstance,
+ this.oApi._fnJsonString(oData),
+ oSettings.iCookieDuration,
+ oSettings.sCookiePrefix,
+ oSettings.fnCookieCallback
+ );
+ },
+
+
+ /**
+ * Callback which allows modification of the state to be saved. Called when the table
+ * has changed state a new state save is required. This method allows modification of
+ * the state saving object prior to actually doing the save, including addition or
+ * other state properties or modification. Note that for plug-in authors, you should
+ * use the 'stateSaveParams' event to save parameters for a plug-in.
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @param {object} oData The state object to be saved
+ * @dtopt Callbacks
+ *
+ * @example
+ * // Remove a saved filter, so filtering is never saved
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bStateSave": true,
+ * "fnStateSaveParams": function (oSettings, oData) {
+ * oData.oSearch.sSearch = "";
+ * }
+ * } );
+ * } );
+ */
+ "fnStateSaveParams": null,
+
+
+ /**
+ * Duration of the cookie which is used for storing session information. This
+ * value is given in seconds.
+ * @type int
+ * @default 7200 <i>(2 hours)</i>
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "iCookieDuration": 60*60*24; // 1 day
+ * } );
+ * } )
+ */
+ "iCookieDuration": 7200,
+
+
+ /**
+ * When enabled DataTables will not make a request to the server for the first
+ * page draw - rather it will use the data already on the page (no sorting etc
+ * will be applied to it), thus saving on an XHR at load time. iDeferLoading
+ * is used to indicate that deferred loading is required, but it is also used
+ * to tell DataTables how many records there are in the full table (allowing
+ * the information element and pagination to be displayed correctly). In the case
+ * where a filtering is applied to the table on initial load, this can be
+ * indicated by giving the parameter as an array, where the first element is
+ * the number of records available after filtering and the second element is the
+ * number of records without filtering (allowing the table information element
+ * to be shown correctly).
+ * @type int | array
+ * @default null
+ * @dtopt Options
+ *
+ * @example
+ * // 57 records available in the table, no filtering applied
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bServerSide": true,
+ * "sAjaxSource": "scripts/server_processing.php",
+ * "iDeferLoading": 57
+ * } );
+ * } );
+ *
+ * @example
+ * // 57 records after filtering, 100 without filtering (an initial filter applied)
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bServerSide": true,
+ * "sAjaxSource": "scripts/server_processing.php",
+ * "iDeferLoading": [ 57, 100 ],
+ * "oSearch": {
+ * "sSearch": "my_filter"
+ * }
+ * } );
+ * } );
+ */
+ "iDeferLoading": null,
+
+
+ /**
+ * Number of rows to display on a single page when using pagination. If
+ * feature enabled (bLengthChange) then the end user will be able to override
+ * this to a custom setting using a pop-up menu.
+ * @type int
+ * @default 10
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "iDisplayLength": 50
+ * } );
+ * } )
+ */
+ "iDisplayLength": 10,
+
+
+ /**
+ * Define the starting point for data display when using DataTables with
+ * pagination. Note that this parameter is the number of records, rather than
+ * the page number, so if you have 10 records per page and want to start on
+ * the third page, it should be "20".
+ * @type int
+ * @default 0
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "iDisplayStart": 20
+ * } );
+ * } )
+ */
+ "iDisplayStart": 0,
+
+
+ /**
+ * The scroll gap is the amount of scrolling that is left to go before
+ * DataTables will load the next 'page' of data automatically. You typically
+ * want a gap which is big enough that the scrolling will be smooth for the
+ * user, while not so large that it will load more data than need.
+ * @type int
+ * @default 100
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bScrollInfinite": true,
+ * "bScrollCollapse": true,
+ * "sScrollY": "200px",
+ * "iScrollLoadGap": 50
+ * } );
+ * } );
+ */
+ "iScrollLoadGap": 100,
+
+
+ /**
+ * By default DataTables allows keyboard navigation of the table (sorting, paging,
+ * and filtering) by adding a tabindex attribute to the required elements. This
+ * allows you to tab through the controls and press the enter key to activate them.
+ * The tabindex is default 0, meaning that the tab follows the flow of the document.
+ * You can overrule this using this parameter if you wish. Use a value of -1 to
+ * disable built-in keyboard navigation.
+ * @type int
+ * @default 0
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "iTabIndex": 1
+ * } );
+ * } );
+ */
+ "iTabIndex": 0,
+
+
+ /**
+ * All strings that DataTables uses in the user interface that it creates
+ * are defined in this object, allowing you to modified them individually or
+ * completely replace them all as required.
+ * @namespace
+ */
+ "oLanguage": {
+ /**
+ * Strings that are used for WAI-ARIA labels and controls only (these are not
+ * actually visible on the page, but will be read by screenreaders, and thus
+ * must be internationalised as well).
+ * @namespace
+ */
+ "oAria": {
+ /**
+ * ARIA label that is added to the table headers when the column may be
+ * sorted ascending by activing the column (click or return when focused).
+ * Note that the column header is prefixed to this string.
+ * @type string
+ * @default : activate to sort column ascending
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "oAria": {
+ * "sSortAscending": " - click/return to sort ascending"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sSortAscending": ": activate to sort column ascending",
+
+ /**
+ * ARIA label that is added to the table headers when the column may be
+ * sorted descending by activing the column (click or return when focused).
+ * Note that the column header is prefixed to this string.
+ * @type string
+ * @default : activate to sort column ascending
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "oAria": {
+ * "sSortDescending": " - click/return to sort descending"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sSortDescending": ": activate to sort column descending"
+ },
+
+ /**
+ * Pagination string used by DataTables for the two built-in pagination
+ * control types ("two_button" and "full_numbers")
+ * @namespace
+ */
+ "oPaginate": {
+ /**
+ * Text to use when using the 'full_numbers' type of pagination for the
+ * button to take the user to the first page.
+ * @type string
+ * @default First
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "oPaginate": {
+ * "sFirst": "First page"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sFirst": "First",
+
+
+ /**
+ * Text to use when using the 'full_numbers' type of pagination for the
+ * button to take the user to the last page.
+ * @type string
+ * @default Last
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "oPaginate": {
+ * "sLast": "Last page"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sLast": "Last",
+
+
+ /**
+ * Text to use for the 'next' pagination button (to take the user to the
+ * next page).
+ * @type string
+ * @default Next
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "oPaginate": {
+ * "sNext": "Next page"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sNext": "Next",
+
+
+ /**
+ * Text to use for the 'previous' pagination button (to take the user to
+ * the previous page).
+ * @type string
+ * @default Previous
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "oPaginate": {
+ * "sPrevious": "Previous page"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sPrevious": "Previous"
+ },
+
+ /**
+ * This string is shown in preference to sZeroRecords when the table is
+ * empty of data (regardless of filtering). Note that this is an optional
+ * parameter - if it is not given, the value of sZeroRecords will be used
+ * instead (either the default or given value).
+ * @type string
+ * @default No data available in table
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sEmptyTable": "No data available in table"
+ * }
+ * } );
+ * } );
+ */
+ "sEmptyTable": "No data available in table",
+
+
+ /**
+ * This string gives information to the end user about the information that
+ * is current on display on the page. The _START_, _END_ and _TOTAL_
+ * variables are all dynamically replaced as the table display updates, and
+ * can be freely moved or removed as the language requirements change.
+ * @type string
+ * @default Showing _START_ to _END_ of _TOTAL_ entries
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sInfo": "Got a total of _TOTAL_ entries to show (_START_ to _END_)"
+ * }
+ * } );
+ * } );
+ */
+ "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
+
+
+ /**
+ * Display information string for when the table is empty. Typically the
+ * format of this string should match sInfo.
+ * @type string
+ * @default Showing 0 to 0 of 0 entries
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sInfoEmpty": "No entries to show"
+ * }
+ * } );
+ * } );
+ */
+ "sInfoEmpty": "Showing 0 to 0 of 0 entries",
+
+
+ /**
+ * When a user filters the information in a table, this string is appended
+ * to the information (sInfo) to give an idea of how strong the filtering
+ * is. The variable _MAX_ is dynamically updated.
+ * @type string
+ * @default (filtered from _MAX_ total entries)
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sInfoFiltered": " - filtering from _MAX_ records"
+ * }
+ * } );
+ * } );
+ */
+ "sInfoFiltered": "(filtered from _MAX_ total entries)",
+
+
+ /**
+ * If can be useful to append extra information to the info string at times,
+ * and this variable does exactly that. This information will be appended to
+ * the sInfo (sInfoEmpty and sInfoFiltered in whatever combination they are
+ * being used) at all times.
+ * @type string
+ * @default <i>Empty string</i>
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sInfoPostFix": "All records shown are derived from real information."
+ * }
+ * } );
+ * } );
+ */
+ "sInfoPostFix": "",
+
+
+ /**
+ * DataTables has a build in number formatter (fnFormatNumber) which is used
+ * to format large numbers that are used in the table information. By
+ * default a comma is used, but this can be trivially changed to any
+ * character you wish with this parameter.
+ * @type string
+ * @default ,
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sInfoThousands": "'"
+ * }
+ * } );
+ * } );
+ */
+ "sInfoThousands": ",",
+
+
+ /**
+ * Detail the action that will be taken when the drop down menu for the
+ * pagination length option is changed. The '_MENU_' variable is replaced
+ * with a default select list of 10, 25, 50 and 100, and can be replaced
+ * with a custom select box if required.
+ * @type string
+ * @default Show _MENU_ entries
+ * @dtopt Language
+ *
+ * @example
+ * // Language change only
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sLengthMenu": "Display _MENU_ records"
+ * }
+ * } );
+ * } );
+ *
+ * @example
+ * // Language and options change
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sLengthMenu": 'Display <select>'+
+ * '<option value="10">10</option>'+
+ * '<option value="20">20</option>'+
+ * '<option value="30">30</option>'+
+ * '<option value="40">40</option>'+
+ * '<option value="50">50</option>'+
+ * '<option value="-1">All</option>'+
+ * '</select> records'
+ * }
+ * } );
+ * } );
+ */
+ "sLengthMenu": "Show _MENU_ entries",
+
+
+ /**
+ * When using Ajax sourced data and during the first draw when DataTables is
+ * gathering the data, this message is shown in an empty row in the table to
+ * indicate to the end user the the data is being loaded. Note that this
+ * parameter is not used when loading data by server-side processing, just
+ * Ajax sourced data with client-side processing.
+ * @type string
+ * @default Loading...
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sLoadingRecords": "Please wait - loading..."
+ * }
+ * } );
+ * } );
+ */
+ "sLoadingRecords": "Loading...",
+
+
+ /**
+ * Text which is displayed when the table is processing a user action
+ * (usually a sort command or similar).
+ * @type string
+ * @default Processing...
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sProcessing": "DataTables is currently busy"
+ * }
+ * } );
+ * } );
+ */
+ "sProcessing": "Processing...",
+
+
+ /**
+ * Details the actions that will be taken when the user types into the
+ * filtering input text box. The variable "_INPUT_", if used in the string,
+ * is replaced with the HTML text box for the filtering input allowing
+ * control over where it appears in the string. If "_INPUT_" is not given
+ * then the input box is appended to the string automatically.
+ * @type string
+ * @default Search:
+ * @dtopt Language
+ *
+ * @example
+ * // Input text box will be appended at the end automatically
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sSearch": "Filter records:"
+ * }
+ * } );
+ * } );
+ *
+ * @example
+ * // Specify where the filter should appear
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sSearch": "Apply filter _INPUT_ to table"
+ * }
+ * } );
+ * } );
+ */
+ "sSearch": "Search:",
+
+
+ /**
+ * All of the language information can be stored in a file on the
+ * server-side, which DataTables will look up if this parameter is passed.
+ * It must store the URL of the language file, which is in a JSON format,
+ * and the object has the same properties as the oLanguage object in the
+ * initialiser object (i.e. the above parameters). Please refer to one of
+ * the example language files to see how this works in action.
+ * @type string
+ * @default <i>Empty string - i.e. disabled</i>
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sUrl": "http://www.sprymedia.co.uk/dataTables/lang.txt"
+ * }
+ * } );
+ * } );
+ */
+ "sUrl": "",
+
+
+ /**
+ * Text shown inside the table records when the is no information to be
+ * displayed after filtering. sEmptyTable is shown when there is simply no
+ * information in the table at all (regardless of filtering).
+ * @type string
+ * @default No matching records found
+ * @dtopt Language
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oLanguage": {
+ * "sZeroRecords": "No records to display"
+ * }
+ * } );
+ * } );
+ */
+ "sZeroRecords": "No matching records found"
+ },
+
+
+ /**
+ * This parameter allows you to have define the global filtering state at
+ * initialisation time. As an object the "sSearch" parameter must be
+ * defined, but all other parameters are optional. When "bRegex" is true,
+ * the search string will be treated as a regular expression, when false
+ * (default) it will be treated as a straight string. When "bSmart"
+ * DataTables will use it's smart filtering methods (to word match at
+ * any point in the data), when false this will not be done.
+ * @namespace
+ * @extends DataTable.models.oSearch
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "oSearch": {"sSearch": "Initial search"}
+ * } );
+ * } )
+ */
+ "oSearch": $.extend( {}, DataTable.models.oSearch ),
+
+
+ /**
+ * By default DataTables will look for the property 'aaData' when obtaining
+ * data from an Ajax source or for server-side processing - this parameter
+ * allows that property to be changed. You can use Javascript dotted object
+ * notation to get a data source for multiple levels of nesting.
+ * @type string
+ * @default aaData
+ * @dtopt Options
+ * @dtopt Server-side
+ *
+ * @example
+ * // Get data from { "data": [...] }
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "sAjaxSource": "sources/data.txt",
+ * "sAjaxDataProp": "data"
+ * } );
+ * } );
+ *
+ * @example
+ * // Get data from { "data": { "inner": [...] } }
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "sAjaxSource": "sources/data.txt",
+ * "sAjaxDataProp": "data.inner"
+ * } );
+ * } );
+ */
+ "sAjaxDataProp": "aaData",
+
+
+ /**
+ * You can instruct DataTables to load data from an external source using this
+ * parameter (use aData if you want to pass data in you already have). Simply
+ * provide a url a JSON object can be obtained from. This object must include
+ * the parameter 'aaData' which is the data source for the table.
+ * @type string
+ * @default null
+ * @dtopt Options
+ * @dtopt Server-side
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sAjaxSource": "http://www.sprymedia.co.uk/dataTables/json.php"
+ * } );
+ * } )
+ */
+ "sAjaxSource": null,
+
+
+ /**
+ * This parameter can be used to override the default prefix that DataTables
+ * assigns to a cookie when state saving is enabled.
+ * @type string
+ * @default SpryMedia_DataTables_
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sCookiePrefix": "my_datatable_",
+ * } );
+ * } );
+ */
+ "sCookiePrefix": "SpryMedia_DataTables_",
+
+
+ /**
+ * This initialisation variable allows you to specify exactly where in the
+ * DOM you want DataTables to inject the various controls it adds to the page
+ * (for example you might want the pagination controls at the top of the
+ * table). DIV elements (with or without a custom class) can also be added to
+ * aid styling. The follow syntax is used:
+ * <ul>
+ * <li>The following options are allowed:
+ * <ul>
+ * <li>'l' - Length changing</li
+ * <li>'f' - Filtering input</li>
+ * <li>'t' - The table!</li>
+ * <li>'i' - Information</li>
+ * <li>'p' - Pagination</li>
+ * <li>'r' - pRocessing</li>
+ * </ul>
+ * </li>
+ * <li>The following constants are allowed:
+ * <ul>
+ * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
+ * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
+ * </ul>
+ * </li>
+ * <li>The following syntax is expected:
+ * <ul>
+ * <li>'&lt;' and '&gt;' - div elements</li>
+ * <li>'&lt;"class" and '&gt;' - div with a class</li>
+ * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
+ * </ul>
+ * </li>
+ * <li>Examples:
+ * <ul>
+ * <li>'&lt;"wrapper"flipt&gt;'</li>
+ * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * @type string
+ * @default lfrtip <i>(when bJQueryUI is false)</i> <b>or</b>
+ * <"H"lfr>t<"F"ip> <i>(when bJQueryUI is true)</i>
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sDom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
+ * } );
+ * } );
+ */
+ "sDom": "lfrtip",
+
+
+ /**
+ * DataTables features two different built-in pagination interaction methods
+ * ('two_button' or 'full_numbers') which present different page controls to
+ * the end user. Further methods can be added using the API (see below).
+ * @type string
+ * @default two_button
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sPaginationType": "full_numbers"
+ * } );
+ * } )
+ */
+ "sPaginationType": "two_button",
+
+
+ /**
+ * Enable horizontal scrolling. When a table is too wide to fit into a certain
+ * layout, or you have a large number of columns in the table, you can enable
+ * x-scrolling to show the table in a viewport, which can be scrolled. This
+ * property can be any CSS unit, or a number (in which case it will be treated
+ * as a pixel measurement).
+ * @type string
+ * @default <i>blank string - i.e. disabled</i>
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sScrollX": "100%",
+ * "bScrollCollapse": true
+ * } );
+ * } );
+ */
+ "sScrollX": "",
+
+
+ /**
+ * This property can be used to force a DataTable to use more width than it
+ * might otherwise do when x-scrolling is enabled. For example if you have a
+ * table which requires to be well spaced, this parameter is useful for
+ * "over-sizing" the table, and thus forcing scrolling. This property can by
+ * any CSS unit, or a number (in which case it will be treated as a pixel
+ * measurement).
+ * @type string
+ * @default <i>blank string - i.e. disabled</i>
+ * @dtopt Options
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sScrollX": "100%",
+ * "sScrollXInner": "110%"
+ * } );
+ * } );
+ */
+ "sScrollXInner": "",
+
+
+ /**
+ * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
+ * to the given height, and enable scrolling for any data which overflows the
+ * current viewport. This can be used as an alternative to paging to display
+ * a lot of data in a small area (although paging and scrolling can both be
+ * enabled at the same time). This property can be any CSS unit, or a number
+ * (in which case it will be treated as a pixel measurement).
+ * @type string
+ * @default <i>blank string - i.e. disabled</i>
+ * @dtopt Features
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "sScrollY": "200px",
+ * "bPaginate": false
+ * } );
+ * } );
+ */
+ "sScrollY": "",
+
+
+ /**
+ * Set the HTTP method that is used to make the Ajax call for server-side
+ * processing or Ajax sourced data.
+ * @type string
+ * @default GET
+ * @dtopt Options
+ * @dtopt Server-side
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bServerSide": true,
+ * "sAjaxSource": "scripts/post.php",
+ * "sServerMethod": "POST"
+ * } );
+ * } );
+ */
+ "sServerMethod": "GET"
+ };
+
+
+
+ /**
+ * Column options that can be given to DataTables at initialisation time.
+ * @namespace
+ */
+ DataTable.defaults.columns = {
+ /**
+ * Allows a column's sorting to take multiple columns into account when
+ * doing a sort. For example first name / last name columns make sense to
+ * do a multi-column sort over the two columns.
+ * @type array
+ * @default null <i>Takes the value of the column index automatically</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "aDataSort": [ 0, 1 ], "aTargets": [ 0 ] },
+ * { "aDataSort": [ 1, 0 ], "aTargets": [ 1 ] },
+ * { "aDataSort": [ 2, 3, 4 ], "aTargets": [ 2 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "aDataSort": [ 0, 1 ] },
+ * { "aDataSort": [ 1, 0 ] },
+ * { "aDataSort": [ 2, 3, 4 ] },
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "aDataSort": null,
+
+
+ /**
+ * You can control the default sorting direction, and even alter the behaviour
+ * of the sort handler (i.e. only allow ascending sorting etc) using this
+ * parameter.
+ * @type array
+ * @default [ 'asc', 'desc' ]
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "asSorting": [ "asc" ], "aTargets": [ 1 ] },
+ * { "asSorting": [ "desc", "asc", "asc" ], "aTargets": [ 2 ] },
+ * { "asSorting": [ "desc" ], "aTargets": [ 3 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * null,
+ * { "asSorting": [ "asc" ] },
+ * { "asSorting": [ "desc", "asc", "asc" ] },
+ * { "asSorting": [ "desc" ] },
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "asSorting": [ 'asc', 'desc' ],
+
+
+ /**
+ * Enable or disable filtering on the data in this column.
+ * @type boolean
+ * @default true
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "bSearchable": false, "aTargets": [ 0 ] }
+ * ] } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "bSearchable": false },
+ * null,
+ * null,
+ * null,
+ * null
+ * ] } );
+ * } );
+ */
+ "bSearchable": true,
+
+
+ /**
+ * Enable or disable sorting on this column.
+ * @type boolean
+ * @default true
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "bSortable": false, "aTargets": [ 0 ] }
+ * ] } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "bSortable": false },
+ * null,
+ * null,
+ * null,
+ * null
+ * ] } );
+ * } );
+ */
+ "bSortable": true,
+
+
+ /**
+ * <code>Deprecated</code> When using fnRender() for a column, you may wish
+ * to use the original data (before rendering) for sorting and filtering
+ * (the default is to used the rendered data that the user can see). This
+ * may be useful for dates etc.
+ *
+ * Please note that this option has now been deprecated and will be removed
+ * in the next version of DataTables. Please use mRender / mData rather than
+ * fnRender.
+ * @type boolean
+ * @default true
+ * @dtopt Columns
+ * @deprecated
+ */
+ "bUseRendered": true,
+
+
+ /**
+ * Enable or disable the display of this column.
+ * @type boolean
+ * @default true
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "bVisible": false, "aTargets": [ 0 ] }
+ * ] } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "bVisible": false },
+ * null,
+ * null,
+ * null,
+ * null
+ * ] } );
+ * } );
+ */
+ "bVisible": true,
+
+
+ /**
+ * Developer definable function that is called whenever a cell is created (Ajax source,
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
+ * allowing you to modify the DOM element (add background colour for example) when the
+ * element is available.
+ * @type function
+ * @param {element} nTd The TD node that has been created
+ * @param {*} sData The Data for the cell
+ * @param {array|object} oData The data for the whole row
+ * @param {int} iRow The row index for the aoData data store
+ * @param {int} iCol The column index for aoColumns
+ * @dtopt Columns
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [ {
+ * "aTargets": [3],
+ * "fnCreatedCell": function (nTd, sData, oData, iRow, iCol) {
+ * if ( sData == "1.7" ) {
+ * $(nTd).css('color', 'blue')
+ * }
+ * }
+ * } ]
+ * });
+ * } );
+ */
+ "fnCreatedCell": null,
+
+
+ /**
+ * <code>Deprecated</code> Custom display function that will be called for the
+ * display of each cell in this column.
+ *
+ * Please note that this option has now been deprecated and will be removed
+ * in the next version of DataTables. Please use mRender / mData rather than
+ * fnRender.
+ * @type function
+ * @param {object} o Object with the following parameters:
+ * @param {int} o.iDataRow The row in aoData
+ * @param {int} o.iDataColumn The column in question
+ * @param {array} o.aData The data for the row in question
+ * @param {object} o.oSettings The settings object for this DataTables instance
+ * @param {object} o.mDataProp The data property used for this column
+ * @param {*} val The current cell value
+ * @returns {string} The string you which to use in the display
+ * @dtopt Columns
+ * @deprecated
+ */
+ "fnRender": null,
+
+
+ /**
+ * The column index (starting from 0!) that you wish a sort to be performed
+ * upon when this column is selected for sorting. This can be used for sorting
+ * on hidden columns for example.
+ * @type int
+ * @default -1 <i>Use automatically calculated column index</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "iDataSort": 1, "aTargets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "iDataSort": 1 },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "iDataSort": -1,
+
+
+ /**
+ * This parameter has been replaced by mData in DataTables to ensure naming
+ * consistency. mDataProp can still be used, as there is backwards compatibility
+ * in DataTables for this option, but it is strongly recommended that you use
+ * mData in preference to mDataProp.
+ * @name DataTable.defaults.columns.mDataProp
+ */
+
+
+ /**
+ * This property can be used to read data from any JSON data source property,
+ * including deeply nested objects / properties. mData can be given in a
+ * number of different ways which effect its behaviour:
+ * <ul>
+ * <li>integer - treated as an array index for the data source. This is the
+ * default that DataTables uses (incrementally increased for each column).</li>
+ * <li>string - read an object property from the data source. Note that you can
+ * use Javascript dotted notation to read deep properties / arrays from the
+ * data source.</li>
+ * <li>null - the sDefaultContent option will be used for the cell (null
+ * by default, so you will need to specify the default content you want -
+ * typically an empty string). This can be useful on generated columns such
+ * as edit / delete action columns.</li>
+ * <li>function - the function given will be executed whenever DataTables
+ * needs to set or get the data for a cell in the column. The function
+ * takes three parameters:
+ * <ul>
+ * <li>{array|object} The data source for the row</li>
+ * <li>{string} The type call data requested - this will be 'set' when
+ * setting data or 'filter', 'display', 'type', 'sort' or undefined when
+ * gathering data. Note that when <i>undefined</i> is given for the type
+ * DataTables expects to get the raw data for the object back</li>
+ * <li>{*} Data to set when the second parameter is 'set'.</li>
+ * </ul>
+ * The return value from the function is not required when 'set' is the type
+ * of call, but otherwise the return is what will be used for the data
+ * requested.</li>
+ * </ul>
+ *
+ * Note that prior to DataTables 1.9.2 mData was called mDataProp. The name change
+ * reflects the flexibility of this property and is consistent with the naming of
+ * mRender. If 'mDataProp' is given, then it will still be used by DataTables, as
+ * it automatically maps the old name to the new if required.
+ * @type string|int|function|null
+ * @default null <i>Use automatically calculated column index</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Read table data from objects
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "sAjaxSource": "sources/deep.txt",
+ * "aoColumns": [
+ * { "mData": "engine" },
+ * { "mData": "browser" },
+ * { "mData": "platform.inner" },
+ * { "mData": "platform.details.0" },
+ * { "mData": "platform.details.1" }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using mData as a function to provide different information for
+ * // sorting, filtering and display. In this case, currency (price)
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "aoColumnDefs": [ {
+ * "aTargets": [ 0 ],
+ * "mData": function ( source, type, val ) {
+ * if (type === 'set') {
+ * source.price = val;
+ * // Store the computed dislay and filter values for efficiency
+ * source.price_display = val=="" ? "" : "$"+numberFormat(val);
+ * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
+ * return;
+ * }
+ * else if (type === 'display') {
+ * return source.price_display;
+ * }
+ * else if (type === 'filter') {
+ * return source.price_filter;
+ * }
+ * // 'sort', 'type' and undefined all just use the integer
+ * return source.price;
+ * }
+ * } ]
+ * } );
+ * } );
+ */
+ "mData": null,
+
+
+ /**
+ * This property is the rendering partner to mData and it is suggested that
+ * when you want to manipulate data for display (including filtering, sorting etc)
+ * but not altering the underlying data for the table, use this property. mData
+ * can actually do everything this property can and more, but this parameter is
+ * easier to use since there is no 'set' option. Like mData is can be given
+ * in a number of different ways to effect its behaviour, with the addition of
+ * supporting array syntax for easy outputting of arrays (including arrays of
+ * objects):
+ * <ul>
+ * <li>integer - treated as an array index for the data source. This is the
+ * default that DataTables uses (incrementally increased for each column).</li>
+ * <li>string - read an object property from the data source. Note that you can
+ * use Javascript dotted notation to read deep properties / arrays from the
+ * data source and also array brackets to indicate that the data reader should
+ * loop over the data source array. When characters are given between the array
+ * brackets, these characters are used to join the data source array together.
+ * For example: "accounts[, ].name" would result in a comma separated list with
+ * the 'name' value from the 'accounts' array of objects.</li>
+ * <li>function - the function given will be executed whenever DataTables
+ * needs to set or get the data for a cell in the column. The function
+ * takes three parameters:
+ * <ul>
+ * <li>{array|object} The data source for the row (based on mData)</li>
+ * <li>{string} The type call data requested - this will be 'filter', 'display',
+ * 'type' or 'sort'.</li>
+ * <li>{array|object} The full data source for the row (not based on mData)</li>
+ * </ul>
+ * The return value from the function is what will be used for the data
+ * requested.</li>
+ * </ul>
+ * @type string|int|function|null
+ * @default null <i>Use mData</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Create a comma separated list from an array of objects
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "sAjaxSource": "sources/deep.txt",
+ * "aoColumns": [
+ * { "mData": "engine" },
+ * { "mData": "browser" },
+ * {
+ * "mData": "platform",
+ * "mRender": "[, ].name"
+ * }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Use as a function to create a link from the data source
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * {
+ * "aTargets": [ 0 ],
+ * "mData": "download_link",
+ * "mRender": function ( data, type, full ) {
+ * return '<a href="'+data+'">Download</a>';
+ * }
+ * ]
+ * } );
+ * } );
+ */
+ "mRender": null,
+
+
+ /**
+ * Change the cell type created for the column - either TD cells or TH cells. This
+ * can be useful as TH cells have semantic meaning in the table body, allowing them
+ * to act as a header for a row (you may wish to add scope='row' to the TH elements).
+ * @type string
+ * @default td
+ * @dtopt Columns
+ *
+ * @example
+ * // Make the first column use TH cells
+ * $(document).ready( function() {
+ * var oTable = $('#example').dataTable( {
+ * "aoColumnDefs": [ {
+ * "aTargets": [ 0 ],
+ * "sCellType": "th"
+ * } ]
+ * } );
+ * } );
+ */
+ "sCellType": "td",
+
+
+ /**
+ * Class to give to each cell in this column.
+ * @type string
+ * @default <i>Empty string</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "sClass": "my_class", "aTargets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "sClass": "my_class" },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "sClass": "",
+
+ /**
+ * When DataTables calculates the column widths to assign to each column,
+ * it finds the longest string in each column and then constructs a
+ * temporary table and reads the widths from that. The problem with this
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
+ * string - thus the calculation can go wrong (doing it properly and putting
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
+ * a "work around" we provide this option. It will append its value to the
+ * text that is found to be the longest string for the column - i.e. padding.
+ * Generally you shouldn't need this, and it is not documented on the
+ * general DataTables.net documentation
+ * @type string
+ * @default <i>Empty string<i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * null,
+ * null,
+ * null,
+ * {
+ * "sContentPadding": "mmm"
+ * }
+ * ]
+ * } );
+ * } );
+ */
+ "sContentPadding": "",
+
+
+ /**
+ * Allows a default value to be given for a column's data, and will be used
+ * whenever a null data source is encountered (this can be because mData
+ * is set to null, or because the data source itself is null).
+ * @type string
+ * @default null
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * {
+ * "mData": null,
+ * "sDefaultContent": "Edit",
+ * "aTargets": [ -1 ]
+ * }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * null,
+ * null,
+ * null,
+ * {
+ * "mData": null,
+ * "sDefaultContent": "Edit"
+ * }
+ * ]
+ * } );
+ * } );
+ */
+ "sDefaultContent": null,
+
+
+ /**
+ * This parameter is only used in DataTables' server-side processing. It can
+ * be exceptionally useful to know what columns are being displayed on the
+ * client side, and to map these to database fields. When defined, the names
+ * also allow DataTables to reorder information from the server if it comes
+ * back in an unexpected order (i.e. if you switch your columns around on the
+ * client-side, your server-side code does not also need updating).
+ * @type string
+ * @default <i>Empty string</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "sName": "engine", "aTargets": [ 0 ] },
+ * { "sName": "browser", "aTargets": [ 1 ] },
+ * { "sName": "platform", "aTargets": [ 2 ] },
+ * { "sName": "version", "aTargets": [ 3 ] },
+ * { "sName": "grade", "aTargets": [ 4 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "sName": "engine" },
+ * { "sName": "browser" },
+ * { "sName": "platform" },
+ * { "sName": "version" },
+ * { "sName": "grade" }
+ * ]
+ * } );
+ * } );
+ */
+ "sName": "",
+
+
+ /**
+ * Defines a data source type for the sorting which can be used to read
+ * real-time information from the table (updating the internally cached
+ * version) prior to sorting. This allows sorting to occur on user editable
+ * elements such as form inputs.
+ * @type string
+ * @default std
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "sSortDataType": "dom-text", "aTargets": [ 2, 3 ] },
+ * { "sType": "numeric", "aTargets": [ 3 ] },
+ * { "sSortDataType": "dom-select", "aTargets": [ 4 ] },
+ * { "sSortDataType": "dom-checkbox", "aTargets": [ 5 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * null,
+ * null,
+ * { "sSortDataType": "dom-text" },
+ * { "sSortDataType": "dom-text", "sType": "numeric" },
+ * { "sSortDataType": "dom-select" },
+ * { "sSortDataType": "dom-checkbox" }
+ * ]
+ * } );
+ * } );
+ */
+ "sSortDataType": "std",
+
+
+ /**
+ * The title of this column.
+ * @type string
+ * @default null <i>Derived from the 'TH' value for this column in the
+ * original HTML table.</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "sTitle": "My column title", "aTargets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "sTitle": "My column title" },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "sTitle": null,
+
+
+ /**
+ * The type allows you to specify how the data for this column will be sorted.
+ * Four types (string, numeric, date and html (which will strip HTML tags
+ * before sorting)) are currently available. Note that only date formats
+ * understood by Javascript's Date() object will be accepted as type date. For
+ * example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 'numeric',
+ * 'date' or 'html' (by default). Further types can be adding through
+ * plug-ins.
+ * @type string
+ * @default null <i>Auto-detected from raw data</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "sType": "html", "aTargets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "sType": "html" },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "sType": null,
+
+
+ /**
+ * Defining the width of the column, this parameter may take any CSS value
+ * (3em, 20px etc). DataTables apples 'smart' widths to columns which have not
+ * been given a specific width through this interface ensuring that the table
+ * remains readable.
+ * @type string
+ * @default null <i>Automatic</i>
+ * @dtopt Columns
+ *
+ * @example
+ * // Using aoColumnDefs
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumnDefs": [
+ * { "sWidth": "20%", "aTargets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using aoColumns
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "aoColumns": [
+ * { "sWidth": "20%" },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "sWidth": null
+ };
+
+
+
+ /**
+ * DataTables settings object - this holds all the information needed for a
+ * given table, including configuration, data and current application of the
+ * table options. DataTables does not have a single instance for each DataTable
+ * with the settings attached to that instance, but rather instances of the
+ * DataTable "class" are created on-the-fly as needed (typically by a
+ * $().dataTable() call) and the settings object is then applied to that
+ * instance.
+ *
+ * Note that this object is related to {@link DataTable.defaults} but this
+ * one is the internal data store for DataTables's cache of columns. It should
+ * NOT be manipulated outside of DataTables. Any configuration should be done
+ * through the initialisation options.
+ * @namespace
+ * @todo Really should attach the settings object to individual instances so we
+ * don't need to create new instances on each $().dataTable() call (if the
+ * table already exists). It would also save passing oSettings around and
+ * into every single function. However, this is a very significant
+ * architecture change for DataTables and will almost certainly break
+ * backwards compatibility with older installations. This is something that
+ * will be done in 2.0.
+ */
+ DataTable.models.oSettings = {
+ /**
+ * Primary features of DataTables and their enablement state.
+ * @namespace
+ */
+ "oFeatures": {
+
+ /**
+ * Flag to say if DataTables should automatically try to calculate the
+ * optimum table and columns widths (true) or not (false).
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bAutoWidth": null,
+
+ /**
+ * Delay the creation of TR and TD elements until they are actually
+ * needed by a driven page draw. This can give a significant speed
+ * increase for Ajax source and Javascript source data, but makes no
+ * difference at all fro DOM and server-side processing tables.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bDeferRender": null,
+
+ /**
+ * Enable filtering on the table or not. Note that if this is disabled
+ * then there is no filtering at all on the table, including fnFilter.
+ * To just remove the filtering input use sDom and remove the 'f' option.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bFilter": null,
+
+ /**
+ * Table information element (the 'Showing x of y records' div) enable
+ * flag.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bInfo": null,
+
+ /**
+ * Present a user control allowing the end user to change the page size
+ * when pagination is enabled.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bLengthChange": null,
+
+ /**
+ * Pagination enabled or not. Note that if this is disabled then length
+ * changing must also be disabled.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bPaginate": null,
+
+ /**
+ * Processing indicator enable flag whenever DataTables is enacting a
+ * user request - typically an Ajax request for server-side processing.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bProcessing": null,
+
+ /**
+ * Server-side processing enabled flag - when enabled DataTables will
+ * get all data from the server for every draw - there is no filtering,
+ * sorting or paging done on the client-side.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bServerSide": null,
+
+ /**
+ * Sorting enablement flag.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bSort": null,
+
+ /**
+ * Apply a class to the columns which are being sorted to provide a
+ * visual highlight or not. This can slow things down when enabled since
+ * there is a lot of DOM interaction.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bSortClasses": null,
+
+ /**
+ * State saving enablement flag.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bStateSave": null
+ },
+
+
+ /**
+ * Scrolling settings for a table.
+ * @namespace
+ */
+ "oScroll": {
+ /**
+ * Indicate if DataTables should be allowed to set the padding / margin
+ * etc for the scrolling header elements or not. Typically you will want
+ * this.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bAutoCss": null,
+
+ /**
+ * When the table is shorter in height than sScrollY, collapse the
+ * table container down to the height of the table (when true).
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bCollapse": null,
+
+ /**
+ * Infinite scrolling enablement flag. Now deprecated in favour of
+ * using the Scroller plug-in.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bInfinite": null,
+
+ /**
+ * Width of the scrollbar for the web-browser's platform. Calculated
+ * during table initialisation.
+ * @type int
+ * @default 0
+ */
+ "iBarWidth": 0,
+
+ /**
+ * Space (in pixels) between the bottom of the scrolling container and
+ * the bottom of the scrolling viewport before the next page is loaded
+ * when using infinite scrolling.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type int
+ */
+ "iLoadGap": null,
+
+ /**
+ * Viewport width for horizontal scrolling. Horizontal scrolling is
+ * disabled if an empty string.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ */
+ "sX": null,
+
+ /**
+ * Width to expand the table to when using x-scrolling. Typically you
+ * should not need to use this.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @deprecated
+ */
+ "sXInner": null,
+
+ /**
+ * Viewport height for vertical scrolling. Vertical scrolling is disabled
+ * if an empty string.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ */
+ "sY": null
+ },
+
+ /**
+ * Language information for the table.
+ * @namespace
+ * @extends DataTable.defaults.oLanguage
+ */
+ "oLanguage": {
+ /**
+ * Information callback function. See
+ * {@link DataTable.defaults.fnInfoCallback}
+ * @type function
+ * @default null
+ */
+ "fnInfoCallback": null
+ },
+
+ /**
+ * Browser support parameters
+ * @namespace
+ */
+ "oBrowser": {
+ /**
+ * Indicate if the browser incorrectly calculates width:100% inside a
+ * scrolling element (IE6/7)
+ * @type boolean
+ * @default false
+ */
+ "bScrollOversize": false
+ },
+
+ /**
+ * Array referencing the nodes which are used for the features. The
+ * parameters of this object match what is allowed by sDom - i.e.
+ * <ul>
+ * <li>'l' - Length changing</li>
+ * <li>'f' - Filtering input</li>
+ * <li>'t' - The table!</li>
+ * <li>'i' - Information</li>
+ * <li>'p' - Pagination</li>
+ * <li>'r' - pRocessing</li>
+ * </ul>
+ * @type array
+ * @default []
+ */
+ "aanFeatures": [],
+
+ /**
+ * Store data information - see {@link DataTable.models.oRow} for detailed
+ * information.
+ * @type array
+ * @default []
+ */
+ "aoData": [],
+
+ /**
+ * Array of indexes which are in the current display (after filtering etc)
+ * @type array
+ * @default []
+ */
+ "aiDisplay": [],
+
+ /**
+ * Array of indexes for display - no filtering
+ * @type array
+ * @default []
+ */
+ "aiDisplayMaster": [],
+
+ /**
+ * Store information about each column that is in use
+ * @type array
+ * @default []
+ */
+ "aoColumns": [],
+
+ /**
+ * Store information about the table's header
+ * @type array
+ * @default []
+ */
+ "aoHeader": [],
+
+ /**
+ * Store information about the table's footer
+ * @type array
+ * @default []
+ */
+ "aoFooter": [],
+
+ /**
+ * Search data array for regular expression searching
+ * @type array
+ * @default []
+ */
+ "asDataSearch": [],
+
+ /**
+ * Store the applied global search information in case we want to force a
+ * research or compare the old search to a new one.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @namespace
+ * @extends DataTable.models.oSearch
+ */
+ "oPreviousSearch": {},
+
+ /**
+ * Store the applied search for each column - see
+ * {@link DataTable.models.oSearch} for the format that is used for the
+ * filtering information for each column.
+ * @type array
+ * @default []
+ */
+ "aoPreSearchCols": [],
+
+ /**
+ * Sorting that is applied to the table. Note that the inner arrays are
+ * used in the following manner:
+ * <ul>
+ * <li>Index 0 - column number</li>
+ * <li>Index 1 - current sorting direction</li>
+ * <li>Index 2 - index of asSorting for this column</li>
+ * </ul>
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type array
+ * @todo These inner arrays should really be objects
+ */
+ "aaSorting": null,
+
+ /**
+ * Sorting that is always applied to the table (i.e. prefixed in front of
+ * aaSorting).
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type array|null
+ * @default null
+ */
+ "aaSortingFixed": null,
+
+ /**
+ * Classes to use for the striping of a table.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type array
+ * @default []
+ */
+ "asStripeClasses": null,
+
+ /**
+ * If restoring a table - we should restore its striping classes as well
+ * @type array
+ * @default []
+ */
+ "asDestroyStripes": [],
+
+ /**
+ * If restoring a table - we should restore its width
+ * @type int
+ * @default 0
+ */
+ "sDestroyWidth": 0,
+
+ /**
+ * Callback functions array for every time a row is inserted (i.e. on a draw).
+ * @type array
+ * @default []
+ */
+ "aoRowCallback": [],
+
+ /**
+ * Callback functions for the header on each draw.
+ * @type array
+ * @default []
+ */
+ "aoHeaderCallback": [],
+
+ /**
+ * Callback function for the footer on each draw.
+ * @type array
+ * @default []
+ */
+ "aoFooterCallback": [],
+
+ /**
+ * Array of callback functions for draw callback functions
+ * @type array
+ * @default []
+ */
+ "aoDrawCallback": [],
+
+ /**
+ * Array of callback functions for row created function
+ * @type array
+ * @default []
+ */
+ "aoRowCreatedCallback": [],
+
+ /**
+ * Callback functions for just before the table is redrawn. A return of
+ * false will be used to cancel the draw.
+ * @type array
+ * @default []
+ */
+ "aoPreDrawCallback": [],
+
+ /**
+ * Callback functions for when the table has been initialised.
+ * @type array
+ * @default []
+ */
+ "aoInitComplete": [],
+
+
+ /**
+ * Callbacks for modifying the settings to be stored for state saving, prior to
+ * saving state.
+ * @type array
+ * @default []
+ */
+ "aoStateSaveParams": [],
+
+ /**
+ * Callbacks for modifying the settings that have been stored for state saving
+ * prior to using the stored values to restore the state.
+ * @type array
+ * @default []
+ */
+ "aoStateLoadParams": [],
+
+ /**
+ * Callbacks for operating on the settings object once the saved state has been
+ * loaded
+ * @type array
+ * @default []
+ */
+ "aoStateLoaded": [],
+
+ /**
+ * Cache the table ID for quick access
+ * @type string
+ * @default <i>Empty string</i>
+ */
+ "sTableId": "",
+
+ /**
+ * The TABLE node for the main table
+ * @type node
+ * @default null
+ */
+ "nTable": null,
+
+ /**
+ * Permanent ref to the thead element
+ * @type node
+ * @default null
+ */
+ "nTHead": null,
+
+ /**
+ * Permanent ref to the tfoot element - if it exists
+ * @type node
+ * @default null
+ */
+ "nTFoot": null,
+
+ /**
+ * Permanent ref to the tbody element
+ * @type node
+ * @default null
+ */
+ "nTBody": null,
+
+ /**
+ * Cache the wrapper node (contains all DataTables controlled elements)
+ * @type node
+ * @default null
+ */
+ "nTableWrapper": null,
+
+ /**
+ * Indicate if when using server-side processing the loading of data
+ * should be deferred until the second draw.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ * @default false
+ */
+ "bDeferLoading": false,
+
+ /**
+ * Indicate if all required information has been read in
+ * @type boolean
+ * @default false
+ */
+ "bInitialised": false,
+
+ /**
+ * Information about open rows. Each object in the array has the parameters
+ * 'nTr' and 'nParent'
+ * @type array
+ * @default []
+ */
+ "aoOpenRows": [],
+
+ /**
+ * Dictate the positioning of DataTables' control elements - see
+ * {@link DataTable.model.oInit.sDom}.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @default null
+ */
+ "sDom": null,
+
+ /**
+ * Which type of pagination should be used.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @default two_button
+ */
+ "sPaginationType": "two_button",
+
+ /**
+ * The cookie duration (for bStateSave) in seconds.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type int
+ * @default 0
+ */
+ "iCookieDuration": 0,
+
+ /**
+ * The cookie name prefix.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @default <i>Empty string</i>
+ */
+ "sCookiePrefix": "",
+
+ /**
+ * Callback function for cookie creation.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type function
+ * @default null
+ */
+ "fnCookieCallback": null,
+
+ /**
+ * Array of callback functions for state saving. Each array element is an
+ * object with the following parameters:
+ * <ul>
+ * <li>function:fn - function to call. Takes two parameters, oSettings
+ * and the JSON string to save that has been thus far created. Returns
+ * a JSON string to be inserted into a json object
+ * (i.e. '"param": [ 0, 1, 2]')</li>
+ * <li>string:sName - name of callback</li>
+ * </ul>
+ * @type array
+ * @default []
+ */
+ "aoStateSave": [],
+
+ /**
+ * Array of callback functions for state loading. Each array element is an
+ * object with the following parameters:
+ * <ul>
+ * <li>function:fn - function to call. Takes two parameters, oSettings
+ * and the object stored. May return false to cancel state loading</li>
+ * <li>string:sName - name of callback</li>
+ * </ul>
+ * @type array
+ * @default []
+ */
+ "aoStateLoad": [],
+
+ /**
+ * State that was loaded from the cookie. Useful for back reference
+ * @type object
+ * @default null
+ */
+ "oLoadedState": null,
+
+ /**
+ * Source url for AJAX data for the table.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @default null
+ */
+ "sAjaxSource": null,
+
+ /**
+ * Property from a given object from which to read the table data from. This
+ * can be an empty string (when not server-side processing), in which case
+ * it is assumed an an array is given directly.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ */
+ "sAjaxDataProp": null,
+
+ /**
+ * Note if draw should be blocked while getting data
+ * @type boolean
+ * @default true
+ */
+ "bAjaxDataGet": true,
+
+ /**
+ * The last jQuery XHR object that was used for server-side data gathering.
+ * This can be used for working with the XHR information in one of the
+ * callbacks
+ * @type object
+ * @default null
+ */
+ "jqXHR": null,
+
+ /**
+ * Function to get the server-side data.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type function
+ */
+ "fnServerData": null,
+
+ /**
+ * Functions which are called prior to sending an Ajax request so extra
+ * parameters can easily be sent to the server
+ * @type array
+ * @default []
+ */
+ "aoServerParams": [],
+
+ /**
+ * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
+ * required).
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ */
+ "sServerMethod": null,
+
+ /**
+ * Format numbers for display.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type function
+ */
+ "fnFormatNumber": null,
+
+ /**
+ * List of options that can be used for the user selectable length menu.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type array
+ * @default []
+ */
+ "aLengthMenu": null,
+
+ /**
+ * Counter for the draws that the table does. Also used as a tracker for
+ * server-side processing
+ * @type int
+ * @default 0
+ */
+ "iDraw": 0,
+
+ /**
+ * Indicate if a redraw is being done - useful for Ajax
+ * @type boolean
+ * @default false
+ */
+ "bDrawing": false,
+
+ /**
+ * Draw index (iDraw) of the last error when parsing the returned data
+ * @type int
+ * @default -1
+ */
+ "iDrawError": -1,
+
+ /**
+ * Paging display length
+ * @type int
+ * @default 10
+ */
+ "_iDisplayLength": 10,
+
+ /**
+ * Paging start point - aiDisplay index
+ * @type int
+ * @default 0
+ */
+ "_iDisplayStart": 0,
+
+ /**
+ * Paging end point - aiDisplay index. Use fnDisplayEnd rather than
+ * this property to get the end point
+ * @type int
+ * @default 10
+ * @private
+ */
+ "_iDisplayEnd": 10,
+
+ /**
+ * Server-side processing - number of records in the result set
+ * (i.e. before filtering), Use fnRecordsTotal rather than
+ * this property to get the value of the number of records, regardless of
+ * the server-side processing setting.
+ * @type int
+ * @default 0
+ * @private
+ */
+ "_iRecordsTotal": 0,
+
+ /**
+ * Server-side processing - number of records in the current display set
+ * (i.e. after filtering). Use fnRecordsDisplay rather than
+ * this property to get the value of the number of records, regardless of
+ * the server-side processing setting.
+ * @type boolean
+ * @default 0
+ * @private
+ */
+ "_iRecordsDisplay": 0,
+
+ /**
+ * Flag to indicate if jQuery UI marking and classes should be used.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bJUI": null,
+
+ /**
+ * The classes to use for the table
+ * @type object
+ * @default {}
+ */
+ "oClasses": {},
+
+ /**
+ * Flag attached to the settings object so you can check in the draw
+ * callback if filtering has been done in the draw. Deprecated in favour of
+ * events.
+ * @type boolean
+ * @default false
+ * @deprecated
+ */
+ "bFiltered": false,
+
+ /**
+ * Flag attached to the settings object so you can check in the draw
+ * callback if sorting has been done in the draw. Deprecated in favour of
+ * events.
+ * @type boolean
+ * @default false
+ * @deprecated
+ */
+ "bSorted": false,
+
+ /**
+ * Indicate that if multiple rows are in the header and there is more than
+ * one unique cell per column, if the top one (true) or bottom one (false)
+ * should be used for sorting / title by DataTables.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bSortCellsTop": null,
+
+ /**
+ * Initialisation object that is used for the table
+ * @type object
+ * @default null
+ */
+ "oInit": null,
+
+ /**
+ * Destroy callback functions - for plug-ins to attach themselves to the
+ * destroy so they can clean up markup and events.
+ * @type array
+ * @default []
+ */
+ "aoDestroyCallback": [],
+
+
+ /**
+ * Get the number of records in the current record set, before filtering
+ * @type function
+ */
+ "fnRecordsTotal": function ()
+ {
+ if ( this.oFeatures.bServerSide ) {
+ return parseInt(this._iRecordsTotal, 10);
+ } else {
+ return this.aiDisplayMaster.length;
+ }
+ },
+
+ /**
+ * Get the number of records in the current record set, after filtering
+ * @type function
+ */
+ "fnRecordsDisplay": function ()
+ {
+ if ( this.oFeatures.bServerSide ) {
+ return parseInt(this._iRecordsDisplay, 10);
+ } else {
+ return this.aiDisplay.length;
+ }
+ },
+
+ /**
+ * Set the display end point - aiDisplay index
+ * @type function
+ * @todo Should do away with _iDisplayEnd and calculate it on-the-fly here
+ */
+ "fnDisplayEnd": function ()
+ {
+ if ( this.oFeatures.bServerSide ) {
+ if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {
+ return this._iDisplayStart+this.aiDisplay.length;
+ } else {
+ return Math.min( this._iDisplayStart+this._iDisplayLength,
+ this._iRecordsDisplay );
+ }
+ } else {
+ return this._iDisplayEnd;
+ }
+ },
+
+ /**
+ * The DataTables object for this table
+ * @type object
+ * @default null
+ */
+ "oInstance": null,
+
+ /**
+ * Unique identifier for each instance of the DataTables object. If there
+ * is an ID on the table node, then it takes that value, otherwise an
+ * incrementing internal counter is used.
+ * @type string
+ * @default null
+ */
+ "sInstance": null,
+
+ /**
+ * tabindex attribute value that is added to DataTables control elements, allowing
+ * keyboard navigation of the table and its controls.
+ */
+ "iTabIndex": 0,
+
+ /**
+ * DIV container for the footer scrolling table if scrolling
+ */
+ "nScrollHead": null,
+
+ /**
+ * DIV container for the footer scrolling table if scrolling
+ */
+ "nScrollFoot": null
+ };
+
+ /**
+ * Extension object for DataTables that is used to provide all extension options.
+ *
+ * Note that the <i>DataTable.ext</i> object is available through
+ * <i>jQuery.fn.dataTable.ext</i> where it may be accessed and manipulated. It is
+ * also aliased to <i>jQuery.fn.dataTableExt</i> for historic reasons.
+ * @namespace
+ * @extends DataTable.models.ext
+ */
+ DataTable.ext = $.extend( true, {}, DataTable.models.ext );
+
+ $.extend( DataTable.ext.oStdClasses, {
+ "sTable": "dataTable",
+
+ /* Two buttons buttons */
+ "sPagePrevEnabled": "paginate_enabled_previous",
+ "sPagePrevDisabled": "paginate_disabled_previous",
+ "sPageNextEnabled": "paginate_enabled_next",
+ "sPageNextDisabled": "paginate_disabled_next",
+ "sPageJUINext": "",
+ "sPageJUIPrev": "",
+
+ /* Full numbers paging buttons */
+ "sPageButton": "paginate_button",
+ "sPageButtonActive": "paginate_active",
+ "sPageButtonStaticDisabled": "paginate_button paginate_button_disabled",
+ "sPageFirst": "first",
+ "sPagePrevious": "previous",
+ "sPageNext": "next",
+ "sPageLast": "last",
+
+ /* Striping classes */
+ "sStripeOdd": "odd",
+ "sStripeEven": "even",
+
+ /* Empty row */
+ "sRowEmpty": "dataTables_empty",
+
+ /* Features */
+ "sWrapper": "dataTables_wrapper",
+ "sFilter": "dataTables_filter",
+ "sInfo": "dataTables_info",
+ "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
+ "sLength": "dataTables_length",
+ "sProcessing": "dataTables_processing",
+
+ /* Sorting */
+ "sSortAsc": "sorting_asc",
+ "sSortDesc": "sorting_desc",
+ "sSortable": "sorting", /* Sortable in both directions */
+ "sSortableAsc": "sorting_asc_disabled",
+ "sSortableDesc": "sorting_desc_disabled",
+ "sSortableNone": "sorting_disabled",
+ "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
+ "sSortJUIAsc": "",
+ "sSortJUIDesc": "",
+ "sSortJUI": "",
+ "sSortJUIAscAllowed": "",
+ "sSortJUIDescAllowed": "",
+ "sSortJUIWrapper": "",
+ "sSortIcon": "",
+
+ /* Scrolling */
+ "sScrollWrapper": "dataTables_scroll",
+ "sScrollHead": "dataTables_scrollHead",
+ "sScrollHeadInner": "dataTables_scrollHeadInner",
+ "sScrollBody": "dataTables_scrollBody",
+ "sScrollFoot": "dataTables_scrollFoot",
+ "sScrollFootInner": "dataTables_scrollFootInner",
+
+ /* Misc */
+ "sFooterTH": "",
+ "sJUIHeader": "",
+ "sJUIFooter": ""
+ } );
+
+
+ $.extend( DataTable.ext.oJUIClasses, DataTable.ext.oStdClasses, {
+ /* Two buttons buttons */
+ "sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left",
+ "sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
+ "sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right",
+ "sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",
+ "sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
+ "sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
+
+ /* Full numbers paging buttons */
+ "sPageButton": "fg-button ui-button ui-state-default",
+ "sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled",
+ "sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled",
+ "sPageFirst": "first ui-corner-tl ui-corner-bl",
+ "sPageLast": "last ui-corner-tr ui-corner-br",
+
+ /* Features */
+ "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
+ "ui-buttonset-multi paging_", /* Note that the type is postfixed */
+
+ /* Sorting */
+ "sSortAsc": "ui-state-default",
+ "sSortDesc": "ui-state-default",
+ "sSortable": "ui-state-default",
+ "sSortableAsc": "ui-state-default",
+ "sSortableDesc": "ui-state-default",
+ "sSortableNone": "ui-state-default",
+ "sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
+ "sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
+ "sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s",
+ "sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n",
+ "sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s",
+ "sSortJUIWrapper": "DataTables_sort_wrapper",
+ "sSortIcon": "DataTables_sort_icon",
+
+ /* Scrolling */
+ "sScrollHead": "dataTables_scrollHead ui-state-default",
+ "sScrollFoot": "dataTables_scrollFoot ui-state-default",
+
+ /* Misc */
+ "sFooterTH": "ui-state-default",
+ "sJUIHeader": "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix",
+ "sJUIFooter": "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix"
+ } );
+
+ /*
+ * Variable: oPagination
+ * Purpose:
+ * Scope: jQuery.fn.dataTableExt
+ */
+ $.extend( DataTable.ext.oPagination, {
+ /*
+ * Variable: two_button
+ * Purpose: Standard two button (forward/back) pagination
+ * Scope: jQuery.fn.dataTableExt.oPagination
+ */
+ "two_button": {
+ /*
+ * Function: oPagination.two_button.fnInit
+ * Purpose: Initialise dom elements required for pagination with forward/back buttons only
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * node:nPaging - the DIV which contains this pagination control
+ * function:fnCallbackDraw - draw function which must be called on update
+ */
+ "fnInit": function ( oSettings, nPaging, fnCallbackDraw )
+ {
+ var oLang = oSettings.oLanguage.oPaginate;
+ var oClasses = oSettings.oClasses;
+ var fnClickHandler = function ( e ) {
+ if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
+ {
+ fnCallbackDraw( oSettings );
+ }
+ };
+
+ var sAppend = (!oSettings.bJUI) ?
+ '<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sPrevious+'</a>'+
+ '<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sNext+'</a>'
+ :
+ '<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUIPrev+'"></span></a>'+
+ '<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUINext+'"></span></a>';
+ $(nPaging).append( sAppend );
+
+ var els = $('a', nPaging);
+ var nPrevious = els[0],
+ nNext = els[1];
+
+ oSettings.oApi._fnBindAction( nPrevious, {action: "previous"}, fnClickHandler );
+ oSettings.oApi._fnBindAction( nNext, {action: "next"}, fnClickHandler );
+
+ /* ID the first elements only */
+ if ( !oSettings.aanFeatures.p )
+ {
+ nPaging.id = oSettings.sTableId+'_paginate';
+ nPrevious.id = oSettings.sTableId+'_previous';
+ nNext.id = oSettings.sTableId+'_next';
+
+ nPrevious.setAttribute('aria-controls', oSettings.sTableId);
+ nNext.setAttribute('aria-controls', oSettings.sTableId);
+ }
+ },
+
+ /*
+ * Function: oPagination.two_button.fnUpdate
+ * Purpose: Update the two button pagination at the end of the draw
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * function:fnCallbackDraw - draw function to call on page change
+ */
+ "fnUpdate": function ( oSettings, fnCallbackDraw )
+ {
+ if ( !oSettings.aanFeatures.p )
+ {
+ return;
+ }
+
+ var oClasses = oSettings.oClasses;
+ var an = oSettings.aanFeatures.p;
+ var nNode;
+
+ /* Loop over each instance of the pager */
+ for ( var i=0, iLen=an.length ; i<iLen ; i++ )
+ {
+ nNode = an[i].firstChild;
+ if ( nNode )
+ {
+ /* Previous page */
+ nNode.className = ( oSettings._iDisplayStart === 0 ) ?
+ oClasses.sPagePrevDisabled : oClasses.sPagePrevEnabled;
+
+ /* Next page */
+ nNode = nNode.nextSibling;
+ nNode.className = ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ?
+ oClasses.sPageNextDisabled : oClasses.sPageNextEnabled;
+ }
+ }
+ }
+ },
+
+
+ /*
+ * Variable: iFullNumbersShowPages
+ * Purpose: Change the number of pages which can be seen
+ * Scope: jQuery.fn.dataTableExt.oPagination
+ */
+ "iFullNumbersShowPages": 5,
+
+ /*
+ * Variable: full_numbers
+ * Purpose: Full numbers pagination
+ * Scope: jQuery.fn.dataTableExt.oPagination
+ */
+ "full_numbers": {
+ /*
+ * Function: oPagination.full_numbers.fnInit
+ * Purpose: Initialise dom elements required for pagination with a list of the pages
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * node:nPaging - the DIV which contains this pagination control
+ * function:fnCallbackDraw - draw function which must be called on update
+ */
+ "fnInit": function ( oSettings, nPaging, fnCallbackDraw )
+ {
+ var oLang = oSettings.oLanguage.oPaginate;
+ var oClasses = oSettings.oClasses;
+ var fnClickHandler = function ( e ) {
+ if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
+ {
+ fnCallbackDraw( oSettings );
+ }
+ };
+
+ $(nPaging).append(
+ '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageFirst+'">'+oLang.sFirst+'</a>'+
+ '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPagePrevious+'">'+oLang.sPrevious+'</a>'+
+ '<span></span>'+
+ '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageNext+'">'+oLang.sNext+'</a>'+
+ '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageLast+'">'+oLang.sLast+'</a>'
+ );
+ var els = $('a', nPaging);
+ var nFirst = els[0],
+ nPrev = els[1],
+ nNext = els[2],
+ nLast = els[3];
+
+ oSettings.oApi._fnBindAction( nFirst, {action: "first"}, fnClickHandler );
+ oSettings.oApi._fnBindAction( nPrev, {action: "previous"}, fnClickHandler );
+ oSettings.oApi._fnBindAction( nNext, {action: "next"}, fnClickHandler );
+ oSettings.oApi._fnBindAction( nLast, {action: "last"}, fnClickHandler );
+
+ /* ID the first elements only */
+ if ( !oSettings.aanFeatures.p )
+ {
+ nPaging.id = oSettings.sTableId+'_paginate';
+ nFirst.id =oSettings.sTableId+'_first';
+ nPrev.id =oSettings.sTableId+'_previous';
+ nNext.id =oSettings.sTableId+'_next';
+ nLast.id =oSettings.sTableId+'_last';
+ }
+ },
+
+ /*
+ * Function: oPagination.full_numbers.fnUpdate
+ * Purpose: Update the list of page buttons shows
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * function:fnCallbackDraw - draw function to call on page change
+ */
+ "fnUpdate": function ( oSettings, fnCallbackDraw )
+ {
+ if ( !oSettings.aanFeatures.p )
+ {
+ return;
+ }
+
+ var iPageCount = DataTable.ext.oPagination.iFullNumbersShowPages;
+ var iPageCountHalf = Math.floor(iPageCount / 2);
+ var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
+ var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;
+ var sList = "";
+ var iStartButton, iEndButton, i, iLen;
+ var oClasses = oSettings.oClasses;
+ var anButtons, anStatic, nPaginateList, nNode;
+ var an = oSettings.aanFeatures.p;
+ var fnBind = function (j) {
+ oSettings.oApi._fnBindAction( this, {"page": j+iStartButton-1}, function(e) {
+ /* Use the information in the element to jump to the required page */
+ oSettings.oApi._fnPageChange( oSettings, e.data.page );
+ fnCallbackDraw( oSettings );
+ e.preventDefault();
+ } );
+ };
+
+ /* Pages calculation */
+ if ( oSettings._iDisplayLength === -1 )
+ {
+ iStartButton = 1;
+ iEndButton = 1;
+ iCurrentPage = 1;
+ }
+ else if (iPages < iPageCount)
+ {
+ iStartButton = 1;
+ iEndButton = iPages;
+ }
+ else if (iCurrentPage <= iPageCountHalf)
+ {
+ iStartButton = 1;
+ iEndButton = iPageCount;
+ }
+ else if (iCurrentPage >= (iPages - iPageCountHalf))
+ {
+ iStartButton = iPages - iPageCount + 1;
+ iEndButton = iPages;
+ }
+ else
+ {
+ iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
+ iEndButton = iStartButton + iPageCount - 1;
+ }
+
+
+ /* Build the dynamic list */
+ for ( i=iStartButton ; i<=iEndButton ; i++ )
+ {
+ sList += (iCurrentPage !== i) ?
+ '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+'">'+oSettings.fnFormatNumber(i)+'</a>' :
+ '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButtonActive+'">'+oSettings.fnFormatNumber(i)+'</a>';
+ }
+
+ /* Loop over each instance of the pager */
+ for ( i=0, iLen=an.length ; i<iLen ; i++ )
+ {
+ nNode = an[i];
+ if ( !nNode.hasChildNodes() )
+ {
+ continue;
+ }
+
+ /* Build up the dynamic list first - html and listeners */
+ $('span:eq(0)', nNode)
+ .html( sList )
+ .children('a').each( fnBind );
+
+ /* Update the permanent button's classes */
+ anButtons = nNode.getElementsByTagName('a');
+ anStatic = [
+ anButtons[0], anButtons[1],
+ anButtons[anButtons.length-2], anButtons[anButtons.length-1]
+ ];
+
+ $(anStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive+" "+oClasses.sPageButtonStaticDisabled );
+ $([anStatic[0], anStatic[1]]).addClass(
+ (iCurrentPage==1) ?
+ oClasses.sPageButtonStaticDisabled :
+ oClasses.sPageButton
+ );
+ $([anStatic[2], anStatic[3]]).addClass(
+ (iPages===0 || iCurrentPage===iPages || oSettings._iDisplayLength===-1) ?
+ oClasses.sPageButtonStaticDisabled :
+ oClasses.sPageButton
+ );
+ }
+ }
+ }
+ } );
+
+ $.extend( DataTable.ext.oSort, {
+ /*
+ * text sorting
+ */
+ "string-pre": function ( a )
+ {
+ if ( typeof a != 'string' ) {
+ a = (a !== null && a.toString) ? a.toString() : '';
+ }
+ return a.toLowerCase();
+ },
+
+ "string-asc": function ( x, y )
+ {
+ return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ },
+
+ "string-desc": function ( x, y )
+ {
+ return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ },
+
+
+ /*
+ * html sorting (ignore html tags)
+ */
+ "html-pre": function ( a )
+ {
+ return a.replace( /<.*?>/g, "" ).toLowerCase();
+ },
+
+ "html-asc": function ( x, y )
+ {
+ return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ },
+
+ "html-desc": function ( x, y )
+ {
+ return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ },
+
+
+ /*
+ * date sorting
+ */
+ "date-pre": function ( a )
+ {
+ var x = Date.parse( a );
+
+ if ( isNaN(x) || x==="" )
+ {
+ x = Date.parse( "01/01/1970 00:00:00" );
+ }
+ return x;
+ },
+
+ "date-asc": function ( x, y )
+ {
+ return x - y;
+ },
+
+ "date-desc": function ( x, y )
+ {
+ return y - x;
+ },
+
+
+ /*
+ * numerical sorting
+ */
+ "numeric-pre": function ( a )
+ {
+ return (a=="-" || a==="") ? 0 : a*1;
+ },
+
+ "numeric-asc": function ( x, y )
+ {
+ return x - y;
+ },
+
+ "numeric-desc": function ( x, y )
+ {
+ return y - x;
+ }
+ } );
+
+
+ $.extend( DataTable.ext.aTypes, [
+ /*
+ * Function: -
+ * Purpose: Check to see if a string is numeric
+ * Returns: string:'numeric' or null
+ * Inputs: mixed:sText - string to check
+ */
+ function ( sData )
+ {
+ /* Allow zero length strings as a number */
+ if ( typeof sData === 'number' )
+ {
+ return 'numeric';
+ }
+ else if ( typeof sData !== 'string' )
+ {
+ return null;
+ }
+
+ var sValidFirstChars = "0123456789-";
+ var sValidChars = "0123456789.";
+ var Char;
+ var bDecimal = false;
+
+ /* Check for a valid first char (no period and allow negatives) */
+ Char = sData.charAt(0);
+ if (sValidFirstChars.indexOf(Char) == -1)
+ {
+ return null;
+ }
+
+ /* Check all the other characters are valid */
+ for ( var i=1 ; i<sData.length ; i++ )
+ {
+ Char = sData.charAt(i);
+ if (sValidChars.indexOf(Char) == -1)
+ {
+ return null;
+ }
+
+ /* Only allowed one decimal place... */
+ if ( Char == "." )
+ {
+ if ( bDecimal )
+ {
+ return null;
+ }
+ bDecimal = true;
+ }
+ }
+
+ return 'numeric';
+ },
+
+ /*
+ * Function: -
+ * Purpose: Check to see if a string is actually a formatted date
+ * Returns: string:'date' or null
+ * Inputs: string:sText - string to check
+ */
+ function ( sData )
+ {
+ var iParse = Date.parse(sData);
+ if ( (iParse !== null && !isNaN(iParse)) || (typeof sData === 'string' && sData.length === 0) )
+ {
+ return 'date';
+ }
+ return null;
+ },
+
+ /*
+ * Function: -
+ * Purpose: Check to see if a string should be treated as an HTML string
+ * Returns: string:'html' or null
+ * Inputs: string:sText - string to check
+ */
+ function ( sData )
+ {
+ if ( typeof sData === 'string' && sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )
+ {
+ return 'html';
+ }
+ return null;
+ }
+ ] );
+
+
+ // jQuery aliases
+ $.fn.DataTable = DataTable;
+ $.fn.dataTable = DataTable;
+ $.fn.dataTableSettings = DataTable.settings;
+ $.fn.dataTableExt = DataTable.ext;
+
+
+ // Information about events fired by DataTables - for documentation.
+ /**
+ * Draw event, fired whenever the table is redrawn on the page, at the same point as
+ * fnDrawCallback. This may be useful for binding events or performing calculations when
+ * the table is altered at all.
+ * @name DataTable#draw
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+ */
+
+ /**
+ * Filter event, fired when the filtering applied to the table (using the build in global
+ * global filter, or column filters) is altered.
+ * @name DataTable#filter
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+ */
+
+ /**
+ * Page change event, fired when the paging of the table is altered.
+ * @name DataTable#page
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+ */
+
+ /**
+ * Sort event, fired when the sorting applied to the table is altered.
+ * @name DataTable#sort
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+ */
+
+ /**
+ * DataTables initialisation complete event, fired when the table is fully drawn,
+ * including Ajax data loaded, if Ajax data is required.
+ * @name DataTable#init
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} oSettings DataTables settings object
+ * @param {object} json The JSON object request from the server - only
+ * present if client-side Ajax sourced data is used</li></ol>
+ */
+
+ /**
+ * State save event, fired when the table has changed state a new state save is required.
+ * This method allows modification of the state saving object prior to actually doing the
+ * save, including addition or other state properties (for plug-ins) or modification
+ * of a DataTables core property.
+ * @name DataTable#stateSaveParams
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} oSettings DataTables settings object
+ * @param {object} json The state information to be saved
+ */
+
+ /**
+ * State load event, fired when the table is loading state from the stored data, but
+ * prior to the settings object being modified by the saved state - allowing modification
+ * of the saved state is required or loading of state for a plug-in.
+ * @name DataTable#stateLoadParams
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} oSettings DataTables settings object
+ * @param {object} json The saved state information
+ */
+
+ /**
+ * State loaded event, fired when state has been loaded from stored data and the settings
+ * object has been modified by the loaded data.
+ * @name DataTable#stateLoaded
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} oSettings DataTables settings object
+ * @param {object} json The saved state information
+ */
+
+ /**
+ * Processing event, fired when DataTables is doing some kind of processing (be it,
+ * sort, filter or anything else). Can be used to indicate to the end user that
+ * there is something happening, or that something has finished.
+ * @name DataTable#processing
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} oSettings DataTables settings object
+ * @param {boolean} bShow Flag for if DataTables is doing processing or not
+ */
+
+ /**
+ * Ajax (XHR) event, fired whenever an Ajax request is completed from a request to
+ * made to the server for new data (note that this trigger is called in fnServerData,
+ * if you override fnServerData and which to use this event, you need to trigger it in
+ * you success function).
+ * @name DataTable#xhr
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+ * @param {object} json JSON returned from the server
+ */
+
+ /**
+ * Destroy event, fired when the DataTable is destroyed by calling fnDestroy or passing
+ * the bDestroy:true parameter in the initialisation object. This can be used to remove
+ * bound events, added DOM nodes, etc.
+ * @name DataTable#destroy
+ * @event
+ * @param {event} e jQuery event object
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+ */
+}));
+
+}(window, document));
+
diff --git a/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables_themeroller.css b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables_themeroller.css
new file mode 100644
index 00000000..cf1d4ed7
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/datatables/jquery.dataTables_themeroller.css
@@ -0,0 +1,244 @@
+
+
+/*
+ * Table
+ */
+table.dataTable {
+ margin: 0 auto;
+ clear: both;
+ width: 100%;
+ border-collapse: collapse;
+}
+
+table.dataTable thead th {
+ padding: 3px 0px 3px 10px;
+ cursor: pointer;
+ *cursor: hand;
+}
+
+table.dataTable tfoot th {
+ padding: 3px 10px;
+}
+
+table.dataTable td {
+ padding: 3px 10px;
+}
+
+table.dataTable td.center,
+table.dataTable td.dataTables_empty {
+ text-align: center;
+}
+
+table.dataTable tr.odd { background-color: #E2E4FF; }
+table.dataTable tr.even { background-color: white; }
+
+table.dataTable tr.odd td.sorting_1 { background-color: #D3D6FF; }
+table.dataTable tr.odd td.sorting_2 { background-color: #DADCFF; }
+table.dataTable tr.odd td.sorting_3 { background-color: #E0E2FF; }
+table.dataTable tr.even td.sorting_1 { background-color: #EAEBFF; }
+table.dataTable tr.even td.sorting_2 { background-color: #F2F3FF; }
+table.dataTable tr.even td.sorting_3 { background-color: #F9F9FF; }
+
+
+/*
+ * Table wrapper
+ */
+.dataTables_wrapper {
+ position: relative;
+ clear: both;
+ *zoom: 1;
+}
+.dataTables_wrapper .ui-widget-header {
+ font-weight: normal;
+}
+.dataTables_wrapper .ui-toolbar {
+ padding: 5px;
+}
+
+
+/*
+ * Page length menu
+ */
+.dataTables_length {
+ float: left;
+}
+
+
+/*
+ * Filter
+ */
+.dataTables_filter {
+ float: right;
+ text-align: right;
+}
+
+
+/*
+ * Table information
+ */
+.dataTables_info {
+ padding-top: 3px;
+ clear: both;
+ float: left;
+}
+
+
+/*
+ * Pagination
+ */
+.dataTables_paginate {
+ float: right;
+ text-align: right;
+}
+
+.dataTables_paginate .ui-button {
+ margin-right: -0.1em !important;
+}
+
+.paging_two_button .ui-button {
+ float: left;
+ cursor: pointer;
+ * cursor: hand;
+}
+
+.paging_full_numbers .ui-button {
+ padding: 2px 6px;
+ margin: 0;
+ cursor: pointer;
+ * cursor: hand;
+ color: #333 !important;
+}
+
+/* Two button pagination - previous / next */
+.paginate_disabled_previous,
+.paginate_enabled_previous,
+.paginate_disabled_next,
+.paginate_enabled_next {
+ height: 19px;
+ float: left;
+ cursor: pointer;
+ *cursor: hand;
+ color: #111 !important;
+}
+.paginate_disabled_previous:hover,
+.paginate_enabled_previous:hover,
+.paginate_disabled_next:hover,
+.paginate_enabled_next:hover {
+ text-decoration: none !important;
+}
+.paginate_disabled_previous:active,
+.paginate_enabled_previous:active,
+.paginate_disabled_next:active,
+.paginate_enabled_next:active {
+ outline: none;
+}
+
+.paginate_disabled_previous,
+.paginate_disabled_next {
+ color: #666 !important;
+}
+.paginate_disabled_previous,
+.paginate_enabled_previous {
+ padding-left: 23px;
+}
+.paginate_disabled_next,
+.paginate_enabled_next {
+ padding-right: 23px;
+ margin-left: 10px;
+}
+
+.paginate_enabled_previous { background: url('../images/back_enabled.png') no-repeat top left; }
+.paginate_enabled_previous:hover { background: url('../images/back_enabled_hover.png') no-repeat top left; }
+.paginate_disabled_previous { background: url('../images/back_disabled.png') no-repeat top left; }
+
+.paginate_enabled_next { background: url('../images/forward_enabled.png') no-repeat top right; }
+.paginate_enabled_next:hover { background: url('../images/forward_enabled_hover.png') no-repeat top right; }
+.paginate_disabled_next { background: url('../images/forward_disabled.png') no-repeat top right; }
+
+/* Full number pagination */
+.paging_full_numbers a:active {
+ outline: none
+}
+.paging_full_numbers a:hover {
+ text-decoration: none;
+}
+
+.paging_full_numbers a.paginate_button,
+.paging_full_numbers a.paginate_active {
+ border: 1px solid #aaa;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+ padding: 2px 5px;
+ margin: 0 3px;
+ cursor: pointer;
+ *cursor: hand;
+ color: #333 !important;
+}
+
+.paging_full_numbers a.paginate_button {
+ background-color: #ddd;
+}
+
+.paging_full_numbers a.paginate_button:hover {
+ background-color: #ccc;
+ text-decoration: none !important;
+}
+
+.paging_full_numbers a.paginate_active {
+ background-color: #99B3FF;
+}
+
+
+/*
+ * Processing indicator
+ */
+.dataTables_processing {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 250px;
+ height: 30px;
+ margin-left: -125px;
+ margin-top: -15px;
+ padding: 14px 0 2px 0;
+ border: 1px solid #ddd;
+ text-align: center;
+ color: #999;
+ font-size: 14px;
+ background-color: white;
+}
+
+
+/*
+ * Sorting
+ */
+table.dataTable thead th div.DataTables_sort_wrapper {
+ position: relative;
+ padding-right: 20px;
+}
+
+table.dataTable thead th div.DataTables_sort_wrapper span {
+ position: absolute;
+ top: 50%;
+ margin-top: -8px;
+ right: 0;
+}
+
+table.dataTable th:active {
+ outline: none;
+}
+
+
+/*
+ * Scrolling
+ */
+.dataTables_scroll {
+ clear: both;
+}
+
+.dataTables_scrollBody {
+ *margin-top: -1px;
+ -webkit-overflow-scrolling: touch;
+}
+
diff --git a/SemanticResultFormats/resources/jquery/dygraphs/dygraph-combined.js b/SemanticResultFormats/resources/jquery/dygraphs/dygraph-combined.js
new file mode 100644
index 00000000..bb2f96a6
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/dygraphs/dygraph-combined.js
@@ -0,0 +1,2 @@
+/*! @license Copyright 2011 Dan Vanderkam (danvdk@gmail.com) MIT-licensed (http://opensource.org/licenses/MIT) */
+Date.ext={};Date.ext.util={};Date.ext.util.xPad=function(a,c,b){if(typeof(b)=="undefined"){b=10}for(;parseInt(a,10)<b&&b>1;b/=10){a=c.toString()+a}return a.toString()};Date.prototype.locale="en-GB";if(document.getElementsByTagName("html")&&document.getElementsByTagName("html")[0].lang){Date.prototype.locale=document.getElementsByTagName("html")[0].lang}Date.ext.locales={};Date.ext.locales.en={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],x:"%d/%m/%y",X:"%T"};Date.ext.locales["en-US"]=Date.ext.locales.en;Date.ext.locales["en-US"].c="%a %d %b %Y %r %Z";Date.ext.locales["en-US"].x="%D";Date.ext.locales["en-US"].X="%r";Date.ext.locales["en-GB"]=Date.ext.locales.en;Date.ext.locales["en-AU"]=Date.ext.locales["en-GB"];Date.ext.formats={a:function(a){return Date.ext.locales[a.locale].a[a.getDay()]},A:function(a){return Date.ext.locales[a.locale].A[a.getDay()]},b:function(a){return Date.ext.locales[a.locale].b[a.getMonth()]},B:function(a){return Date.ext.locales[a.locale].B[a.getMonth()]},c:"toLocaleString",C:function(a){return Date.ext.util.xPad(parseInt(a.getFullYear()/100,10),0)},d:["getDate","0"],e:["getDate"," "],g:function(a){return Date.ext.util.xPad(parseInt(Date.ext.util.G(a)/100,10),0)},G:function(c){var e=c.getFullYear();var b=parseInt(Date.ext.formats.V(c),10);var a=parseInt(Date.ext.formats.W(c),10);if(a>b){e++}else{if(a===0&&b>=52){e--}}return e},H:["getHours","0"],I:function(b){var a=b.getHours()%12;return Date.ext.util.xPad(a===0?12:a,0)},j:function(c){var a=c-new Date(""+c.getFullYear()+"/1/1 GMT");a+=c.getTimezoneOffset()*60000;var b=parseInt(a/60000/60/24,10)+1;return Date.ext.util.xPad(b,0,100)},m:function(a){return Date.ext.util.xPad(a.getMonth()+1,0)},M:["getMinutes","0"],p:function(a){return Date.ext.locales[a.locale].p[a.getHours()>=12?1:0]},P:function(a){return Date.ext.locales[a.locale].P[a.getHours()>=12?1:0]},S:["getSeconds","0"],u:function(a){var b=a.getDay();return b===0?7:b},U:function(e){var a=parseInt(Date.ext.formats.j(e),10);var c=6-e.getDay();var b=parseInt((a+c)/7,10);return Date.ext.util.xPad(b,0)},V:function(e){var c=parseInt(Date.ext.formats.W(e),10);var a=(new Date(""+e.getFullYear()+"/1/1")).getDay();var b=c+(a>4||a<=1?0:1);if(b==53&&(new Date(""+e.getFullYear()+"/12/31")).getDay()<4){b=1}else{if(b===0){b=Date.ext.formats.V(new Date(""+(e.getFullYear()-1)+"/12/31"))}}return Date.ext.util.xPad(b,0)},w:"getDay",W:function(e){var a=parseInt(Date.ext.formats.j(e),10);var c=7-Date.ext.formats.u(e);var b=parseInt((a+c)/7,10);return Date.ext.util.xPad(b,0,10)},y:function(a){return Date.ext.util.xPad(a.getFullYear()%100,0)},Y:"getFullYear",z:function(c){var b=c.getTimezoneOffset();var a=Date.ext.util.xPad(parseInt(Math.abs(b/60),10),0);var e=Date.ext.util.xPad(b%60,0);return(b>0?"-":"+")+a+e},Z:function(a){return a.toString().replace(/^.*\(([^)]+)\)$/,"$1")},"%":function(a){return"%"}};Date.ext.aggregates={c:"locale",D:"%m/%d/%y",h:"%b",n:"\n",r:"%I:%M:%S %p",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"};Date.ext.aggregates.z=Date.ext.formats.z(new Date());Date.ext.aggregates.Z=Date.ext.formats.Z(new Date());Date.ext.unsupported={};Date.prototype.strftime=function(a){if(!(this.locale in Date.ext.locales)){if(this.locale.replace(/-[a-zA-Z]+$/,"") in Date.ext.locales){this.locale=this.locale.replace(/-[a-zA-Z]+$/,"")}else{this.locale="en-GB"}}var c=this;while(a.match(/%[cDhnrRtTxXzZ]/)){a=a.replace(/%([cDhnrRtTxXzZ])/g,function(e,d){var g=Date.ext.aggregates[d];return(g=="locale"?Date.ext.locales[c.locale][d]:g)})}var b=a.replace(/%([aAbBCdegGHIjmMpPSuUVwWyY%])/g,function(e,d){var g=Date.ext.formats[d];if(typeof(g)=="string"){return c[g]()}else{if(typeof(g)=="function"){return g.call(c,c)}else{if(typeof(g)=="object"&&typeof(g[0])=="string"){return Date.ext.util.xPad(c[g[0]](),g[1])}else{return d}}}});c=null;return b};"use strict";function RGBColorParser(f){this.ok=false;if(f.charAt(0)=="#"){f=f.substr(1,6)}f=f.replace(/ /g,"");f=f.toLowerCase();var b={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"00ffff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000000",blanchedalmond:"ffebcd",blue:"0000ff",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"00ffff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dodgerblue:"1e90ff",feldspar:"d19275",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"ff00ff",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgrey:"d3d3d3",lightgreen:"90ee90",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslateblue:"8470ff",lightslategray:"778899",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"00ff00",limegreen:"32cd32",linen:"faf0e6",magenta:"ff00ff",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370d8",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"d87093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",red:"ff0000",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",violetred:"d02090",wheat:"f5deb3",white:"ffffff",whitesmoke:"f5f5f5",yellow:"ffff00",yellowgreen:"9acd32"};for(var g in b){if(f==g){f=b[g]}}var e=[{re:/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,example:["rgb(123, 234, 45)","rgb(255,234,245)"],process:function(i){return[parseInt(i[1]),parseInt(i[2]),parseInt(i[3])]}},{re:/^(\w{2})(\w{2})(\w{2})$/,example:["#00ff00","336699"],process:function(i){return[parseInt(i[1],16),parseInt(i[2],16),parseInt(i[3],16)]}},{re:/^(\w{1})(\w{1})(\w{1})$/,example:["#fb0","f0f"],process:function(i){return[parseInt(i[1]+i[1],16),parseInt(i[2]+i[2],16),parseInt(i[3]+i[3],16)]}}];for(var c=0;c<e.length;c++){var j=e[c].re;var a=e[c].process;var h=j.exec(f);if(h){var d=a(h);this.r=d[0];this.g=d[1];this.b=d[2];this.ok=true}}this.r=(this.r<0||isNaN(this.r))?0:((this.r>255)?255:this.r);this.g=(this.g<0||isNaN(this.g))?0:((this.g>255)?255:this.g);this.b=(this.b<0||isNaN(this.b))?0:((this.b>255)?255:this.b);this.toRGB=function(){return"rgb("+this.r+", "+this.g+", "+this.b+")"};this.toHex=function(){var l=this.r.toString(16);var k=this.g.toString(16);var i=this.b.toString(16);if(l.length==1){l="0"+l}if(k.length==1){k="0"+k}if(i.length==1){i="0"+i}return"#"+l+k+i}}function printStackTrace(b){b=b||{guess:true};var c=b.e||null,e=!!b.guess;var d=new printStackTrace.implementation(),a=d.run(c);return(e)?d.guessAnonymousFunctions(a):a}printStackTrace.implementation=function(){};printStackTrace.implementation.prototype={run:function(a,b){a=a||this.createException();b=b||this.mode(a);if(b==="other"){return this.other(arguments.callee)}else{return this[b](a)}},createException:function(){try{this.undef()}catch(a){return a}},mode:function(a){if(a["arguments"]&&a.stack){return"chrome"}else{if(typeof a.message==="string"&&typeof window!=="undefined"&&window.opera){if(!a.stacktrace){return"opera9"}if(a.message.indexOf("\n")>-1&&a.message.split("\n").length>a.stacktrace.split("\n").length){return"opera9"}if(!a.stack){return"opera10a"}if(a.stacktrace.indexOf("called from line")<0){return"opera10b"}return"opera11"}else{if(a.stack){return"firefox"}}}return"other"},instrumentFunction:function(b,d,e){b=b||window;var a=b[d];b[d]=function c(){e.call(this,printStackTrace().slice(4));return b[d]._instrumented.apply(this,arguments)};b[d]._instrumented=a},deinstrumentFunction:function(a,b){if(a[b].constructor===Function&&a[b]._instrumented&&a[b]._instrumented.constructor===Function){a[b]=a[b]._instrumented}},chrome:function(b){var a=(b.stack+"\n").replace(/^\S[^\(]+?[\n$]/gm,"").replace(/^\s+at\s+/gm,"").replace(/^([^\(]+?)([\n$])/gm,"{anonymous}()@$1$2").replace(/^Object.<anonymous>\s*\(([^\)]+)\)/gm,"{anonymous}()@$1").split("\n");a.pop();return a},firefox:function(a){return a.stack.replace(/(?:\n@:0)?\s+$/m,"").replace(/^\(/gm,"{anonymous}(").split("\n")},opera11:function(g){var a="{anonymous}",h=/^.*line (\d+), column (\d+)(?: in (.+))? in (\S+):$/;var k=g.stacktrace.split("\n"),l=[];for(var c=0,f=k.length;c<f;c+=2){var d=h.exec(k[c]);if(d){var j=d[4]+":"+d[1]+":"+d[2];var b=d[3]||"global code";b=b.replace(/<anonymous function: (\S+)>/,"$1").replace(/<anonymous function>/,a);l.push(b+"@"+j+" -- "+k[c+1].replace(/^\s+/,""))}}return l},opera10b:function(g){var a="{anonymous}",h=/^(.*)@(.+):(\d+)$/;var j=g.stacktrace.split("\n"),k=[];for(var c=0,f=j.length;c<f;c++){var d=h.exec(j[c]);if(d){var b=d[1]?(d[1]+"()"):"global code";k.push(b+"@"+d[2]+":"+d[3])}}return k},opera10a:function(g){var a="{anonymous}",h=/Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i;var j=g.stacktrace.split("\n"),k=[];for(var c=0,f=j.length;c<f;c+=2){var d=h.exec(j[c]);if(d){var b=d[3]||a;k.push(b+"()@"+d[2]+":"+d[1]+" -- "+j[c+1].replace(/^\s+/,""))}}return k},opera9:function(j){var d="{anonymous}",h=/Line (\d+).*script (?:in )?(\S+)/i;var c=j.message.split("\n"),b=[];for(var g=2,a=c.length;g<a;g+=2){var f=h.exec(c[g]);if(f){b.push(d+"()@"+f[2]+":"+f[1]+" -- "+c[g+1].replace(/^\s+/,""))}}return b},other:function(g){var b="{anonymous}",f=/function\s*([\w\-$]+)?\s*\(/i,a=[],d,c,e=10;while(g&&a.length<e){d=f.test(g.toString())?RegExp.$1||b:b;c=Array.prototype.slice.call(g["arguments"]||[]);a[a.length]=d+"("+this.stringifyArguments(c)+")";g=g.caller}return a},stringifyArguments:function(c){var b=[];var e=Array.prototype.slice;for(var d=0;d<c.length;++d){var a=c[d];if(a===undefined){b[d]="undefined"}else{if(a===null){b[d]="null"}else{if(a.constructor){if(a.constructor===Array){if(a.length<3){b[d]="["+this.stringifyArguments(a)+"]"}else{b[d]="["+this.stringifyArguments(e.call(a,0,1))+"..."+this.stringifyArguments(e.call(a,-1))+"]"}}else{if(a.constructor===Object){b[d]="#object"}else{if(a.constructor===Function){b[d]="#function"}else{if(a.constructor===String){b[d]='"'+a+'"'}else{if(a.constructor===Number){b[d]=a}}}}}}}}}return b.join(",")},sourceCache:{},ajax:function(a){var b=this.createXMLHTTPObject();if(b){try{b.open("GET",a,false);b.send(null);return b.responseText}catch(c){}}return""},createXMLHTTPObject:function(){var c,a=[function(){return new XMLHttpRequest()},function(){return new ActiveXObject("Msxml2.XMLHTTP")},function(){return new ActiveXObject("Msxml3.XMLHTTP")},function(){return new ActiveXObject("Microsoft.XMLHTTP")}];for(var b=0;b<a.length;b++){try{c=a[b]();this.createXMLHTTPObject=a[b];return c}catch(d){}}},isSameDomain:function(a){return a.indexOf(location.hostname)!==-1},getSource:function(a){if(!(a in this.sourceCache)){this.sourceCache[a]=this.ajax(a).split("\n")}return this.sourceCache[a]},guessAnonymousFunctions:function(k){for(var g=0;g<k.length;++g){var f=/\{anonymous\}\(.*\)@(.*)/,l=/^(.*?)(?::(\d+))(?::(\d+))?(?: -- .+)?$/,b=k[g],c=f.exec(b);if(c){var e=l.exec(c[1]),d=e[1],a=e[2],j=e[3]||0;if(d&&this.isSameDomain(d)&&a){var h=this.guessAnonymousFunction(d,a,j);k[g]=b.replace("{anonymous}",h)}}}return k},guessAnonymousFunction:function(c,f,a){var b;try{b=this.findFunctionName(this.getSource(c),f)}catch(d){b="getSource failed with url: "+c+", exception: "+d.toString()}return b},findFunctionName:function(a,e){var g=/function\s+([^(]*?)\s*\(([^)]*)\)/;var k=/['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*function\b/;var h=/['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*(?:eval|new Function)\b/;var b="",l,j=Math.min(e,20),d,c;for(var f=0;f<j;++f){l=a[e-f-1];c=l.indexOf("//");if(c>=0){l=l.substr(0,c)}if(l){b=l+b;d=k.exec(b);if(d&&d[1]){return d[1]}d=g.exec(b);if(d&&d[1]){return d[1]}d=h.exec(b);if(d&&d[1]){return d[1]}}}return"(?)"}};CanvasRenderingContext2D.prototype.installPattern=function(e){if(typeof(this.isPatternInstalled)!=="undefined"){throw"Must un-install old line pattern before installing a new one."}this.isPatternInstalled=true;var g=[0,0];var b=[];var f=this.beginPath;var d=this.lineTo;var c=this.moveTo;var a=this.stroke;this.uninstallPattern=function(){this.beginPath=f;this.lineTo=d;this.moveTo=c;this.stroke=a;this.uninstallPattern=undefined;this.isPatternInstalled=undefined};this.beginPath=function(){b=[];f.call(this)};this.moveTo=function(h,i){b.push([[h,i]]);c.call(this,h,i)};this.lineTo=function(h,j){var i=b[b.length-1];i.push([h,j])};this.stroke=function(){if(b.length===0){a.call(this);return}for(var p=0;p<b.length;p++){var o=b[p];var l=o[0][0],u=o[0][1];for(var n=1;n<o.length;n++){var h=o[n][0],s=o[n][1];this.save();var w=(h-l);var v=(s-u);var r=Math.sqrt(w*w+v*v);var k=Math.atan2(v,w);this.translate(l,u);c.call(this,0,0);this.rotate(k);var m=g[0];var t=0;while(r>t){var q=e[m];if(g[1]){t+=g[1]}else{t+=q}if(t>r){g=[m,t-r];t=r}else{g=[(m+1)%e.length,0]}if(m%2===0){d.call(this,t,0)}else{c.call(this,t,0)}m=(m+1)%e.length}this.restore();l=h,u=s}}a.call(this);b=[]}};CanvasRenderingContext2D.prototype.uninstallPattern=function(){throw"Must install a line pattern before uninstalling it."};"use strict";var DygraphOptions=function(a){this.dygraph_=a;this.yAxes_=[];this.xAxis_={};this.series_={};this.global_=this.dygraph_.attrs_;this.user_=this.dygraph_.user_attrs_||{};this.highlightSeries_=this.get("highlightSeriesOpts")||{};var b=this.get("labels");if(!b){return}this.reparseSeries()};DygraphOptions.AXIS_STRING_MAPPINGS_={y:0,Y:0,y1:0,Y1:0,y2:1,Y2:1};DygraphOptions.axisToIndex_=function(a){if(typeof(a)=="string"){if(DygraphOptions.AXIS_STRING_MAPPINGS_.hasOwnProperty(a)){return DygraphOptions.AXIS_STRING_MAPPINGS_[a]}throw"Unknown axis : "+a}if(typeof(a)=="number"){if(a===0||a===1){return a}throw"Dygraphs only supports two y-axes, indexed from 0-1."}if(typeof(a)=="object"){throw"Using objects for axis specification is not supported inside the 'series' option."}if(a){throw"Unknown axis : "+a}return 0};DygraphOptions.prototype.reparseSeries=function(){this.labels=this.get("labels").slice(1);this.yAxes_=[{series:[],options:{}}];this.xAxis_={options:{}};this.series_={};var d=!this.user_.series;if(d){var f=0;for(var b=0;b<this.labels.length;b++){var a=this.labels[b];var g=this.user_[a]||{};var c=0;var e=g.axis;if(typeof(e)=="object"){c=++f;this.yAxes_[c]={series:[a],options:e}}if(!e){this.yAxes_[0].series.push(a)}this.series_[a]={idx:b,yAxis:c,options:g}}for(var b=0;b<this.labels.length;b++){var a=this.labels[b];var g=this.series_[a]["options"];var e=g.axis;if(typeof(e)=="string"){if(!this.series_.hasOwnProperty(e)){this.dygraph_.error("Series "+a+" wants to share a y-axis with series "+e+", which does not define its own axis.");return null}var c=this.series_[e].yAxis;this.series_[a].yAxis=c;this.yAxes_[c].series.push(a)}}}else{for(var b=0;b<this.labels.length;b++){var a=this.labels[b];var g=this.user_.series[a]||{};var c=DygraphOptions.axisToIndex_(g.axis);this.series_[a]={idx:b,yAxis:c,options:g};if(!this.yAxes_[c]){this.yAxes_[c]={series:[a],options:{}}}else{this.yAxes_[c].series.push(a)}}}var h=this.user_.axes||{};Dygraph.update(this.yAxes_[0].options,h.y||{});if(this.yAxes_.length>1){Dygraph.update(this.yAxes_[1].options,h.y2||{})}Dygraph.update(this.xAxis_.options,h.x||{})};DygraphOptions.prototype.get=function(b){var a=this.getGlobalUser_(b);if(a!=null){return a}return this.getGlobalDefault_(b)};DygraphOptions.prototype.getGlobalUser_=function(a){if(this.user_.hasOwnProperty(a)){return this.user_[a]}return null};DygraphOptions.prototype.getGlobalDefault_=function(a){if(this.global_.hasOwnProperty(a)){return this.global_[a]}if(Dygraph.DEFAULT_ATTRS.hasOwnProperty(a)){return Dygraph.DEFAULT_ATTRS[a]}return null};DygraphOptions.prototype.getForAxis=function(c,d){var e;var h;if(typeof(d)=="number"){e=d;h=e==0?"y":"y2"}else{if(d=="y1"){d="y"}if(d=="y"){e=0}else{if(d=="y2"){e=1}else{if(d=="x"){e=-1}else{throw"Unknown axis "+d}}}h=d}var f=(e==-1)?this.xAxis_:this.yAxes_[e];if(f){var g=f.options;if(g.hasOwnProperty(c)){return g[c]}}var b=this.getGlobalUser_(c);if(b!=null){return b}var a=Dygraph.DEFAULT_ATTRS.axes[h];if(a.hasOwnProperty(c)){return a[c]}return this.getGlobalDefault_(c)};DygraphOptions.prototype.getForSeries=function(b,d){if(d===this.dygraph_.highlightSet_){if(this.highlightSeries_.hasOwnProperty(b)){return this.highlightSeries_[b]}}if(!this.series_.hasOwnProperty(d)){throw"Unknown series: "+d}var c=this.series_[d];var a=c.options;if(a.hasOwnProperty(b)){return a[b]}return this.getForAxis(b,c.yAxis)};DygraphOptions.prototype.numAxes=function(){return this.yAxes_.length};DygraphOptions.prototype.axisForSeries=function(a){return this.series_[a].yAxis};DygraphOptions.prototype.axisOptions=function(a){return this.yAxes_[a].options};DygraphOptions.prototype.seriesForAxis=function(a){return this.yAxes_[a].series};DygraphOptions.prototype.seriesNames=function(){return this.labels_};DygraphOptions.prototype.indexOfSeries=function(a){return this.series_[a].idx};"use strict";var DygraphLayout=function(a){this.dygraph_=a;this.datasets=[];this.setNames=[];this.annotations=[];this.yAxes_=null;this.points=null;this.xTicks_=null;this.yTicks_=null};DygraphLayout.prototype.attr_=function(a){return this.dygraph_.attr_(a)};DygraphLayout.prototype.addDataset=function(a,b){this.datasets.push(b);this.setNames.push(a)};DygraphLayout.prototype.getPlotArea=function(){return this.computePlotArea_()};DygraphLayout.prototype.computePlotArea_=function(){var a={x:0,y:0};a.w=this.dygraph_.width_-a.x-this.attr_("rightGap");a.h=this.dygraph_.height_;var b={chart_div:this.dygraph_.graphDiv,reserveSpaceLeft:function(c){var d={x:a.x,y:a.y,w:c,h:a.h};a.x+=c;a.w-=c;return d},reserveSpaceRight:function(c){var d={x:a.x+a.w-c,y:a.y,w:c,h:a.h};a.w-=c;return d},reserveSpaceTop:function(c){var d={x:a.x,y:a.y,w:a.w,h:c};a.y+=c;a.h-=c;return d},reserveSpaceBottom:function(c){var d={x:a.x,y:a.y+a.h-c,w:a.w,h:c};a.h-=c;return d},chartRect:function(){return{x:a.x,y:a.y,w:a.w,h:a.h}}};this.dygraph_.cascadeEvents_("layout",b);if(this.attr_("showRangeSelector")){a.h-=this.attr_("rangeSelectorHeight")+4}return a};DygraphLayout.prototype.setAnnotations=function(d){this.annotations=[];var e=this.attr_("xValueParser")||function(a){return a};for(var c=0;c<d.length;c++){var b={};if(!d[c].xval&&!d[c].x){this.dygraph_.error("Annotations must have an 'x' property");return}if(d[c].icon&&!(d[c].hasOwnProperty("width")&&d[c].hasOwnProperty("height"))){this.dygraph_.error("Must set width and height when setting annotation.icon property");return}Dygraph.update(b,d[c]);if(!b.xval){b.xval=e(b.x)}this.annotations.push(b)}};DygraphLayout.prototype.setXTicks=function(a){this.xTicks_=a};DygraphLayout.prototype.setYAxes=function(a){this.yAxes_=a};DygraphLayout.prototype.setDateWindow=function(a){this.dateWindow_=a};DygraphLayout.prototype.evaluate=function(){this._evaluateLimits();this._evaluateLineCharts();this._evaluateLineTicks();this._evaluateAnnotations()};DygraphLayout.prototype._evaluateLimits=function(){this.minxval=this.maxxval=null;if(this.dateWindow_){this.minxval=this.dateWindow_[0];this.maxxval=this.dateWindow_[1]}else{for(var f=0;f<this.datasets.length;++f){var d=this.datasets[f];if(d.length>1){var b=d[0][0];if(!this.minxval||b<this.minxval){this.minxval=b}var a=d[d.length-1][0];if(!this.maxxval||a>this.maxxval){this.maxxval=a}}}}this.xrange=this.maxxval-this.minxval;this.xscale=(this.xrange!==0?1/this.xrange:1);for(var c=0;c<this.yAxes_.length;c++){var e=this.yAxes_[c];e.minyval=e.computedValueRange[0];e.maxyval=e.computedValueRange[1];e.yrange=e.maxyval-e.minyval;e.yscale=(e.yrange!==0?1/e.yrange:1);if(e.g.attr_("logscale")){e.ylogrange=Dygraph.log10(e.maxyval)-Dygraph.log10(e.minyval);e.ylogscale=(e.ylogrange!==0?1/e.ylogrange:1);if(!isFinite(e.ylogrange)||isNaN(e.ylogrange)){e.g.error("axis "+c+" of graph at "+e.g+" can't be displayed in log scale for range ["+e.minyval+" - "+e.maxyval+"]")}}}};DygraphLayout._calcYNormal=function(b,c,a){if(a){return 1-((Dygraph.log10(c)-Dygraph.log10(b.minyval))*b.ylogscale)}else{return 1-((c-b.minyval)*b.yscale)}};DygraphLayout.prototype._evaluateLineCharts=function(){var c=this.attr_("connectSeparatedPoints");this.points=new Array(this.datasets.length);for(var a=0;a<this.datasets.length;a++){var e=this.datasets[a];var h=this.setNames[a];var b=this.dygraph_.axisPropertiesForSeries(h);var i=this.dygraph_.attributes_.getForSeries("logscale",h);var n=new Array(e.length);for(var f=0;f<e.length;f++){var m=e[f];var d=DygraphLayout.parseFloat_(m[0]);var k=DygraphLayout.parseFloat_(m[1]);var l=(d-this.minxval)*this.xscale;var g=DygraphLayout._calcYNormal(b,k,i);if(c&&m[1]===null){k=null}n[f]={x:l,y:g,xval:d,yval:k,name:h}}this.points[a]=n}};DygraphLayout.parseFloat_=function(a){if(a===null){return NaN}return a};DygraphLayout.prototype._evaluateLineTicks=function(){var d,c,b,f;this.xticks=[];for(d=0;d<this.xTicks_.length;d++){c=this.xTicks_[d];b=c.label;f=this.xscale*(c.v-this.minxval);if((f>=0)&&(f<=1)){this.xticks.push([f,b])}}this.yticks=[];for(d=0;d<this.yAxes_.length;d++){var e=this.yAxes_[d];for(var a=0;a<e.ticks.length;a++){c=e.ticks[a];b=c.label;f=this.dygraph_.toPercentYCoord(c.v,d);if((f>=0)&&(f<=1)){this.yticks.push([d,f,b])}}}};DygraphLayout.prototype.evaluateWithError=function(){this.evaluate();if(!(this.attr_("errorBars")||this.attr_("customBars"))){return}var h=0;for(var a=0;a<this.datasets.length;++a){var p=this.points[a];var g=0;var f=this.datasets[a];var l=this.setNames[a];var e=this.dygraph_.axisPropertiesForSeries(l);var m=this.dygraph_.attributes_.getForSeries("logscale",l);for(g=0;g<f.length;g++,h++){var q=f[g];var c=DygraphLayout.parseFloat_(q[0]);var n=DygraphLayout.parseFloat_(q[1]);if(c==p[g].xval&&n==p[g].yval){var k=DygraphLayout.parseFloat_(q[2]);var d=DygraphLayout.parseFloat_(q[3]);var o=n-k;var b=n+d;p[g].y_top=DygraphLayout._calcYNormal(e,o,m);p[g].y_bottom=DygraphLayout._calcYNormal(e,b,m)}}}};DygraphLayout.prototype._evaluateAnnotations=function(){var d;var g={};for(d=0;d<this.annotations.length;d++){var b=this.annotations[d];g[b.xval+","+b.series]=b}this.annotated_points=[];if(!this.annotations||!this.annotations.length){return}for(var h=0;h<this.points.length;h++){var e=this.points[h];for(d=0;d<e.length;d++){var f=e[d];var c=f.xval+","+f.name;if(c in g){f.annotation=g[c];this.annotated_points.push(f)}}}};DygraphLayout.prototype.removeAllDatasets=function(){delete this.datasets;delete this.setNames;delete this.setPointsLengths;delete this.setPointsOffsets;this.datasets=[];this.setNames=[];this.setPointsLengths=[];this.setPointsOffsets=[]};DygraphLayout.prototype.unstackPointAtIndex=function(f,e){var a=this.points[f][e];if(!a.yval){return a}var c={};for(var d in a){c[d]=a[d]}if(!this.attr_("stackedGraph")){return c}if(f==this.points.length-1){return c}var b=this.points[f+1];if(b[e].xval==a.xval&&b[e].yval){c.yval-=b[e].yval}return c};"use strict";var DygraphCanvasRenderer=function(d,c,b,e){this.dygraph_=d;this.layout=e;this.element=c;this.elementContext=b;this.container=this.element.parentNode;this.height=this.element.height;this.width=this.element.width;if(!this.isIE&&!(DygraphCanvasRenderer.isSupported(this.element))){throw"Canvas is not supported."}this.area=e.getPlotArea();this.container.style.position="relative";this.container.style.width=this.width+"px";if(this.dygraph_.isUsingExcanvas_){this._createIEClipArea()}else{if(!Dygraph.isAndroid()){var a=this.dygraph_.canvas_ctx_;a.beginPath();a.rect(this.area.x,this.area.y,this.area.w,this.area.h);a.clip();a=this.dygraph_.hidden_ctx_;a.beginPath();a.rect(this.area.x,this.area.y,this.area.w,this.area.h);a.clip()}}};DygraphCanvasRenderer.prototype.attr_=function(a,b){return this.dygraph_.attr_(a,b)};DygraphCanvasRenderer.prototype.clear=function(){var a;if(this.isIE){try{if(this.clearDelay){this.clearDelay.cancel();this.clearDelay=null}a=this.elementContext}catch(b){return}}a=this.elementContext;a.clearRect(0,0,this.width,this.height)};DygraphCanvasRenderer.isSupported=function(f){var b=null;try{if(typeof(f)=="undefined"||f===null){b=document.createElement("canvas")}else{b=f}b.getContext("2d")}catch(c){var d=navigator.appVersion.match(/MSIE (\d\.\d)/);var a=(navigator.userAgent.toLowerCase().indexOf("opera")!=-1);if((!d)||(d[1]<6)||(a)){return false}return true}return true};DygraphCanvasRenderer.prototype.render=function(){this._updatePoints();this._renderLineChart()};DygraphCanvasRenderer.prototype._createIEClipArea=function(){var g="dygraph-clip-div";var f=this.dygraph_.graphDiv;for(var e=f.childNodes.length-1;e>=0;e--){if(f.childNodes[e].className==g){f.removeChild(f.childNodes[e])}}var c=document.bgColor;var d=this.dygraph_.graphDiv;while(d!=document){var a=d.currentStyle.backgroundColor;if(a&&a!="transparent"){c=a;break}d=d.parentNode}function b(j){if(j.w===0||j.h===0){return}var i=document.createElement("div");i.className=g;i.style.backgroundColor=c;i.style.position="absolute";i.style.left=j.x+"px";i.style.top=j.y+"px";i.style.width=j.w+"px";i.style.height=j.h+"px";f.appendChild(i)}var h=this.area;b({x:0,y:0,w:h.x,h:this.height});b({x:h.x,y:0,w:this.width-h.x,h:h.y});b({x:h.x+h.w,y:0,w:this.width-h.x-h.w,h:this.height});b({x:h.x,y:h.y+h.h,w:this.width-h.x,h:this.height-h.h-h.y})};DygraphCanvasRenderer._getIteratorPredicate=function(a){return a?DygraphCanvasRenderer._predicateThatSkipsEmptyPoints:null};DygraphCanvasRenderer._predicateThatSkipsEmptyPoints=function(b,a){return b[a].yval!==null};DygraphCanvasRenderer._drawStyledLine=function(i,a,m,q,f,n,d){var h=i.dygraph;var c=h.getOption("stepPlot");if(!Dygraph.isArrayLike(q)){q=null}var l=h.getOption("drawGapEdgePoints",i.setName);var o=i.points;var k=Dygraph.createIterator(o,0,o.length,DygraphCanvasRenderer._getIteratorPredicate(h.getOption("connectSeparatedPoints")));var j=q&&(q.length>=2);var p=i.drawingContext;p.save();if(j){p.installPattern(q)}var b=DygraphCanvasRenderer._drawSeries(i,k,m,d,f,l,c,a);DygraphCanvasRenderer._drawPointsOnLine(i,b,n,a,d);if(j){p.uninstallPattern()}p.restore()};DygraphCanvasRenderer._drawSeries=function(w,u,m,h,q,t,g,r){var b=null;var x=null;var k=null;var j;var p;var l=[];var f=true;var o=w.drawingContext;o.beginPath();o.strokeStyle=r;o.lineWidth=m;var c=u.array_;var v=u.end_;var a=u.predicate_;for(var s=u.start_;s<v;s++){p=c[s];if(a){while(s<v&&!a(c,s)){s++}if(s==v){break}p=c[s]}if(p.canvasy===null||p.canvasy!=p.canvasy){if(g&&b!==null){o.moveTo(b,x);o.lineTo(p.canvasx,x)}b=x=null}else{j=false;if(t||!b){u.nextIdx_=s;var n=u.next();k=u.hasNext?u.peek.canvasy:null;var d=k===null||k!=k;j=(!b&&d);if(t){if((!f&&!b)||(u.hasNext&&d)){j=true}}}if(b!==null){if(m){if(g){o.moveTo(b,x);o.lineTo(p.canvasx,x)}o.lineTo(p.canvasx,p.canvasy)}}else{o.moveTo(p.canvasx,p.canvasy)}if(q||j){l.push([p.canvasx,p.canvasy])}b=p.canvasx;x=p.canvasy}f=false}o.stroke();return l};DygraphCanvasRenderer._drawPointsOnLine=function(h,i,f,d,g){var c=h.drawingContext;for(var b=0;b<i.length;b++){var a=i[b];c.save();f(h.dygraph,h.setName,c,a[0],a[1],d,g);c.restore()}};DygraphCanvasRenderer.prototype._updatePoints=function(){var e=this.layout.points;for(var c=e.length;c--;){var d=e[c];for(var b=d.length;b--;){var a=d[b];a.canvasx=this.area.w*a.x+this.area.x;a.canvasy=this.area.h*a.y+this.area.y}}};DygraphCanvasRenderer.prototype._renderLineChart=function(h,x){var k=x||this.elementContext;var u=this.attr_("errorBars")||this.attr_("customBars");var f=this.attr_("fillGraph");var q;var a=this.layout.points;var v=this.layout.setNames;var n=v.length;var b;this.colors=this.dygraph_.colorsMap_;var r=this.attr_("plotter");var g=r;if(!Dygraph.isArrayLike(g)){g=[g]}var c={};for(q=0;q<v.length;q++){b=v[q];var w=this.attr_("plotter",b);if(w==r){continue}c[b]=w}for(q=0;q<g.length;q++){var t=g[q];var s=(q==g.length-1);for(var m=0;m<a.length;m++){b=v[m];if(h&&b!=h){continue}var o=a[m];var e=t;if(b in c){if(s){e=c[b]}else{continue}}var l=this.colors[b];var d=this.dygraph_.getOption("strokeWidth",b);k.save();k.strokeStyle=l;k.lineWidth=d;e({points:o,setName:b,drawingContext:k,color:l,strokeWidth:d,dygraph:this.dygraph_,axis:this.dygraph_.axisPropertiesForSeries(b),plotArea:this.area,seriesIndex:m,seriesCount:a.length,allSeriesPoints:a});k.restore()}}};DygraphCanvasRenderer._Plotters={linePlotter:function(a){DygraphCanvasRenderer._linePlotter(a)},fillPlotter:function(a){DygraphCanvasRenderer._fillPlotter(a)},errorPlotter:function(a){DygraphCanvasRenderer._errorPlotter(a)}};DygraphCanvasRenderer._linePlotter=function(f){var d=f.dygraph;var h=f.setName;var i=f.strokeWidth;var a=d.getOption("strokeBorderWidth",h);var j=d.getOption("drawPointCallback",h)||Dygraph.Circles.DEFAULT;var k=d.getOption("strokePattern",h);var c=d.getOption("drawPoints",h);var b=d.getOption("pointSize",h);if(a&&i){DygraphCanvasRenderer._drawStyledLine(f,d.getOption("strokeBorderColor",h),i+2*a,k,c,j,b)}DygraphCanvasRenderer._drawStyledLine(f,f.color,i,k,c,j,b)};DygraphCanvasRenderer._errorPlotter=function(t){var s=t.dygraph;var h=t.setName;var v=s.getOption("errorBars")||s.getOption("customBars");if(!v){return}var l=s.getOption("fillGraph",h);if(l){s.warn("Can't use fillGraph option with error bars")}var n=t.drawingContext;var o=t.color;var p=s.getOption("fillAlpha",h);var j=s.getOption("stepPlot");var b=t.axis;var q=t.points;var r=Dygraph.createIterator(q,0,q.length,DygraphCanvasRenderer._getIteratorPredicate(s.getOption("connectSeparatedPoints")));var k;var i=NaN;var d=NaN;var f=[-1,-1];var u=b.yscale;var a=new RGBColorParser(o);var w="rgba("+a.r+","+a.g+","+a.b+","+p+")";n.fillStyle=w;n.beginPath();var c=function(e){return(e===null||e===undefined||isNaN(e))};while(r.hasNext){var m=r.next();if((!j&&c(m.y))||(j&&!isNaN(d)&&c(d))){i=NaN;continue}if(j){k=[m.y_bottom,m.y_top];d=m.y}else{k=[m.y_bottom,m.y_top]}k[0]=t.plotArea.h*k[0]+t.plotArea.y;k[1]=t.plotArea.h*k[1]+t.plotArea.y;if(!isNaN(i)){if(j){n.moveTo(i,f[0]);n.lineTo(m.canvasx,f[0]);n.lineTo(m.canvasx,f[1])}else{n.moveTo(i,f[0]);n.lineTo(m.canvasx,k[0]);n.lineTo(m.canvasx,k[1])}n.lineTo(i,f[1]);n.closePath()}f=k;i=m.canvasx}n.fill()};DygraphCanvasRenderer._fillPlotter=function(D){if(D.seriesIndex!==0){return}var B=D.dygraph;var G=B.getLabels().slice(1);for(var A=G.length;A>=0;A--){if(!B.visibility()[A]){G.splice(A,1)}}var h=(function(){for(var e=0;e<G.length;e++){if(B.getOption("fillGraph",G[e])){return true}}return false})();if(!h){return}var u=D.drawingContext;var C=D.plotArea;var c=D.allSeriesPoints;var x=c.length;var w=B.getOption("fillAlpha");var o=B.getOption("stepPlot");var j=B.getOption("stackedGraph");var p=B.getColors();var q={};var a;for(var s=x-1;s>=0;s--){var m=G[s];if(!B.getOption("fillGraph",m)){continue}var v=p[s];var f=B.axisPropertiesForSeries(m);var d=1+f.minyval*f.yscale;if(d<0){d=0}else{if(d>1){d=1}}d=C.h*d+C.y;var z=c[s];var y=Dygraph.createIterator(z,0,z.length,DygraphCanvasRenderer._getIteratorPredicate(B.getOption("connectSeparatedPoints")));var l=NaN;var k=[-1,-1];var r;var E=f.yscale;var b=new RGBColorParser(v);var F="rgba("+b.r+","+b.g+","+b.b+","+w+")";u.fillStyle=F;u.beginPath();while(y.hasNext){var t=y.next();if(!Dygraph.isOK(t.y)){l=NaN;continue}if(j){a=q[t.canvasx];var n;if(a===undefined){n=d}else{if(o){n=a[0]}else{n=a}}r=[t.canvasy,n];if(o){if(k[0]===-1){q[t.canvasx]=[t.canvasy,d]}else{q[t.canvasx]=[t.canvasy,k[0]]}}else{q[t.canvasx]=t.canvasy}}else{r=[t.canvasy,d]}if(!isNaN(l)){u.moveTo(l,k[0]);if(o){u.lineTo(t.canvasx,k[0]);if(a){u.lineTo(t.canvasx,a[1])}else{u.lineTo(t.canvasx,r[1])}}else{u.lineTo(t.canvasx,r[0]);u.lineTo(t.canvasx,r[1])}u.lineTo(l,k[1]);u.closePath()}k=r;l=t.canvasx}u.fill()}};"use strict";var Dygraph=function(d,c,b,a){if(a!==undefined){this.warn("Using deprecated four-argument dygraph constructor");this.__old_init__(d,c,b,a)}else{this.__init__(d,c,b)}};Dygraph.NAME="Dygraph";Dygraph.VERSION="1.2";Dygraph.__repr__=function(){return"["+this.NAME+" "+this.VERSION+"]"};Dygraph.toString=function(){return this.__repr__()};Dygraph.DEFAULT_ROLL_PERIOD=1;Dygraph.DEFAULT_WIDTH=480;Dygraph.DEFAULT_HEIGHT=320;Dygraph.ANIMATION_STEPS=12;Dygraph.ANIMATION_DURATION=200;Dygraph.numberValueFormatter=function(a,e,h,d){var b=e("sigFigs");if(b!==null){return Dygraph.floatFormat(a,b)}var f=e("digitsAfterDecimal");var c=e("maxNumberWidth");if(a!==0&&(Math.abs(a)>=Math.pow(10,c)||Math.abs(a)<Math.pow(10,-f))){return a.toExponential(f)}else{return""+Dygraph.round_(a,f)}};Dygraph.numberAxisLabelFormatter=function(a,d,c,b){return Dygraph.numberValueFormatter(a,c,b)};Dygraph.dateString_=function(e){var i=Dygraph.zeropad;var h=new Date(e);var f=""+h.getFullYear();var g=i(h.getMonth()+1);var a=i(h.getDate());var c="";var b=h.getHours()*3600+h.getMinutes()*60+h.getSeconds();if(b){c=" "+Dygraph.hmsString_(e)}return f+"/"+g+"/"+a+c};Dygraph.dateAxisFormatter=function(b,c){if(c>=Dygraph.DECADAL){return b.strftime("%Y")}else{if(c>=Dygraph.MONTHLY){return b.strftime("%b %y")}else{var a=b.getHours()*3600+b.getMinutes()*60+b.getSeconds()+b.getMilliseconds();if(a===0||c>=Dygraph.DAILY){return new Date(b.getTime()+3600*1000).strftime("%d%b")}else{return Dygraph.hmsString_(b.getTime())}}}};Dygraph.Plotters=DygraphCanvasRenderer._Plotters;Dygraph.DEFAULT_ATTRS={highlightCircleSize:3,highlightSeriesOpts:null,highlightSeriesBackgroundAlpha:0.5,labelsDivWidth:250,labelsDivStyles:{},labelsSeparateLines:false,labelsShowZeroValues:true,labelsKMB:false,labelsKMG2:false,showLabelsOnHighlight:true,digitsAfterDecimal:2,maxNumberWidth:6,sigFigs:null,strokeWidth:1,strokeBorderWidth:0,strokeBorderColor:"white",axisTickSize:3,axisLabelFontSize:14,xAxisLabelWidth:50,yAxisLabelWidth:50,rightGap:5,showRoller:false,xValueParser:Dygraph.dateParser,delimiter:",",sigma:2,errorBars:false,fractions:false,wilsonInterval:true,customBars:false,fillGraph:false,fillAlpha:0.15,connectSeparatedPoints:false,stackedGraph:false,hideOverlayOnMouseOut:true,legend:"onmouseover",stepPlot:false,avoidMinZero:false,drawAxesAtZero:false,titleHeight:28,xLabelHeight:18,yLabelWidth:18,drawXAxis:true,drawYAxis:true,axisLineColor:"black",axisLineWidth:0.3,gridLineWidth:0.3,axisLabelColor:"black",axisLabelFont:"Arial",axisLabelWidth:50,drawYGrid:true,drawXGrid:true,gridLineColor:"rgb(128,128,128)",interactionModel:null,animatedZooms:false,showRangeSelector:false,rangeSelectorHeight:40,rangeSelectorPlotStrokeColor:"#808FAB",rangeSelectorPlotFillColor:"#A7B1C4",plotter:[Dygraph.Plotters.fillPlotter,Dygraph.Plotters.errorPlotter,Dygraph.Plotters.linePlotter],plugins:[],axes:{x:{pixelsPerLabel:60,axisLabelFormatter:Dygraph.dateAxisFormatter,valueFormatter:Dygraph.dateString_,ticker:null},y:{pixelsPerLabel:30,valueFormatter:Dygraph.numberValueFormatter,axisLabelFormatter:Dygraph.numberAxisLabelFormatter,ticker:null},y2:{pixelsPerLabel:30,valueFormatter:Dygraph.numberValueFormatter,axisLabelFormatter:Dygraph.numberAxisLabelFormatter,ticker:null}}};Dygraph.HORIZONTAL=1;Dygraph.VERTICAL=2;Dygraph.PLUGINS=[];Dygraph.addedAnnotationCSS=false;Dygraph.prototype.__old_init__=function(f,d,e,b){if(e!==null){var a=["Date"];for(var c=0;c<e.length;c++){a.push(e[c])}Dygraph.update(b,{labels:a})}this.__init__(f,d,b)};Dygraph.prototype.__init__=function(a,c,l){if(/MSIE/.test(navigator.userAgent)&&!window.opera&&typeof(G_vmlCanvasManager)!="undefined"&&document.readyState!="complete"){var o=this;setTimeout(function(){o.__init__(a,c,l)},100);return}if(l===null||l===undefined){l={}}l=Dygraph.mapLegacyOptions_(l);if(typeof(a)=="string"){a=document.getElementById(a)}if(!a){Dygraph.error("Constructing dygraph with a non-existent div!");return}this.isUsingExcanvas_=typeof(G_vmlCanvasManager)!="undefined";this.maindiv_=a;this.file_=c;this.rollPeriod_=l.rollPeriod||Dygraph.DEFAULT_ROLL_PERIOD;this.previousVerticalX_=-1;this.fractions_=l.fractions||false;this.dateWindow_=l.dateWindow||null;this.is_initial_draw_=true;this.annotations_=[];this.zoomed_x_=false;this.zoomed_y_=false;a.innerHTML="";if(a.style.width===""&&l.width){a.style.width=l.width+"px"}if(a.style.height===""&&l.height){a.style.height=l.height+"px"}if(a.style.height===""&&a.clientHeight===0){a.style.height=Dygraph.DEFAULT_HEIGHT+"px";if(a.style.width===""){a.style.width=Dygraph.DEFAULT_WIDTH+"px"}}this.width_=a.clientWidth;this.height_=a.clientHeight;if(l.stackedGraph){l.fillGraph=true}if(l.showRangeSelector&&l.animatedZooms){this.warn("You should not set animatedZooms=true when using the range selector.");l.animatedZooms=false}this.user_attrs_={};Dygraph.update(this.user_attrs_,l);this.attrs_={};Dygraph.updateDeep(this.attrs_,Dygraph.DEFAULT_ATTRS);this.boundaryIds_=[];this.setIndexByName_={};this.datasetIndex_=[];this.registeredEvents_=[];this.eventListeners_={};this.attributes_=new DygraphOptions(this);this.createInterface_();this.plugins_=[];var d=Dygraph.PLUGINS.concat(this.getOption("plugins"));for(var g=0;g<d.length;g++){var k=d[g];var f=new k();var j={plugin:f,events:{},options:{},pluginOptions:{}};var b=f.activate(this);for(var h in b){j.events[h]=b[h]}this.plugins_.push(j)}for(var g=0;g<this.plugins_.length;g++){var n=this.plugins_[g];for(var h in n.events){if(!n.events.hasOwnProperty(h)){continue}var m=n.events[h];var e=[n.plugin,m];if(!(h in this.eventListeners_)){this.eventListeners_[h]=[e]}else{this.eventListeners_[h].push(e)}}}this.start_()};Dygraph.prototype.cascadeEvents_=function(c,b){if(!(c in this.eventListeners_)){return true}var g={dygraph:this,cancelable:false,defaultPrevented:false,preventDefault:function(){if(!g.cancelable){throw"Cannot call preventDefault on non-cancelable event."}g.defaultPrevented=true},propagationStopped:false,stopPropagation:function(){g.propagationStopped=true}};Dygraph.update(g,b);var a=this.eventListeners_[c];if(a){for(var d=a.length-1;d>=0;d--){var f=a[d][0];var h=a[d][1];h.call(f,g);if(g.propagationStopped){break}}}return g.defaultPrevented};Dygraph.prototype.isZoomed=function(a){if(a===null||a===undefined){return this.zoomed_x_||this.zoomed_y_}if(a==="x"){return this.zoomed_x_}if(a==="y"){return this.zoomed_y_}throw"axis parameter is ["+a+"] must be null, 'x' or 'y'."};Dygraph.prototype.toString=function(){var a=this.maindiv_;var b=(a&&a.id)?a.id:a;return"[Dygraph "+b+"]"};Dygraph.prototype.attr_=function(b,a){return a?this.attributes_.getForSeries(b,a):this.attributes_.get(b)};Dygraph.prototype.getOption=function(a,b){return this.attr_(a,b)};Dygraph.prototype.getOptionForAxis=function(a,b){return this.attributes_.getForAxis(a,b)};Dygraph.prototype.optionsViewForAxis_=function(b){var a=this;return function(c){var d=a.user_attrs_.axes;if(d&&d[b]&&d[b][c]){return d[b][c]}if(typeof(a.user_attrs_[c])!="undefined"){return a.user_attrs_[c]}d=a.attrs_.axes;if(d&&d[b]&&d[b][c]){return d[b][c]}if(b=="y"&&a.axes_[0].hasOwnProperty(c)){return a.axes_[0][c]}else{if(b=="y2"&&a.axes_[1].hasOwnProperty(c)){return a.axes_[1][c]}}return a.attr_(c)}};Dygraph.prototype.rollPeriod=function(){return this.rollPeriod_};Dygraph.prototype.xAxisRange=function(){return this.dateWindow_?this.dateWindow_:this.xAxisExtremes()};Dygraph.prototype.xAxisExtremes=function(){var b=this.rawData_[0][0];var a=this.rawData_[this.rawData_.length-1][0];return[b,a]};Dygraph.prototype.yAxisRange=function(a){if(typeof(a)=="undefined"){a=0}if(a<0||a>=this.axes_.length){return null}var b=this.axes_[a];return[b.computedValueRange[0],b.computedValueRange[1]]};Dygraph.prototype.yAxisRanges=function(){var a=[];for(var b=0;b<this.axes_.length;b++){a.push(this.yAxisRange(b))}return a};Dygraph.prototype.toDomCoords=function(a,c,b){return[this.toDomXCoord(a),this.toDomYCoord(c,b)]};Dygraph.prototype.toDomXCoord=function(b){if(b===null){return null}var c=this.plotter_.area;var a=this.xAxisRange();return c.x+(b-a[0])/(a[1]-a[0])*c.w};Dygraph.prototype.toDomYCoord=function(d,a){var c=this.toPercentYCoord(d,a);if(c===null){return null}var b=this.plotter_.area;return b.y+c*b.h};Dygraph.prototype.toDataCoords=function(a,c,b){return[this.toDataXCoord(a),this.toDataYCoord(c,b)]};Dygraph.prototype.toDataXCoord=function(b){if(b===null){return null}var c=this.plotter_.area;var a=this.xAxisRange();return a[0]+(b-c.x)/c.w*(a[1]-a[0])};Dygraph.prototype.toDataYCoord=function(h,b){if(h===null){return null}var c=this.plotter_.area;var g=this.yAxisRange(b);if(typeof(b)=="undefined"){b=0}if(!this.axes_[b].logscale){return g[0]+(c.y+c.h-h)/c.h*(g[1]-g[0])}else{var f=(h-c.y)/c.h;var a=Dygraph.log10(g[1]);var e=a-(f*(a-Dygraph.log10(g[0])));var d=Math.pow(Dygraph.LOG_SCALE,e);return d}};Dygraph.prototype.toPercentYCoord=function(f,c){if(f===null){return null}if(typeof(c)=="undefined"){c=0}var e=this.yAxisRange(c);var d;var b=this.attributes_.getForAxis("logscale",c);if(!b){d=(e[1]-f)/(e[1]-e[0])}else{var a=Dygraph.log10(e[1]);d=(a-Dygraph.log10(f))/(a-Dygraph.log10(e[0]))}return d};Dygraph.prototype.toPercentXCoord=function(b){if(b===null){return null}var a=this.xAxisRange();return(b-a[0])/(a[1]-a[0])};Dygraph.prototype.numColumns=function(){return this.rawData_[0]?this.rawData_[0].length:this.attr_("labels").length};Dygraph.prototype.numRows=function(){return this.rawData_.length};Dygraph.prototype.fullXRange_=function(){if(this.numRows()>0){return[this.rawData_[0][0],this.rawData_[this.numRows()-1][0]]}else{return[0,1]}};Dygraph.prototype.getValue=function(b,a){if(b<0||b>this.rawData_.length){return null}if(a<0||a>this.rawData_[b].length){return null}return this.rawData_[b][a]};Dygraph.prototype.createInterface_=function(){var a=this.maindiv_;this.graphDiv=document.createElement("div");this.graphDiv.style.width=this.width_+"px";this.graphDiv.style.height=this.height_+"px";a.appendChild(this.graphDiv);this.canvas_=Dygraph.createCanvas();this.canvas_.style.position="absolute";this.canvas_.width=this.width_;this.canvas_.height=this.height_;this.canvas_.style.width=this.width_+"px";this.canvas_.style.height=this.height_+"px";this.canvas_ctx_=Dygraph.getContext(this.canvas_);this.hidden_=this.createPlotKitCanvas_(this.canvas_);this.hidden_ctx_=Dygraph.getContext(this.hidden_);if(this.attr_("showRangeSelector")){this.rangeSelector_=new DygraphRangeSelector(this)}this.graphDiv.appendChild(this.hidden_);this.graphDiv.appendChild(this.canvas_);this.mouseEventElement_=this.createMouseEventElement_();this.layout_=new DygraphLayout(this);if(this.rangeSelector_){this.rangeSelector_.addToGraph(this.graphDiv,this.layout_)}var b=this;this.mouseMoveHandler=function(c){b.mouseMove_(c)};this.addEvent(this.mouseEventElement_,"mousemove",this.mouseMoveHandler);this.mouseOutHandler=function(c){b.mouseOut_(c)};this.addEvent(this.mouseEventElement_,"mouseout",this.mouseOutHandler);this.createDragInterface_();this.resizeHandler=function(c){b.resize()};this.addEvent(window,"resize",this.resizeHandler)};Dygraph.prototype.destroy=function(){var b=function(e){while(e.hasChildNodes()){b(e.firstChild);e.removeChild(e.firstChild)}};for(var a=0;a<this.registeredEvents_.length;a++){var d=this.registeredEvents_[a];Dygraph.removeEvent(d.elem,d.type,d.fn)}this.registeredEvents_=[];Dygraph.removeEvent(this.mouseEventElement_,"mouseout",this.mouseOutHandler);Dygraph.removeEvent(this.mouseEventElement_,"mousemove",this.mouseMoveHandler);Dygraph.removeEvent(this.mouseEventElement_,"mousemove",this.mouseUpHandler_);b(this.maindiv_);var c=function(e){for(var f in e){if(typeof(e[f])==="object"){e[f]=null}}};Dygraph.removeEvent(window,"resize",this.resizeHandler);this.resizeHandler=null;c(this.layout_);c(this.plotter_);c(this)};Dygraph.prototype.createPlotKitCanvas_=function(a){var b=Dygraph.createCanvas();b.style.position="absolute";b.style.top=a.style.top;b.style.left=a.style.left;b.width=this.width_;b.height=this.height_;b.style.width=this.width_+"px";b.style.height=this.height_+"px";return b};Dygraph.prototype.createMouseEventElement_=function(){if(this.isUsingExcanvas_){var a=document.createElement("div");a.style.position="absolute";a.style.backgroundColor="white";a.style.filter="alpha(opacity=0)";a.style.width=this.width_+"px";a.style.height=this.height_+"px";this.graphDiv.appendChild(a);return a}else{return this.canvas_}};Dygraph.prototype.setColors_=function(){var g=this.getLabels();var e=g.length-1;this.colors_=[];this.colorsMap_={};var a=this.attr_("colors");var d;if(!a){var c=this.attr_("colorSaturation")||1;var b=this.attr_("colorValue")||0.5;var k=Math.ceil(e/2);for(d=1;d<=e;d++){if(!this.visibility()[d-1]){continue}var h=d%2?Math.ceil(d/2):(k+d/2);var f=(1*h/(1+e));var j=Dygraph.hsvToRGB(f,c,b);this.colors_.push(j);this.colorsMap_[g[d]]=j}}else{for(d=0;d<e;d++){if(!this.visibility()[d]){continue}var j=a[d%a.length];this.colors_.push(j);this.colorsMap_[g[1+d]]=j}}};Dygraph.prototype.getColors=function(){return this.colors_};Dygraph.prototype.getPropertiesForSeries=function(c){var a=-1;var d=this.getLabels();for(var b=1;b<d.length;b++){if(d[b]==c){a=b;break}}if(a==-1){return null}return{name:c,column:a,visible:this.visibility()[a-1],color:this.colorsMap_[c],axis:1+this.attributes_.axisForSeries(c)}};Dygraph.prototype.createRollInterface_=function(){if(!this.roller_){this.roller_=document.createElement("input");this.roller_.type="text";this.roller_.style.display="none";this.graphDiv.appendChild(this.roller_)}var e=this.attr_("showRoller")?"block":"none";var d=this.plotter_.area;var b={position:"absolute",zIndex:10,top:(d.y+d.h-25)+"px",left:(d.x+1)+"px",display:e};this.roller_.size="2";this.roller_.value=this.rollPeriod_;for(var a in b){if(b.hasOwnProperty(a)){this.roller_.style[a]=b[a]}}var c=this;this.roller_.onchange=function(){c.adjustRoll(c.roller_.value)}};Dygraph.prototype.dragGetX_=function(b,a){return Dygraph.pageX(b)-a.px};Dygraph.prototype.dragGetY_=function(b,a){return Dygraph.pageY(b)-a.py};Dygraph.prototype.createDragInterface_=function(){var c={isZooming:false,isPanning:false,is2DPan:false,dragStartX:null,dragStartY:null,dragEndX:null,dragEndY:null,dragDirection:null,prevEndX:null,prevEndY:null,prevDragDirection:null,cancelNextDblclick:false,initialLeftmostDate:null,xUnitsPerPixel:null,dateRange:null,px:0,py:0,boundedDates:null,boundedValues:null,tarp:new Dygraph.IFrameTarp(),initializeMouseDown:function(i,h,f){if(i.preventDefault){i.preventDefault()}else{i.returnValue=false;i.cancelBubble=true}f.px=Dygraph.findPosX(h.canvas_);f.py=Dygraph.findPosY(h.canvas_);f.dragStartX=h.dragGetX_(i,f);f.dragStartY=h.dragGetY_(i,f);f.cancelNextDblclick=false;f.tarp.cover()}};var e=this.attr_("interactionModel");var b=this;var d=function(f){return function(g){f(g,b,c)}};for(var a in e){if(!e.hasOwnProperty(a)){continue}this.addEvent(this.mouseEventElement_,a,d(e[a]))}this.mouseUpHandler_=function(g){if(c.isZooming||c.isPanning){c.isZooming=false;c.dragStartX=null;c.dragStartY=null}if(c.isPanning){c.isPanning=false;c.draggingDate=null;c.dateRange=null;for(var f=0;f<b.axes_.length;f++){delete b.axes_[f].draggingValue;delete b.axes_[f].dragValueRange}}c.tarp.uncover()};this.addEvent(document,"mouseup",this.mouseUpHandler_)};Dygraph.prototype.drawZoomRect_=function(e,c,i,b,g,a,f,d){var h=this.canvas_ctx_;if(a==Dygraph.HORIZONTAL){h.clearRect(Math.min(c,f),this.layout_.getPlotArea().y,Math.abs(c-f),this.layout_.getPlotArea().h)}else{if(a==Dygraph.VERTICAL){h.clearRect(this.layout_.getPlotArea().x,Math.min(b,d),this.layout_.getPlotArea().w,Math.abs(b-d))}}if(e==Dygraph.HORIZONTAL){if(i&&c){h.fillStyle="rgba(128,128,128,0.33)";h.fillRect(Math.min(c,i),this.layout_.getPlotArea().y,Math.abs(i-c),this.layout_.getPlotArea().h)}}else{if(e==Dygraph.VERTICAL){if(g&&b){h.fillStyle="rgba(128,128,128,0.33)";h.fillRect(this.layout_.getPlotArea().x,Math.min(b,g),this.layout_.getPlotArea().w,Math.abs(g-b))}}}if(this.isUsingExcanvas_){this.currentZoomRectArgs_=[e,c,i,b,g,0,0,0]}};Dygraph.prototype.clearZoomRect_=function(){this.currentZoomRectArgs_=null;this.canvas_ctx_.clearRect(0,0,this.canvas_.width,this.canvas_.height)};Dygraph.prototype.doZoomX_=function(c,a){this.currentZoomRectArgs_=null;var b=this.toDataXCoord(c);var d=this.toDataXCoord(a);this.doZoomXDates_(b,d)};Dygraph.zoomAnimationFunction=function(c,b){var a=1.5;return(1-Math.pow(a,-c))/(1-Math.pow(a,-b))};Dygraph.prototype.doZoomXDates_=function(c,e){var a=this.xAxisRange();var d=[c,e];this.zoomed_x_=true;var b=this;this.doAnimatedZoom(a,d,null,null,function(){if(b.attr_("zoomCallback")){b.attr_("zoomCallback")(c,e,b.yAxisRanges())}})};Dygraph.prototype.doZoomY_=function(h,f){this.currentZoomRectArgs_=null;var c=this.yAxisRanges();var b=[];for(var e=0;e<this.axes_.length;e++){var d=this.toDataYCoord(h,e);var a=this.toDataYCoord(f,e);b.push([a,d])}this.zoomed_y_=true;var g=this;this.doAnimatedZoom(null,null,c,b,function(){if(g.attr_("zoomCallback")){var i=g.xAxisRange();g.attr_("zoomCallback")(i[0],i[1],g.yAxisRanges())}})};Dygraph.prototype.resetZoom=function(){var c=false,d=false,a=false;if(this.dateWindow_!==null){c=true;d=true}for(var g=0;g<this.axes_.length;g++){if(typeof(this.axes_[g].valueWindow)!=="undefined"&&this.axes_[g].valueWindow!==null){c=true;a=true}}this.clearSelection();if(c){this.zoomed_x_=false;this.zoomed_y_=false;var f=this.rawData_[0][0];var b=this.rawData_[this.rawData_.length-1][0];if(!this.attr_("animatedZooms")){this.dateWindow_=null;for(g=0;g<this.axes_.length;g++){if(this.axes_[g].valueWindow!==null){delete this.axes_[g].valueWindow}}this.drawGraph_();if(this.attr_("zoomCallback")){this.attr_("zoomCallback")(f,b,this.yAxisRanges())}return}var l=null,m=null,k=null,h=null;if(d){l=this.xAxisRange();m=[f,b]}if(a){k=this.yAxisRanges();var n=this.gatherDatasets_(this.rolledSeries_,null);var o=n[1];this.computeYAxisRanges_(o);h=[];for(g=0;g<this.axes_.length;g++){var e=this.axes_[g];h.push((e.valueRange!==null&&e.valueRange!==undefined)?e.valueRange:e.extremeRange)}}var j=this;this.doAnimatedZoom(l,m,k,h,function(){j.dateWindow_=null;for(var p=0;p<j.axes_.length;p++){if(j.axes_[p].valueWindow!==null){delete j.axes_[p].valueWindow}}if(j.attr_("zoomCallback")){j.attr_("zoomCallback")(f,b,j.yAxisRanges())}})}};Dygraph.prototype.doAnimatedZoom=function(a,e,b,c,m){var i=this.attr_("animatedZooms")?Dygraph.ANIMATION_STEPS:1;var l=[];var k=[];var f,d;if(a!==null&&e!==null){for(f=1;f<=i;f++){d=Dygraph.zoomAnimationFunction(f,i);l[f-1]=[a[0]*(1-d)+d*e[0],a[1]*(1-d)+d*e[1]]}}if(b!==null&&c!==null){for(f=1;f<=i;f++){d=Dygraph.zoomAnimationFunction(f,i);var n=[];for(var g=0;g<this.axes_.length;g++){n.push([b[g][0]*(1-d)+d*c[g][0],b[g][1]*(1-d)+d*c[g][1]])}k[f-1]=n}}var h=this;Dygraph.repeatAndCleanup(function(p){if(k.length){for(var o=0;o<h.axes_.length;o++){var j=k[p][o];h.axes_[o].valueWindow=[j[0],j[1]]}}if(l.length){h.dateWindow_=l[p]}h.drawGraph_()},i,Dygraph.ANIMATION_DURATION/i,m)};Dygraph.prototype.getArea=function(){return this.plotter_.area};Dygraph.prototype.eventToDomCoords=function(c){var b=Dygraph.pageX(c)-Dygraph.findPosX(this.mouseEventElement_);var a=Dygraph.pageY(c)-Dygraph.findPosY(this.mouseEventElement_);return[b,a]};Dygraph.prototype.findClosestRow=function(b){var k=Infinity;var d=-1,a=-1;var g=this.layout_.points;for(var e=0;e<g.length;e++){var m=g[e];var f=m.length;for(var c=0;c<f;c++){var l=m[c];if(!Dygraph.isValidPoint(l,true)){continue}var h=Math.abs(l.canvasx-b);if(h<k){k=h;a=e;d=c}}}return this.idxToRow_(a,d)};Dygraph.prototype.findClosestPoint=function(f,e){var j=Infinity;var k=-1;var h,o,n,l,d,c;for(var b=this.layout_.datasets.length-1;b>=0;--b){var m=this.layout_.points[b];for(var g=0;g<m.length;++g){var l=m[g];if(!Dygraph.isValidPoint(l)){continue}o=l.canvasx-f;n=l.canvasy-e;h=o*o+n*n;if(h<j){j=h;d=l;c=b;k=g}}}var a=this.layout_.setNames[c];return{row:k+this.getLeftBoundary_(),seriesName:a,point:d}};Dygraph.prototype.findStackedPoint=function(i,h){var q=this.findClosestRow(i);var g=this.getLeftBoundary_();var e=q-g;var j=this.layout_.points;var f,d;for(var c=0;c<this.layout_.datasets.length;++c){var m=this.layout_.points[c];if(e>=m.length){continue}var n=m[e];if(!Dygraph.isValidPoint(n)){continue}var k=n.canvasy;if(i>n.canvasx&&e+1<m.length){var l=m[e+1];if(Dygraph.isValidPoint(l)){var p=l.canvasx-n.canvasx;if(p>0){var a=(i-n.canvasx)/p;k+=a*(l.canvasy-n.canvasy)}}}else{if(i<n.canvasx&&e>0){var o=m[e-1];if(Dygraph.isValidPoint(o)){var p=n.canvasx-o.canvasx;if(p>0){var a=(n.canvasx-i)/p;k+=a*(o.canvasy-n.canvasy)}}}}if(c===0||k<h){f=n;d=c}}var b=this.layout_.setNames[d];return{row:q,seriesName:b,point:f}};Dygraph.prototype.mouseMove_=function(b){var h=this.layout_.points;if(h===undefined||h===null){return}var e=this.eventToDomCoords(b);var a=e[0];var j=e[1];var f=this.attr_("highlightSeriesOpts");var d=false;if(f&&!this.isSeriesLocked()){var c;if(this.attr_("stackedGraph")){c=this.findStackedPoint(a,j)}else{c=this.findClosestPoint(a,j)}d=this.setSelection(c.row,c.seriesName)}else{var g=this.findClosestRow(a);d=this.setSelection(g)}var i=this.attr_("highlightCallback");if(i&&d){i(b,this.lastx_,this.selPoints_,this.lastRow_,this.highlightSet_)}};Dygraph.prototype.getLeftBoundary_=function(){for(var a=0;a<this.boundaryIds_.length;a++){if(this.boundaryIds_[a]!==undefined){return this.boundaryIds_[a][0]}}return 0};Dygraph.prototype.idxToRow_=function(b,a){if(a<0){return -1}var c=this.getLeftBoundary_();return c+a};Dygraph.prototype.animateSelection_=function(f){var e=10;var c=30;if(this.fadeLevel===undefined){this.fadeLevel=0}if(this.animateId===undefined){this.animateId=0}var g=this.fadeLevel;var b=f<0?g:e-g;if(b<=0){if(this.fadeLevel){this.updateSelection_(1)}return}var a=++this.animateId;var d=this;Dygraph.repeatAndCleanup(function(h){if(d.animateId!=a){return}d.fadeLevel+=f;if(d.fadeLevel===0){d.clearSelection()}else{d.updateSelection_(d.fadeLevel/e)}},b,c,function(){})};Dygraph.prototype.updateSelection_=function(d){var l=this.cascadeEvents_("select",{selectedX:this.lastx_,selectedPoints:this.selPoints_});var h;var o=this.canvas_ctx_;if(this.attr_("highlightSeriesOpts")){o.clearRect(0,0,this.width_,this.height_);var f=1-this.attr_("highlightSeriesBackgroundAlpha");if(f){var g=true;if(g){if(d===undefined){this.animateSelection_(1);return}f*=d}o.fillStyle="rgba(255,255,255,"+f+")";o.fillRect(0,0,this.width_,this.height_)}this.plotter_._renderLineChart(this.highlightSet_,o)}else{if(this.previousVerticalX_>=0){var j=0;var k=this.attr_("labels");for(h=1;h<k.length;h++){var c=this.attr_("highlightCircleSize",k[h]);if(c>j){j=c}}var m=this.previousVerticalX_;o.clearRect(m-j-1,0,2*j+2,this.height_)}}if(this.isUsingExcanvas_&&this.currentZoomRectArgs_){Dygraph.prototype.drawZoomRect_.apply(this,this.currentZoomRectArgs_)}if(this.selPoints_.length>0){var b=this.selPoints_[0].canvasx;o.save();for(h=0;h<this.selPoints_.length;h++){var p=this.selPoints_[h];if(!Dygraph.isOK(p.canvasy)){continue}var a=this.attr_("highlightCircleSize",p.name);var n=this.attr_("drawHighlightPointCallback",p.name);var e=this.plotter_.colors[p.name];if(!n){n=Dygraph.Circles.DEFAULT}o.lineWidth=this.attr_("strokeWidth",p.name);o.strokeStyle=e;o.fillStyle=e;n(this.g,p.name,o,b,p.canvasy,e,a)}o.restore();this.previousVerticalX_=b}};Dygraph.prototype.setSelection=function(d,g,f){this.selPoints_=[];if(d!==false){d-=this.getLeftBoundary_()}var c=false;if(d!==false&&d>=0){if(d!=this.lastRow_){c=true}this.lastRow_=d;for(var b=0;b<this.layout_.datasets.length;++b){var e=this.layout_.datasets[b];if(d<e.length){var a=this.layout_.points[b][d];if(this.attr_("stackedGraph")){a=this.layout_.unstackPointAtIndex(b,d)}if(a.yval!==null){this.selPoints_.push(a)}}}}else{if(this.lastRow_>=0){c=true}this.lastRow_=-1}if(this.selPoints_.length){this.lastx_=this.selPoints_[0].xval}else{this.lastx_=-1}if(g!==undefined){if(this.highlightSet_!==g){c=true}this.highlightSet_=g}if(f!==undefined){this.lockedSet_=f}if(c){this.updateSelection_(undefined)}return c};Dygraph.prototype.mouseOut_=function(a){if(this.attr_("unhighlightCallback")){this.attr_("unhighlightCallback")(a)}if(this.attr_("hideOverlayOnMouseOut")&&!this.lockedSet_){this.clearSelection()}};Dygraph.prototype.clearSelection=function(){this.cascadeEvents_("deselect",{});this.lockedSet_=false;if(this.fadeLevel){this.animateSelection_(-1);return}this.canvas_ctx_.clearRect(0,0,this.width_,this.height_);this.fadeLevel=0;this.selPoints_=[];this.lastx_=-1;this.lastRow_=-1;this.highlightSet_=null};Dygraph.prototype.getSelection=function(){if(!this.selPoints_||this.selPoints_.length<1){return -1}for(var c=0;c<this.layout_.points.length;c++){var a=this.layout_.points[c];for(var b=0;b<a.length;b++){if(a[b].x==this.selPoints_[0].x){return b+this.getLeftBoundary_()}}}return -1};Dygraph.prototype.getHighlightSeries=function(){return this.highlightSet_};Dygraph.prototype.isSeriesLocked=function(){return this.lockedSet_};Dygraph.prototype.loadedEvent_=function(a){this.rawData_=this.parseCSV_(a);this.predraw_()};Dygraph.prototype.addXTicks_=function(){var a;if(this.dateWindow_){a=[this.dateWindow_[0],this.dateWindow_[1]]}else{a=this.fullXRange_()}var c=this.optionsViewForAxis_("x");var b=c("ticker")(a[0],a[1],this.width_,c,this);this.layout_.setXTicks(b)};Dygraph.prototype.extremeValues_=function(d){var h=null,f=null,c,g;var b=this.attr_("errorBars")||this.attr_("customBars");if(b){for(c=0;c<d.length;c++){g=d[c][1][0];if(g===null||isNaN(g)){continue}var a=g-d[c][1][1];var e=g+d[c][1][2];if(a>g){a=g}if(e<g){e=g}if(f===null||e>f){f=e}if(h===null||a<h){h=a}}}else{for(c=0;c<d.length;c++){g=d[c][1];if(g===null||isNaN(g)){continue}if(f===null||g>f){f=g}if(h===null||g<h){h=g}}}return[h,f]};Dygraph.prototype.predraw_=function(){var e=new Date();this.computeYAxes_();if(this.plotter_){this.cascadeEvents_("clearChart");this.plotter_.clear()}this.plotter_=new DygraphCanvasRenderer(this,this.hidden_,this.hidden_ctx_,this.layout_);this.createRollInterface_();this.cascadeEvents_("predraw");if(this.rangeSelector_){this.rangeSelector_.renderStaticLayer()}this.rolledSeries_=[null];for(var c=1;c<this.numColumns();c++){var d=this.attr_("logscale");var b=this.extractSeries_(this.rawData_,c,d);b=this.rollingAverage(b,this.rollPeriod_);this.rolledSeries_.push(b)}this.drawGraph_();var a=new Date();this.drawingTimeMs_=(a-e)};Dygraph.prototype.gatherDatasets_=function(w,c){var s=[];var b=[];var e=[];var a={};var u,t,r;var m=w.length-1;for(u=m;u>=1;u--){if(!this.visibility()[u-1]){continue}var h=[];for(t=0;t<w[u].length;t++){h.push(w[u][t])}var o=this.attr_("errorBars")||this.attr_("customBars");if(c){var A=c[0];var f=c[1];var p=[];var d=null,z=null;for(r=0;r<h.length;r++){if(h[r][0]>=A&&d===null){d=r}if(h[r][0]<=f){z=r}}if(d===null){d=0}if(d>0){d--}if(z===null){z=h.length-1}if(z<h.length-1){z++}s[u-1]=[d,z];for(r=d;r<=z;r++){p.push(h[r])}h=p}else{s[u-1]=[0,h.length-1]}var n=this.extremeValues_(h);if(o){for(t=0;t<h.length;t++){h[t]=[h[t][0],h[t][1][0],h[t][1][1],h[t][1][2]]}}else{if(this.attr_("stackedGraph")){var q=h.length;var y;for(t=0;t<q;t++){var g=h[t][0];if(b[g]===undefined){b[g]=0}y=h[t][1];if(y===null){h[t]=[g,null];continue}b[g]+=y;h[t]=[g,b[g]];if(b[g]>n[1]){n[1]=b[g]}if(b[g]<n[0]){n[0]=b[g]}}}}var v=this.attr_("labels")[u];a[v]=n;e[u]=h}if(this.attr_("stackedGraph")){for(r=e.length-1;r>=0;--r){if(!e[r]){continue}for(t=0;t<e[r].length;t++){var g=e[r][t][0];if(isNaN(b[g])){for(u=e.length-1;u>=0;u--){if(!e[u]){continue}e[u][t][1]=NaN}}}break}}return[e,a,s]};Dygraph.prototype.drawGraph_=function(){var a=new Date();var e=this.is_initial_draw_;this.is_initial_draw_=false;this.layout_.removeAllDatasets();this.setColors_();this.attrs_.pointSize=0.5*this.attr_("highlightCircleSize");var j=this.gatherDatasets_(this.rolledSeries_,this.dateWindow_);var d=j[0];var k=j[1];this.boundaryIds_=j[2];this.setIndexByName_={};var h=this.attr_("labels");if(h.length>0){this.setIndexByName_[h[0]]=0}var f=0;for(var g=1;g<d.length;g++){this.setIndexByName_[h[g]]=g;if(!this.visibility()[g-1]){continue}this.layout_.addDataset(h[g],d[g]);this.datasetIndex_[g]=f++}this.computeYAxisRanges_(k);this.layout_.setYAxes(this.axes_);this.addXTicks_();var b=this.zoomed_x_;this.layout_.setDateWindow(this.dateWindow_);this.zoomed_x_=b;this.layout_.evaluateWithError();this.renderGraph_(e);if(this.attr_("timingName")){var c=new Date();if(console){console.log(this.attr_("timingName")+" - drawGraph: "+(c-a)+"ms")}}};Dygraph.prototype.renderGraph_=function(a){this.cascadeEvents_("clearChart");this.plotter_.clear();if(this.attr_("underlayCallback")){this.attr_("underlayCallback")(this.hidden_ctx_,this.layout_.getPlotArea(),this,this)}var b={canvas:this.hidden_,drawingContext:this.hidden_ctx_};this.cascadeEvents_("willDrawChart",b);this.plotter_.render();this.cascadeEvents_("didDrawChart",b);this.canvas_.getContext("2d").clearRect(0,0,this.canvas_.width,this.canvas_.height);if(this.rangeSelector_){this.rangeSelector_.renderInteractiveLayer()}if(this.attr_("drawCallback")!==null){this.attr_("drawCallback")(this,a)}};Dygraph.prototype.computeYAxes_=function(){var e,c,a,f,d,g,b;if(this.axes_!==undefined&&this.user_attrs_.hasOwnProperty("valueRange")===false){c=[];for(d=0;d<this.axes_.length;d++){c.push(this.axes_[d].valueWindow)}}this.axes_=[];for(f=0;f<this.attributes_.numAxes();f++){g={g:this};Dygraph.update(g,this.attributes_.axisOptions(f));this.axes_[f]=g}b=this.attr_("valueRange");if(b){this.axes_[0].valueRange=b}if(c!==undefined){for(d=0;d<c.length;d++){this.axes_[d].valueWindow=c[d]}}for(f=0;f<this.axes_.length;f++){if(f===0){g=this.optionsViewForAxis_("y"+(f?"2":""));b=g("valueRange");if(b){this.axes_[f].valueRange=b}}else{var h=this.user_attrs_.axes;if(h&&h.y2){b=h.y2.valueRange;if(b){this.axes_[f].valueRange=b}}}}};Dygraph.prototype.numAxes=function(){return this.attributes_.numAxes()};Dygraph.prototype.axisPropertiesForSeries=function(a){return this.axes_[this.attributes_.axisForSeries(a)]};Dygraph.prototype.computeYAxisRanges_=function(a){var g;var l=this.attributes_.numAxes();for(var t=0;t<l;t++){var b=this.axes_[t];var w=this.attributes_.getForAxis("logscale",t);var z=this.attributes_.getForAxis("includeZero",t);g=this.attributes_.seriesForAxis(t);if(g.length==0){b.extremeRange=[0,1]}else{var x=Infinity;var v=-Infinity;var o,m;for(var r=0;r<g.length;r++){if(!a.hasOwnProperty(g[r])){continue}o=a[g[r]][0];if(o!==null){x=Math.min(o,x)}m=a[g[r]][1];if(m!==null){v=Math.max(m,v)}}if(z&&x>0){x=0}if(x==Infinity){x=0}if(v==-Infinity){v=1}var s=v-x;if(s===0){s=v}var d,A;if(w){d=v+0.1*s;A=x}else{d=v+0.1*s;A=x-0.1*s;if(!this.attr_("avoidMinZero")){if(A<0&&x>=0){A=0}if(d>0&&v<=0){d=0}}if(this.attr_("includeZero")){if(v<0){d=0}if(x>0){A=0}}}b.extremeRange=[A,d]}if(b.valueWindow){b.computedValueRange=[b.valueWindow[0],b.valueWindow[1]]}else{if(b.valueRange){b.computedValueRange=[b.valueRange[0],b.valueRange[1]]}else{b.computedValueRange=b.extremeRange}}var n=this.optionsViewForAxis_("y"+(t?"2":""));var y=n("ticker");if(t===0||b.independentTicks){b.ticks=y(b.computedValueRange[0],b.computedValueRange[1],this.height_,n,this)}else{var h=this.axes_[0];var e=h.ticks;var f=h.computedValueRange[1]-h.computedValueRange[0];var B=b.computedValueRange[1]-b.computedValueRange[0];var c=[];for(var q=0;q<e.length;q++){var p=(e[q].v-h.computedValueRange[0])/f;var u=b.computedValueRange[0]+p*B;c.push(u)}b.ticks=y(b.computedValueRange[0],b.computedValueRange[1],this.height_,n,this,c)}}};Dygraph.prototype.extractSeries_=function(g,e,f){var d=[];for(var c=0;c<g.length;c++){var b=g[c][0];var a=g[c][e];if(f){if(a<=0){a=null}}d.push([b,a])}return d};Dygraph.prototype.rollingAverage=function(l,d){if(l.length<2){return l}d=Math.min(d,l.length);var b=[];var s=this.attr_("sigma");var E,o,w,v,m,c,D,x;if(this.fractions_){var k=0;var h=0;var e=100;for(w=0;w<l.length;w++){k+=l[w][1][0];h+=l[w][1][1];if(w-d>=0){k-=l[w-d][1][0];h-=l[w-d][1][1]}var A=l[w][0];var u=h?k/h:0;if(this.attr_("errorBars")){if(this.attr_("wilsonInterval")){if(h){var r=u<0?0:u,t=h;var z=s*Math.sqrt(r*(1-r)/t+s*s/(4*t*t));var a=1+s*s/h;E=(r+s*s/(2*h)-z)/a;o=(r+s*s/(2*h)+z)/a;b[w]=[A,[r*e,(r-E)*e,(o-r)*e]]}else{b[w]=[A,[0,0,0]]}}else{x=h?s*Math.sqrt(u*(1-u)/h):1;b[w]=[A,[e*u,e*x,e*x]]}}else{b[w]=[A,e*u]}}}else{if(this.attr_("customBars")){E=0;var B=0;o=0;var g=0;for(w=0;w<l.length;w++){var C=l[w][1];m=C[1];b[w]=[l[w][0],[m,m-C[0],C[2]-m]];if(m!==null&&!isNaN(m)){E+=C[0];B+=m;o+=C[2];g+=1}if(w-d>=0){var q=l[w-d];if(q[1][1]!==null&&!isNaN(q[1][1])){E-=q[1][0];B-=q[1][1];o-=q[1][2];g-=1}}if(g){b[w]=[l[w][0],[1*B/g,1*(B-E)/g,1*(o-B)/g]]}else{b[w]=[l[w][0],[null,null,null]]}}}else{if(!this.attr_("errorBars")){if(d==1){return l}for(w=0;w<l.length;w++){c=0;D=0;for(v=Math.max(0,w-d+1);v<w+1;v++){m=l[v][1];if(m===null||isNaN(m)){continue}D++;c+=l[v][1]}if(D){b[w]=[l[w][0],c/D]}else{b[w]=[l[w][0],null]}}}else{for(w=0;w<l.length;w++){c=0;var f=0;D=0;for(v=Math.max(0,w-d+1);v<w+1;v++){m=l[v][1][0];if(m===null||isNaN(m)){continue}D++;c+=l[v][1][0];f+=Math.pow(l[v][1][1],2)}if(D){x=Math.sqrt(f)/D;b[w]=[l[w][0],[c/D,s*x,s*x]]}else{b[w]=[l[w][0],[null,null,null]]}}}}}return b};Dygraph.prototype.detectTypeFromString_=function(b){var a=false;var c=b.indexOf("-");if((c>0&&(b[c-1]!="e"&&b[c-1]!="E"))||b.indexOf("/")>=0||isNaN(parseFloat(b))){a=true}else{if(b.length==8&&b>"19700101"&&b<"20371231"){a=true}}this.setXAxisOptions_(a)};Dygraph.prototype.setXAxisOptions_=function(a){if(a){this.attrs_.xValueParser=Dygraph.dateParser;this.attrs_.axes.x.valueFormatter=Dygraph.dateString_;this.attrs_.axes.x.ticker=Dygraph.dateTicker;this.attrs_.axes.x.axisLabelFormatter=Dygraph.dateAxisFormatter}else{this.attrs_.xValueParser=function(b){return parseFloat(b)};this.attrs_.axes.x.valueFormatter=function(b){return b};this.attrs_.axes.x.ticker=Dygraph.numericLinearTicks;this.attrs_.axes.x.axisLabelFormatter=this.attrs_.axes.x.valueFormatter}};Dygraph.prototype.parseFloat_=function(a,c,b){var e=parseFloat(a);if(!isNaN(e)){return e}if(/^ *$/.test(a)){return null}if(/^ *nan *$/i.test(a)){return NaN}var d="Unable to parse '"+a+"' as a number";if(b!==null&&c!==null){d+=" on line "+(1+c)+" ('"+b+"') of CSV."}this.error(d);return null};Dygraph.prototype.parseCSV_=function(t){var r=[];var s=Dygraph.detectLineDelimiter(t);var a=t.split(s||"\n");var g,k;var p=this.attr_("delimiter");if(a[0].indexOf(p)==-1&&a[0].indexOf("\t")>=0){p="\t"}var b=0;if(!("labels" in this.user_attrs_)){b=1;this.attrs_.labels=a[0].split(p);this.attributes_.reparseSeries()}var o=0;var m;var q=false;var c=this.attr_("labels").length;var f=false;for(var l=b;l<a.length;l++){var e=a[l];o=l;if(e.length===0){continue}if(e[0]=="#"){continue}var d=e.split(p);if(d.length<2){continue}var h=[];if(!q){this.detectTypeFromString_(d[0]);m=this.attr_("xValueParser");q=true}h[0]=m(d[0],this);if(this.fractions_){for(k=1;k<d.length;k++){g=d[k].split("/");if(g.length!=2){this.error('Expected fractional "num/den" values in CSV data but found a value \''+d[k]+"' on line "+(1+l)+" ('"+e+"') which is not of this form.");h[k]=[0,0]}else{h[k]=[this.parseFloat_(g[0],l,e),this.parseFloat_(g[1],l,e)]}}}else{if(this.attr_("errorBars")){if(d.length%2!=1){this.error("Expected alternating (value, stdev.) pairs in CSV data but line "+(1+l)+" has an odd number of values ("+(d.length-1)+"): '"+e+"'")}for(k=1;k<d.length;k+=2){h[(k+1)/2]=[this.parseFloat_(d[k],l,e),this.parseFloat_(d[k+1],l,e)]}}else{if(this.attr_("customBars")){for(k=1;k<d.length;k++){var u=d[k];if(/^ *$/.test(u)){h[k]=[null,null,null]}else{g=u.split(";");if(g.length==3){h[k]=[this.parseFloat_(g[0],l,e),this.parseFloat_(g[1],l,e),this.parseFloat_(g[2],l,e)]}else{this.warn('When using customBars, values must be either blank or "low;center;high" tuples (got "'+u+'" on line '+(1+l))}}}}else{for(k=1;k<d.length;k++){h[k]=this.parseFloat_(d[k],l,e)}}}}if(r.length>0&&h[0]<r[r.length-1][0]){f=true}if(h.length!=c){this.error("Number of columns in line "+l+" ("+h.length+") does not agree with number of labels ("+c+") "+e)}if(l===0&&this.attr_("labels")){var n=true;for(k=0;n&&k<h.length;k++){if(h[k]){n=false}}if(n){this.warn("The dygraphs 'labels' option is set, but the first row of CSV data ('"+e+"') appears to also contain labels. Will drop the CSV labels and use the option labels.");continue}}r.push(h)}if(f){this.warn("CSV is out of order; order it correctly to speed loading.");r.sort(function(j,i){return j[0]-i[0]})}return r};Dygraph.prototype.parseArray_=function(c){if(c.length===0){this.error("Can't plot empty data set");return null}if(c[0].length===0){this.error("Data set cannot contain an empty row");return null}var a;if(this.attr_("labels")===null){this.warn("Using default labels. Set labels explicitly via 'labels' in the options parameter");this.attrs_.labels=["X"];for(a=1;a<c[0].length;a++){this.attrs_.labels.push("Y"+a)}this.attributes_.reparseSeries()}else{var b=this.attr_("labels");if(b.length!=c[0].length){this.error("Mismatch between number of labels ("+b+") and number of columns in array ("+c[0].length+")");return null}}if(Dygraph.isDateLike(c[0][0])){this.attrs_.axes.x.valueFormatter=Dygraph.dateString_;this.attrs_.axes.x.ticker=Dygraph.dateTicker;this.attrs_.axes.x.axisLabelFormatter=Dygraph.dateAxisFormatter;var d=Dygraph.clone(c);for(a=0;a<c.length;a++){if(d[a].length===0){this.error("Row "+(1+a)+" of data is empty");return null}if(d[a][0]===null||typeof(d[a][0].getTime)!="function"||isNaN(d[a][0].getTime())){this.error("x value in row "+(1+a)+" is not a Date");return null}d[a][0]=d[a][0].getTime()}return d}else{this.attrs_.axes.x.valueFormatter=function(e){return e};this.attrs_.axes.x.ticker=Dygraph.numericLinearTicks;this.attrs_.axes.x.axisLabelFormatter=Dygraph.numberAxisLabelFormatter;return c}};Dygraph.prototype.parseDataTable_=function(w){var d=function(i){var j=String.fromCharCode(65+i%26);i=Math.floor(i/26);while(i>0){j=String.fromCharCode(65+(i-1)%26)+j.toLowerCase();i=Math.floor((i-1)/26)}return j};var h=w.getNumberOfColumns();var g=w.getNumberOfRows();var f=w.getColumnType(0);if(f=="date"||f=="datetime"){this.attrs_.xValueParser=Dygraph.dateParser;this.attrs_.axes.x.valueFormatter=Dygraph.dateString_;this.attrs_.axes.x.ticker=Dygraph.dateTicker;this.attrs_.axes.x.axisLabelFormatter=Dygraph.dateAxisFormatter}else{if(f=="number"){this.attrs_.xValueParser=function(i){return parseFloat(i)};this.attrs_.axes.x.valueFormatter=function(i){return i};this.attrs_.axes.x.ticker=Dygraph.numericLinearTicks;this.attrs_.axes.x.axisLabelFormatter=this.attrs_.axes.x.valueFormatter}else{this.error("only 'date', 'datetime' and 'number' types are supported for column 1 of DataTable input (Got '"+f+"')");return null}}var m=[];var t={};var s=false;var q,o;for(q=1;q<h;q++){var b=w.getColumnType(q);if(b=="number"){m.push(q)}else{if(b=="string"&&this.attr_("displayAnnotations")){var r=m[m.length-1];if(!t.hasOwnProperty(r)){t[r]=[q]}else{t[r].push(q)}s=true}else{this.error("Only 'number' is supported as a dependent type with Gviz. 'string' is only supported if displayAnnotations is true")}}}var u=[w.getColumnLabel(0)];for(q=0;q<m.length;q++){u.push(w.getColumnLabel(m[q]));if(this.attr_("errorBars")){q+=1}}this.attrs_.labels=u;h=u.length;var v=[];var l=false;var a=[];for(q=0;q<g;q++){var e=[];if(typeof(w.getValue(q,0))==="undefined"||w.getValue(q,0)===null){this.warn("Ignoring row "+q+" of DataTable because of undefined or null first column.");continue}if(f=="date"||f=="datetime"){e.push(w.getValue(q,0).getTime())}else{e.push(w.getValue(q,0))}if(!this.attr_("errorBars")){for(o=0;o<m.length;o++){var c=m[o];e.push(w.getValue(q,c));if(s&&t.hasOwnProperty(c)&&w.getValue(q,t[c][0])!==null){var p={};p.series=w.getColumnLabel(c);p.xval=e[0];p.shortText=d(a.length);p.text="";for(var n=0;n<t[c].length;n++){if(n){p.text+="\n"}p.text+=w.getValue(q,t[c][n])}a.push(p)}}for(o=0;o<e.length;o++){if(!isFinite(e[o])){e[o]=null}}}else{for(o=0;o<h-1;o++){e.push([w.getValue(q,1+2*o),w.getValue(q,2+2*o)])}}if(v.length>0&&e[0]<v[v.length-1][0]){l=true}v.push(e)}if(l){this.warn("DataTable is out of order; order it correctly to speed loading.");v.sort(function(j,i){return j[0]-i[0]})}this.rawData_=v;if(a.length>0){this.setAnnotations(a,true)}this.attributes_.reparseSeries()};Dygraph.prototype.start_=function(){var d=this.file_;if(typeof d=="function"){d=d()}if(Dygraph.isArrayLike(d)){this.rawData_=this.parseArray_(d);this.predraw_()}else{if(typeof d=="object"&&typeof d.getColumnRange=="function"){this.parseDataTable_(d);this.predraw_()}else{if(typeof d=="string"){var c=Dygraph.detectLineDelimiter(d);if(c){this.loadedEvent_(d)}else{var b=new XMLHttpRequest();var a=this;b.onreadystatechange=function(){if(b.readyState==4){if(b.status===200||b.status===0){a.loadedEvent_(b.responseText)}}};b.open("GET",d,true);b.send(null)}}else{this.error("Unknown data format: "+(typeof d))}}}};Dygraph.prototype.updateOptions=function(e,b){if(typeof(b)=="undefined"){b=false}var d=e.file;var c=Dygraph.mapLegacyOptions_(e);if("rollPeriod" in c){this.rollPeriod_=c.rollPeriod}if("dateWindow" in c){this.dateWindow_=c.dateWindow;if(!("isZoomedIgnoreProgrammaticZoom" in c)){this.zoomed_x_=(c.dateWindow!==null)}}if("valueRange" in c&&!("isZoomedIgnoreProgrammaticZoom" in c)){this.zoomed_y_=(c.valueRange!==null)}var a=Dygraph.isPixelChangingOptionList(this.attr_("labels"),c);Dygraph.updateDeep(this.user_attrs_,c);this.attributes_.reparseSeries();if(d){this.file_=d;if(!b){this.start_()}}else{if(!b){if(a){this.predraw_()}else{this.renderGraph_(false)}}}};Dygraph.mapLegacyOptions_=function(c){var a={};for(var b in c){if(b=="file"){continue}if(c.hasOwnProperty(b)){a[b]=c[b]}}var e=function(g,f,h){if(!a.axes){a.axes={}}if(!a.axes[g]){a.axes[g]={}}a.axes[g][f]=h};var d=function(f,g,h){if(typeof(c[f])!="undefined"){Dygraph.warn("Option "+f+" is deprecated. Use the "+h+" option for the "+g+" axis instead. (e.g. { axes : { "+g+" : { "+h+" : ... } } } (see http://dygraphs.com/per-axis.html for more information.");e(g,h,c[f]);delete a[f]}};d("xValueFormatter","x","valueFormatter");d("pixelsPerXLabel","x","pixelsPerLabel");d("xAxisLabelFormatter","x","axisLabelFormatter");d("xTicker","x","ticker");d("yValueFormatter","y","valueFormatter");d("pixelsPerYLabel","y","pixelsPerLabel");d("yAxisLabelFormatter","y","axisLabelFormatter");d("yTicker","y","ticker");return a};Dygraph.prototype.resize=function(d,b){if(this.resize_lock){return}this.resize_lock=true;if((d===null)!=(b===null)){this.warn("Dygraph.resize() should be called with zero parameters or two non-NULL parameters. Pretending it was zero.");d=b=null}var a=this.width_;var c=this.height_;if(d){this.maindiv_.style.width=d+"px";this.maindiv_.style.height=b+"px";this.width_=d;this.height_=b}else{this.width_=this.maindiv_.clientWidth;this.height_=this.maindiv_.clientHeight}if(a!=this.width_||c!=this.height_){this.maindiv_.innerHTML="";this.roller_=null;this.attrs_.labelsDiv=null;this.createInterface_();if(this.annotations_.length){this.layout_.setAnnotations(this.annotations_)}this.predraw_()}this.resize_lock=false};Dygraph.prototype.adjustRoll=function(a){this.rollPeriod_=a;this.predraw_()};Dygraph.prototype.visibility=function(){if(!this.attr_("visibility")){this.attrs_.visibility=[]}while(this.attr_("visibility").length<this.numColumns()-1){this.attrs_.visibility.push(true)}return this.attr_("visibility")};Dygraph.prototype.setVisibility=function(b,c){var a=this.visibility();if(b<0||b>=a.length){this.warn("invalid series number in setVisibility: "+b)}else{a[b]=c;this.predraw_()}};Dygraph.prototype.size=function(){return{width:this.width_,height:this.height_}};Dygraph.prototype.setAnnotations=function(b,a){Dygraph.addAnnotationRule();this.annotations_=b;this.layout_.setAnnotations(this.annotations_);if(!a){this.predraw_()}};Dygraph.prototype.annotations=function(){return this.annotations_};Dygraph.prototype.getLabels=function(){return this.attr_("labels").slice()};Dygraph.prototype.indexFromSetName=function(a){return this.setIndexByName_[a]};Dygraph.prototype.datasetIndexFromSetName_=function(a){return this.datasetIndex_[this.indexFromSetName(a)]};Dygraph.addAnnotationRule=function(){if(Dygraph.addedAnnotationCSS){return}var f="border: 1px solid black; background-color: white; text-align: center;";var e=document.createElement("style");e.type="text/css";document.getElementsByTagName("head")[0].appendChild(e);for(var b=0;b<document.styleSheets.length;b++){if(document.styleSheets[b].disabled){continue}var d=document.styleSheets[b];try{if(d.insertRule){var a=d.cssRules?d.cssRules.length:0;d.insertRule(".dygraphDefaultAnnotation { "+f+" }",a)}else{if(d.addRule){d.addRule(".dygraphDefaultAnnotation",f)}}Dygraph.addedAnnotationCSS=true;return}catch(c){}}this.warn("Unable to add default annotation CSS rule; display may be off.")};var DateGraph=Dygraph;"use strict";Dygraph.LOG_SCALE=10;Dygraph.LN_TEN=Math.log(Dygraph.LOG_SCALE);Dygraph.log10=function(a){return Math.log(a)/Dygraph.LN_TEN};Dygraph.DEBUG=1;Dygraph.INFO=2;Dygraph.WARNING=3;Dygraph.ERROR=3;Dygraph.LOG_STACK_TRACES=false;Dygraph.DOTTED_LINE=[2,2];Dygraph.DASHED_LINE=[7,3];Dygraph.DOT_DASH_LINE=[7,2,2,2];Dygraph.log=function(b,d){var a;if(typeof(printStackTrace)!="undefined"){try{a=printStackTrace({guess:false});while(a[0].indexOf("stacktrace")!=-1){a.splice(0,1)}a.splice(0,2);for(var c=0;c<a.length;c++){a[c]=a[c].replace(/\([^)]*\/(.*)\)/,"@$1").replace(/\@.*\/([^\/]*)/,"@$1").replace("[object Object].","")}var g=a.splice(0,1)[0];d+=" ("+g.replace(/^.*@ ?/,"")+")"}catch(f){}}if(typeof(window.console)!="undefined"){switch(b){case Dygraph.DEBUG:window.console.debug("dygraphs: "+d);break;case Dygraph.INFO:window.console.info("dygraphs: "+d);break;case Dygraph.WARNING:window.console.warn("dygraphs: "+d);break;case Dygraph.ERROR:window.console.error("dygraphs: "+d);break}}if(Dygraph.LOG_STACK_TRACES){window.console.log(a.join("\n"))}};Dygraph.info=function(a){Dygraph.log(Dygraph.INFO,a)};Dygraph.prototype.info=Dygraph.info;Dygraph.warn=function(a){Dygraph.log(Dygraph.WARNING,a)};Dygraph.prototype.warn=Dygraph.warn;Dygraph.error=function(a){Dygraph.log(Dygraph.ERROR,a)};Dygraph.prototype.error=Dygraph.error;Dygraph.getContext=function(a){return(a.getContext("2d"))};Dygraph.addEvent=function addEvent(c,b,a){if(c.addEventListener){c.addEventListener(b,a,false)}else{c[b+a]=function(){a(window.event)};c.attachEvent("on"+b,c[b+a])}};Dygraph.prototype.addEvent=function addEvent(c,b,a){Dygraph.addEvent(c,b,a);this.registeredEvents_.push({elem:c,type:b,fn:a})};Dygraph.removeEvent=function addEvent(c,b,a){if(c.removeEventListener){c.removeEventListener(b,a,false)}else{try{c.detachEvent("on"+b,c[b+a])}catch(d){}c[b+a]=null}};Dygraph.cancelEvent=function(a){a=a?a:window.event;if(a.stopPropagation){a.stopPropagation()}if(a.preventDefault){a.preventDefault()}a.cancelBubble=true;a.cancel=true;a.returnValue=false;return false};Dygraph.hsvToRGB=function(h,g,k){var c;var d;var l;if(g===0){c=k;d=k;l=k}else{var e=Math.floor(h*6);var j=(h*6)-e;var b=k*(1-g);var a=k*(1-(g*j));var m=k*(1-(g*(1-j)));switch(e){case 1:c=a;d=k;l=b;break;case 2:c=b;d=k;l=m;break;case 3:c=b;d=a;l=k;break;case 4:c=m;d=b;l=k;break;case 5:c=k;d=b;l=a;break;case 6:case 0:c=k;d=m;l=b;break}}c=Math.floor(255*c+0.5);d=Math.floor(255*d+0.5);l=Math.floor(255*l+0.5);return"rgb("+c+","+d+","+l+")"};Dygraph.findPosX=function(b){var c=0;if(b.offsetParent){var a=b;while(1){c+=a.offsetLeft;if(!a.offsetParent){break}a=a.offsetParent}}else{if(b.x){c+=b.x}}while(b&&b!=document.body){c-=b.scrollLeft;b=b.parentNode}return c};Dygraph.findPosY=function(c){var b=0;if(c.offsetParent){var a=c;while(1){b+=a.offsetTop;if(!a.offsetParent){break}a=a.offsetParent}}else{if(c.y){b+=c.y}}while(c&&c!=document.body){b-=c.scrollTop;c=c.parentNode}return b};Dygraph.pageX=function(c){if(c.pageX){return(!c.pageX||c.pageX<0)?0:c.pageX}else{var d=document.documentElement;var a=document.body;return c.clientX+(d.scrollLeft||a.scrollLeft)-(d.clientLeft||0)}};Dygraph.pageY=function(c){if(c.pageY){return(!c.pageY||c.pageY<0)?0:c.pageY}else{var d=document.documentElement;var a=document.body;return c.clientY+(d.scrollTop||a.scrollTop)-(d.clientTop||0)}};Dygraph.isOK=function(a){return !!a&&!isNaN(a)};Dygraph.isValidPoint=function(b,a){if(!b){return false}if(b.yval===null){return false}if(b.x===null||b.x===undefined){return false}if(b.y===null||b.y===undefined){return false}if(isNaN(b.x)||(!a&&isNaN(b.y))){return false}return true};Dygraph.floatFormat=function(a,b){var c=Math.min(Math.max(1,b||2),21);return(Math.abs(a)<0.001&&a!==0)?a.toExponential(c-1):a.toPrecision(c)};Dygraph.zeropad=function(a){if(a<10){return"0"+a}else{return""+a}};Dygraph.hmsString_=function(a){var c=Dygraph.zeropad;var b=new Date(a);if(b.getSeconds()){return c(b.getHours())+":"+c(b.getMinutes())+":"+c(b.getSeconds())}else{return c(b.getHours())+":"+c(b.getMinutes())}};Dygraph.round_=function(c,b){var a=Math.pow(10,b);return Math.round(c*a)/a};Dygraph.binarySearch=function(a,d,i,e,b){if(e===null||e===undefined||b===null||b===undefined){e=0;b=d.length-1}if(e>b){return -1}if(i===null||i===undefined){i=0}var h=function(j){return j>=0&&j<d.length};var g=parseInt((e+b)/2,10);var c=d[g];var f;if(c==a){return g}else{if(c>a){if(i>0){f=g-1;if(h(f)&&d[f]<a){return g}}return Dygraph.binarySearch(a,d,i,e,g-1)}else{if(c<a){if(i<0){f=g+1;if(h(f)&&d[f]>a){return g}}return Dygraph.binarySearch(a,d,i,g+1,b)}}}return -1};Dygraph.dateParser=function(a){var b;var c;if(a.search("-")==-1||a.search("T")!=-1||a.search("Z")!=-1){c=Dygraph.dateStrToMillis(a);if(c&&!isNaN(c)){return c}}if(a.search("-")!=-1){b=a.replace("-","/","g");while(b.search("-")!=-1){b=b.replace("-","/")}c=Dygraph.dateStrToMillis(b)}else{if(a.length==8){b=a.substr(0,4)+"/"+a.substr(4,2)+"/"+a.substr(6,2);c=Dygraph.dateStrToMillis(b)}else{c=Dygraph.dateStrToMillis(a)}}if(!c||isNaN(c)){Dygraph.error("Couldn't parse "+a+" as a date")}return c};Dygraph.dateStrToMillis=function(a){return new Date(a).getTime()};Dygraph.update=function(b,c){if(typeof(c)!="undefined"&&c!==null){for(var a in c){if(c.hasOwnProperty(a)){b[a]=c[a]}}}return b};Dygraph.updateDeep=function(b,d){function c(e){return(typeof Node==="object"?e instanceof Node:typeof e==="object"&&typeof e.nodeType==="number"&&typeof e.nodeName==="string")}if(typeof(d)!="undefined"&&d!==null){for(var a in d){if(d.hasOwnProperty(a)){if(d[a]===null){b[a]=null}else{if(Dygraph.isArrayLike(d[a])){b[a]=d[a].slice()}else{if(c(d[a])){b[a]=d[a]}else{if(typeof(d[a])=="object"){if(typeof(b[a])!="object"||b[a]===null){b[a]={}}Dygraph.updateDeep(b[a],d[a])}else{b[a]=d[a]}}}}}}}return b};Dygraph.isArrayLike=function(b){var a=typeof(b);if((a!="object"&&!(a=="function"&&typeof(b.item)=="function"))||b===null||typeof(b.length)!="number"||b.nodeType===3){return false}return true};Dygraph.isDateLike=function(a){if(typeof(a)!="object"||a===null||typeof(a.getTime)!="function"){return false}return true};Dygraph.clone=function(c){var b=[];for(var a=0;a<c.length;a++){if(Dygraph.isArrayLike(c[a])){b.push(Dygraph.clone(c[a]))}else{b.push(c[a])}}return b};Dygraph.createCanvas=function(){var a=document.createElement("canvas");var b=(/MSIE/.test(navigator.userAgent)&&!window.opera);if(b&&(typeof(G_vmlCanvasManager)!="undefined")){a=G_vmlCanvasManager.initElement((a))}return a};Dygraph.isAndroid=function(){return(/Android/).test(navigator.userAgent)};Dygraph.Iterator=function(d,c,b,a){c=c||0;b=b||d.length;this.hasNext=true;this.peek=null;this.start_=c;this.array_=d;this.predicate_=a;this.end_=Math.min(d.length,c+b);this.nextIdx_=c-1;this.next()};Dygraph.Iterator.prototype.next=function(){if(!this.hasNext){return null}var c=this.peek;var b=this.nextIdx_+1;var a=false;while(b<this.end_){if(!this.predicate_||this.predicate_(this.array_,b)){this.peek=this.array_[b];a=true;break}b++}this.nextIdx_=b;if(!a){this.hasNext=false;this.peek=null}return c};Dygraph.createIterator=function(d,c,b,a){return new Dygraph.Iterator(d,c,b,a)};Dygraph.requestAnimFrame=(function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1000/60)}})();Dygraph.repeatAndCleanup=function(h,g,f,a){var i=0;var d;var b=new Date().getTime();h(i);if(g==1){a();return}var e=g-1;(function c(){if(i>=g){return}Dygraph.requestAnimFrame.call(window,function(){var l=new Date().getTime();var j=l-b;d=i;i=Math.floor(j/f);var k=i-d;var m=(i+k)>e;if(m||(i>=e)){h(e);a()}else{if(k!=0){h(i)}c()}})})()};Dygraph.isPixelChangingOptionList=function(h,e){var d={annotationClickHandler:true,annotationDblClickHandler:true,annotationMouseOutHandler:true,annotationMouseOverHandler:true,axisLabelColor:true,axisLineColor:true,axisLineWidth:true,clickCallback:true,digitsAfterDecimal:true,drawCallback:true,drawHighlightPointCallback:true,drawPoints:true,drawPointCallback:true,drawXGrid:true,drawYGrid:true,fillAlpha:true,gridLineColor:true,gridLineWidth:true,hideOverlayOnMouseOut:true,highlightCallback:true,highlightCircleSize:true,interactionModel:true,isZoomedIgnoreProgrammaticZoom:true,labelsDiv:true,labelsDivStyles:true,labelsDivWidth:true,labelsKMB:true,labelsKMG2:true,labelsSeparateLines:true,labelsShowZeroValues:true,legend:true,maxNumberWidth:true,panEdgeFraction:true,pixelsPerYLabel:true,pointClickCallback:true,pointSize:true,rangeSelectorPlotFillColor:true,rangeSelectorPlotStrokeColor:true,showLabelsOnHighlight:true,showRoller:true,sigFigs:true,strokeWidth:true,underlayCallback:true,unhighlightCallback:true,xAxisLabelFormatter:true,xTicker:true,xValueFormatter:true,yAxisLabelFormatter:true,yValueFormatter:true,zoomCallback:true};var a=false;var b={};if(h){for(var f=1;f<h.length;f++){b[h[f]]=true}}for(var g in e){if(a){break}if(e.hasOwnProperty(g)){if(b[g]){for(var c in e[g]){if(a){break}if(e[g].hasOwnProperty(c)&&!d[c]){a=true}}}else{if(!d[g]){a=true}}}}return a};Dygraph.compareArrays=function(c,b){if(!Dygraph.isArrayLike(c)||!Dygraph.isArrayLike(b)){return false}if(c.length!==b.length){return false}for(var a=0;a<c.length;a++){if(c[a]!==b[a]){return false}}return true};Dygraph.regularShape_=function(p,c,j,f,e,a,o){a=a||0;o=o||Math.PI*2/c;p.beginPath();var h=true;var g=a;var d=g;var i=function(){var q=f+(Math.sin(d)*j);var r=e+(-Math.cos(d)*j);return[q,r]};var b=i();var m=b[0];var k=b[1];p.moveTo(m,k);for(var n=0;n<c;n++){d=(n==c-1)?g:(d+o);var l=i();p.lineTo(l[0],l[1])}p.fill();p.stroke()};Dygraph.shapeFunction_=function(b,a,c){return function(j,i,f,e,k,h,d){f.strokeStyle=h;f.fillStyle="white";Dygraph.regularShape_(f,b,d,e,k,a,c)}};Dygraph.Circles={DEFAULT:function(h,f,b,e,d,c,a){b.beginPath();b.fillStyle=c;b.arc(e,d,a,0,2*Math.PI,false);b.fill()},TRIANGLE:Dygraph.shapeFunction_(3),SQUARE:Dygraph.shapeFunction_(4,Math.PI/4),DIAMOND:Dygraph.shapeFunction_(4),PENTAGON:Dygraph.shapeFunction_(5),HEXAGON:Dygraph.shapeFunction_(6),CIRCLE:function(f,e,c,b,h,d,a){c.beginPath();c.strokeStyle=d;c.fillStyle="white";c.arc(b,h,a,0,2*Math.PI,false);c.fill();c.stroke()},STAR:Dygraph.shapeFunction_(5,0,4*Math.PI/5),PLUS:function(f,e,c,b,h,d,a){c.strokeStyle=d;c.beginPath();c.moveTo(b+a,h);c.lineTo(b-a,h);c.closePath();c.stroke();c.beginPath();c.moveTo(b,h+a);c.lineTo(b,h-a);c.closePath();c.stroke()},EX:function(f,e,c,b,h,d,a){c.strokeStyle=d;c.beginPath();c.moveTo(b+a,h+a);c.lineTo(b-a,h-a);c.closePath();c.stroke();c.beginPath();c.moveTo(b+a,h-a);c.lineTo(b-a,h+a);c.closePath();c.stroke()}};Dygraph.IFrameTarp=function(){this.tarps=[]};Dygraph.IFrameTarp.prototype.cover=function(){var f=document.getElementsByTagName("iframe");for(var c=0;c<f.length;c++){var e=f[c];var b=Dygraph.findPosX(e),h=Dygraph.findPosY(e),d=e.offsetWidth,a=e.offsetHeight;var g=document.createElement("div");g.style.position="absolute";g.style.left=b+"px";g.style.top=h+"px";g.style.width=d+"px";g.style.height=a+"px";g.style.zIndex=999;document.body.appendChild(g);this.tarps.push(g)}};Dygraph.IFrameTarp.prototype.uncover=function(){for(var a=0;a<this.tarps.length;a++){this.tarps[a].parentNode.removeChild(this.tarps[a])}this.tarps=[]};Dygraph.detectLineDelimiter=function(c){for(var a=0;a<c.length;a++){var b=c.charAt(a);if(b==="\r"){if(((a+1)<c.length)&&(c.charAt(a+1)==="\n")){return"\r\n"}return b}if(b==="\n"){if(((a+1)<c.length)&&(c.charAt(a+1)==="\r")){return"\n\r"}return b}}return null};"use strict";Dygraph.GVizChart=function(a){this.container=a};Dygraph.GVizChart.prototype.draw=function(b,a){this.container.innerHTML="";if(typeof(this.date_graph)!="undefined"){this.date_graph.destroy()}this.date_graph=new Dygraph(this.container,b,a)};Dygraph.GVizChart.prototype.setSelection=function(b){var a=false;if(b.length){a=b[0].row}this.date_graph.setSelection(a)};Dygraph.GVizChart.prototype.getSelection=function(){var b=[];var d=this.date_graph.getSelection();if(d<0){return b}var a=this.date_graph.layout_.datasets;for(var c=0;c<a.length;++c){b.push({row:d,column:c+1})}return b};"use strict";Dygraph.Interaction={};Dygraph.Interaction.startPan=function(o,t,c){var r,b;c.isPanning=true;var k=t.xAxisRange();c.dateRange=k[1]-k[0];c.initialLeftmostDate=k[0];c.xUnitsPerPixel=c.dateRange/(t.plotter_.area.w-1);if(t.attr_("panEdgeFraction")){var x=t.width_*t.attr_("panEdgeFraction");var d=t.xAxisExtremes();var j=t.toDomXCoord(d[0])-x;var l=t.toDomXCoord(d[1])+x;var u=t.toDataXCoord(j);var w=t.toDataXCoord(l);c.boundedDates=[u,w];var f=[];var a=t.height_*t.attr_("panEdgeFraction");for(r=0;r<t.axes_.length;r++){b=t.axes_[r];var p=b.extremeRange;var q=t.toDomYCoord(p[0],r)+a;var s=t.toDomYCoord(p[1],r)-a;var n=t.toDataYCoord(q);var e=t.toDataYCoord(s);f[r]=[n,e]}c.boundedValues=f}c.is2DPan=false;c.axes=[];for(r=0;r<t.axes_.length;r++){b=t.axes_[r];var h={};var m=t.yAxisRange(r);var v=t.attributes_.getForAxis("logscale",r);if(v){h.initialTopValue=Dygraph.log10(m[1]);h.dragValueRange=Dygraph.log10(m[1])-Dygraph.log10(m[0])}else{h.initialTopValue=m[1];h.dragValueRange=m[1]-m[0]}h.unitsPerPixel=h.dragValueRange/(t.plotter_.area.h-1);c.axes.push(h);if(b.valueWindow||b.valueRange){c.is2DPan=true}}};Dygraph.Interaction.movePan=function(b,k,c){c.dragEndX=k.dragGetX_(b,c);c.dragEndY=k.dragGetY_(b,c);var h=c.initialLeftmostDate-(c.dragEndX-c.dragStartX)*c.xUnitsPerPixel;if(c.boundedDates){h=Math.max(h,c.boundedDates[0])}var a=h+c.dateRange;if(c.boundedDates){if(a>c.boundedDates[1]){h=h-(a-c.boundedDates[1]);a=h+c.dateRange}}k.dateWindow_=[h,a];if(c.is2DPan){for(var j=0;j<k.axes_.length;j++){var e=k.axes_[j];var o=c.axes[j];var d=c.dragEndY-c.dragStartY;var p=d*o.unitsPerPixel;var f=c.boundedValues?c.boundedValues[j]:null;var l=o.initialTopValue+p;if(f){l=Math.min(l,f[1])}var n=l-o.dragValueRange;if(f){if(n<f[0]){l=l-(n-f[0]);n=l-o.dragValueRange}}var m=k.attributes_.getForAxis("logscale",j);if(m){e.valueWindow=[Math.pow(Dygraph.LOG_SCALE,n),Math.pow(Dygraph.LOG_SCALE,l)]}else{e.valueWindow=[n,l]}}}k.drawGraph_(false)};Dygraph.Interaction.endPan=function(c,b,a){a.dragEndX=b.dragGetX_(c,a);a.dragEndY=b.dragGetY_(c,a);var e=Math.abs(a.dragEndX-a.dragStartX);var d=Math.abs(a.dragEndY-a.dragStartY);if(e<2&&d<2&&b.lastx_!==undefined&&b.lastx_!=-1){Dygraph.Interaction.treatMouseOpAsClick(b,c,a)}a.isPanning=false;a.is2DPan=false;a.initialLeftmostDate=null;a.dateRange=null;a.valueRange=null;a.boundedDates=null;a.boundedValues=null;a.axes=null};Dygraph.Interaction.startZoom=function(c,b,a){a.isZooming=true;a.zoomMoved=false};Dygraph.Interaction.moveZoom=function(c,b,a){a.zoomMoved=true;a.dragEndX=b.dragGetX_(c,a);a.dragEndY=b.dragGetY_(c,a);var e=Math.abs(a.dragStartX-a.dragEndX);var d=Math.abs(a.dragStartY-a.dragEndY);a.dragDirection=(e<d/2)?Dygraph.VERTICAL:Dygraph.HORIZONTAL;b.drawZoomRect_(a.dragDirection,a.dragStartX,a.dragEndX,a.dragStartY,a.dragEndY,a.prevDragDirection,a.prevEndX,a.prevEndY);a.prevEndX=a.dragEndX;a.prevEndY=a.dragEndY;a.prevDragDirection=a.dragDirection};Dygraph.Interaction.treatMouseOpAsClick=function(f,b,d){var k=f.attr_("clickCallback");var n=f.attr_("pointClickCallback");var j=null;if(n){var l=-1;var m=Number.MAX_VALUE;for(var e=0;e<f.selPoints_.length;e++){var c=f.selPoints_[e];var a=Math.pow(c.canvasx-d.dragEndX,2)+Math.pow(c.canvasy-d.dragEndY,2);if(!isNaN(a)&&(l==-1||a<m)){m=a;l=e}}var h=f.attr_("highlightCircleSize")+2;if(m<=h*h){j=f.selPoints_[l]}}if(j){n(b,j)}if(k){k(b,f.lastx_,f.selPoints_)}};Dygraph.Interaction.endZoom=function(c,b,a){a.isZooming=false;a.dragEndX=b.dragGetX_(c,a);a.dragEndY=b.dragGetY_(c,a);var e=Math.abs(a.dragEndX-a.dragStartX);var d=Math.abs(a.dragEndY-a.dragStartY);if(e<2&&d<2&&b.lastx_!==undefined&&b.lastx_!=-1){Dygraph.Interaction.treatMouseOpAsClick(b,c,a)}if(e>=10&&a.dragDirection==Dygraph.HORIZONTAL){b.doZoomX_(Math.min(a.dragStartX,a.dragEndX),Math.max(a.dragStartX,a.dragEndX));a.cancelNextDblclick=true}else{if(d>=10&&a.dragDirection==Dygraph.VERTICAL){b.doZoomY_(Math.min(a.dragStartY,a.dragEndY),Math.max(a.dragStartY,a.dragEndY));a.cancelNextDblclick=true}else{if(a.zoomMoved){b.clearZoomRect_()}}}a.dragStartX=null;a.dragStartY=null};Dygraph.Interaction.startTouch=function(f,e,d){f.preventDefault();var h=[];for(var c=0;c<f.touches.length;c++){var b=f.touches[c];h.push({pageX:b.pageX,pageY:b.pageY,dataX:e.toDataXCoord(b.pageX),dataY:e.toDataYCoord(b.pageY)})}d.initialTouches=h;if(h.length==1){d.initialPinchCenter=h[0];d.touchDirections={x:true,y:true}}else{if(h.length==2){d.initialPinchCenter={pageX:0.5*(h[0].pageX+h[1].pageX),pageY:0.5*(h[0].pageY+h[1].pageY),dataX:0.5*(h[0].dataX+h[1].dataX),dataY:0.5*(h[0].dataY+h[1].dataY)};var a=180/Math.PI*Math.atan2(d.initialPinchCenter.pageY-h[0].pageY,h[0].pageX-d.initialPinchCenter.pageX);a=Math.abs(a);if(a>90){a=90-a}d.touchDirections={x:(a<(90-45/2)),y:(a>45/2)}}}d.initialRange={x:e.xAxisRange(),y:e.yAxisRange()}};Dygraph.Interaction.moveTouch=function(n,q,d){var p,l=[];for(p=0;p<n.touches.length;p++){var k=n.touches[p];l.push({pageX:k.pageX,pageY:k.pageY})}var a=d.initialTouches;var h;var j=d.initialPinchCenter;if(l.length==1){h=l[0]}else{h={pageX:0.5*(l[0].pageX+l[1].pageX),pageY:0.5*(l[0].pageY+l[1].pageY)}}var m={pageX:h.pageX-j.pageX,pageY:h.pageY-j.pageY};var f=d.initialRange.x[1]-d.initialRange.x[0];var o=d.initialRange.y[0]-d.initialRange.y[1];m.dataX=(m.pageX/q.plotter_.area.w)*f;m.dataY=(m.pageY/q.plotter_.area.h)*o;var u,c;if(l.length==1){u=1;c=1}else{if(l.length==2){var e=(a[1].pageX-j.pageX);u=(l[1].pageX-h.pageX)/e;var s=(a[1].pageY-j.pageY);c=(l[1].pageY-h.pageY)/s}}u=Math.min(8,Math.max(0.125,u));c=Math.min(8,Math.max(0.125,c));if(d.touchDirections.x){q.dateWindow_=[j.dataX-m.dataX+(d.initialRange.x[0]-j.dataX)/u,j.dataX-m.dataX+(d.initialRange.x[1]-j.dataX)/u]}if(d.touchDirections.y){for(p=0;p<1;p++){var b=q.axes_[p];var r=q.attributes_.getForAxis("logscale",p);if(r){}else{b.valueWindow=[j.dataY-m.dataY+(d.initialRange.y[0]-j.dataY)/c,j.dataY-m.dataY+(d.initialRange.y[1]-j.dataY)/c]}}}q.drawGraph_(false)};Dygraph.Interaction.endTouch=function(c,b,a){if(c.touches.length!==0){Dygraph.Interaction.startTouch(c,b,a)}};Dygraph.Interaction.defaultModel={mousedown:function(c,b,a){if(c.button&&c.button==2){return}a.initializeMouseDown(c,b,a);if(c.altKey||c.shiftKey){Dygraph.startPan(c,b,a)}else{Dygraph.startZoom(c,b,a)}},mousemove:function(c,b,a){if(a.isZooming){Dygraph.moveZoom(c,b,a)}else{if(a.isPanning){Dygraph.movePan(c,b,a)}}},mouseup:function(c,b,a){if(a.isZooming){Dygraph.endZoom(c,b,a)}else{if(a.isPanning){Dygraph.endPan(c,b,a)}}},touchstart:function(c,b,a){Dygraph.Interaction.startTouch(c,b,a)},touchmove:function(c,b,a){Dygraph.Interaction.moveTouch(c,b,a)},touchend:function(c,b,a){Dygraph.Interaction.endTouch(c,b,a)},mouseout:function(c,b,a){if(a.isZooming){a.dragEndX=null;a.dragEndY=null}},dblclick:function(c,b,a){if(a.cancelNextDblclick){a.cancelNextDblclick=false;return}if(c.altKey||c.shiftKey){return}b.resetZoom()}};Dygraph.DEFAULT_ATTRS.interactionModel=Dygraph.Interaction.defaultModel;Dygraph.defaultInteractionModel=Dygraph.Interaction.defaultModel;Dygraph.endZoom=Dygraph.Interaction.endZoom;Dygraph.moveZoom=Dygraph.Interaction.moveZoom;Dygraph.startZoom=Dygraph.Interaction.startZoom;Dygraph.endPan=Dygraph.Interaction.endPan;Dygraph.movePan=Dygraph.Interaction.movePan;Dygraph.startPan=Dygraph.Interaction.startPan;Dygraph.Interaction.nonInteractiveModel_={mousedown:function(c,b,a){a.initializeMouseDown(c,b,a)},mouseup:function(c,b,a){a.dragEndX=b.dragGetX_(c,a);a.dragEndY=b.dragGetY_(c,a);var e=Math.abs(a.dragEndX-a.dragStartX);var d=Math.abs(a.dragEndY-a.dragStartY);if(e<2&&d<2&&b.lastx_!==undefined&&b.lastx_!=-1){Dygraph.Interaction.treatMouseOpAsClick(b,c,a)}}};Dygraph.Interaction.dragIsPanInteractionModel={mousedown:function(c,b,a){a.initializeMouseDown(c,b,a);Dygraph.startPan(c,b,a)},mousemove:function(c,b,a){if(a.isPanning){Dygraph.movePan(c,b,a)}},mouseup:function(c,b,a){if(a.isPanning){Dygraph.endPan(c,b,a)}}};"use strict";var DygraphRangeSelector=function(a){this.isIE_=/MSIE/.test(navigator.userAgent)&&!window.opera;this.isUsingExcanvas_=a.isUsingExcanvas_;this.dygraph_=a;this.hasTouchInterface_=typeof(TouchEvent)!="undefined";this.isMobileDevice_=/mobile|android/gi.test(navigator.appVersion);this.createCanvases_();if(this.isUsingExcanvas_){this.createIEPanOverlay_()}this.createZoomHandles_();this.initInteraction_()};DygraphRangeSelector.prototype.addToGraph=function(a,b){this.layout_=b;this.resize_();a.appendChild(this.bgcanvas_);a.appendChild(this.fgcanvas_);a.appendChild(this.leftZoomHandle_);a.appendChild(this.rightZoomHandle_)};DygraphRangeSelector.prototype.renderStaticLayer=function(){this.resize_();this.drawStaticLayer_()};DygraphRangeSelector.prototype.renderInteractiveLayer=function(){if(this.isChangingRange_){return}this.placeZoomHandles_();this.drawInteractiveLayer_()};DygraphRangeSelector.prototype.resize_=function(){function c(d,e){d.style.top=e.y+"px";d.style.left=e.x+"px";d.width=e.w;d.height=e.h;d.style.width=d.width+"px";d.style.height=d.height+"px"}var b=this.layout_.getPlotArea();var a=this.attr_("xAxisHeight")||(this.attr_("axisLabelFontSize")+2*this.attr_("axisTickSize"));this.canvasRect_={x:b.x,y:b.y+b.h+a+4,w:b.w,h:this.attr_("rangeSelectorHeight")};c(this.bgcanvas_,this.canvasRect_);c(this.fgcanvas_,this.canvasRect_)};DygraphRangeSelector.prototype.attr_=function(a){return this.dygraph_.attr_(a)};DygraphRangeSelector.prototype.createCanvases_=function(){this.bgcanvas_=Dygraph.createCanvas();this.bgcanvas_.className="dygraph-rangesel-bgcanvas";this.bgcanvas_.style.position="absolute";this.bgcanvas_.style.zIndex=9;this.bgcanvas_ctx_=Dygraph.getContext(this.bgcanvas_);this.fgcanvas_=Dygraph.createCanvas();this.fgcanvas_.className="dygraph-rangesel-fgcanvas";this.fgcanvas_.style.position="absolute";this.fgcanvas_.style.zIndex=9;this.fgcanvas_.style.cursor="default";this.fgcanvas_ctx_=Dygraph.getContext(this.fgcanvas_)};DygraphRangeSelector.prototype.createIEPanOverlay_=function(){this.iePanOverlay_=document.createElement("div");this.iePanOverlay_.style.position="absolute";this.iePanOverlay_.style.backgroundColor="white";this.iePanOverlay_.style.filter="alpha(opacity=0)";this.iePanOverlay_.style.display="none";this.iePanOverlay_.style.cursor="move";this.fgcanvas_.appendChild(this.iePanOverlay_)};DygraphRangeSelector.prototype.createZoomHandles_=function(){var a=new Image();a.className="dygraph-rangesel-zoomhandle";a.style.position="absolute";a.style.zIndex=10;a.style.visibility="hidden";a.style.cursor="col-resize";if(/MSIE 7/.test(navigator.userAgent)){a.width=7;a.height=14;a.style.backgroundColor="white";a.style.border="1px solid #333333"}else{a.width=9;a.height=16;a.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAQCAYAAADESFVDAAAAAXNSR0IArs4c6QAAAAZiS0dEANAAzwDP4Z7KegAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9sHGw0cMqdt1UwAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAaElEQVQoz+3SsRFAQBCF4Z9WJM8KCDVwownl6YXsTmCUsyKGkZzcl7zkz3YLkypgAnreFmDEpHkIwVOMfpdi9CEEN2nGpFdwD03yEqDtOgCaun7sqSTDH32I1pQA2Pb9sZecAxc5r3IAb21d6878xsAAAAAASUVORK5CYII="}if(this.isMobileDevice_){a.width*=2;a.height*=2}this.leftZoomHandle_=a;this.rightZoomHandle_=a.cloneNode(false)};DygraphRangeSelector.prototype.initInteraction_=function(){var o=this;var h=this.isIE_?document:window;var q=0;var v=null;var t=false;var c=false;var f=!this.isMobileDevice_&&!this.isUsingExcanvas_;var k=new Dygraph.IFrameTarp();var p,e,s,i,w,g,x,u,r,b,n,j;var d,m,l;p=function(C){var B=o.dygraph_.xAxisExtremes();var z=(B[1]-B[0])/o.canvasRect_.w;var A=B[0]+(C.leftHandlePos-o.canvasRect_.x)*z;var y=B[0]+(C.rightHandlePos-o.canvasRect_.x)*z;return[A,y]};j=function(z){var y=window.outerWidth/document.documentElement.clientWidth;if(!isNaN(y)){return z/y}else{return z}};e=function(y){Dygraph.cancelEvent(y);t=true;q=y.screenX;v=y.target?y.target:y.srcElement;o.dygraph_.addEvent(h,"mousemove",s);o.dygraph_.addEvent(h,"mouseup",i);o.fgcanvas_.style.cursor="col-resize";k.cover();return true};s=function(C){if(!t){return false}Dygraph.cancelEvent(C);var z=C.screenX-q;if(Math.abs(z)<4||C.screenX===0){return true}q=C.screenX;z=j(z);var B=o.getZoomHandleStatus_();var y;if(v==o.leftZoomHandle_){y=B.leftHandlePos+z;y=Math.min(y,B.rightHandlePos-v.width-3);y=Math.max(y,o.canvasRect_.x)}else{y=B.rightHandlePos+z;y=Math.min(y,o.canvasRect_.x+o.canvasRect_.w);y=Math.max(y,B.leftHandlePos+v.width+3)}var A=v.width/2;v.style.left=(y-A)+"px";o.drawInteractiveLayer_();if(f){w()}return true};i=function(y){if(!t){return false}t=false;k.uncover();Dygraph.removeEvent(h,"mousemove",s);Dygraph.removeEvent(h,"mouseup",i);o.fgcanvas_.style.cursor="default";if(!f){w()}return true};w=function(){try{var z=o.getZoomHandleStatus_();o.isChangingRange_=true;if(!z.isZoomed){o.dygraph_.resetZoom()}else{var y=p(z);o.dygraph_.doZoomXDates_(y[0],y[1])}}finally{o.isChangingRange_=false}};g=function(A){if(o.isUsingExcanvas_){return A.srcElement==o.iePanOverlay_}else{var z=o.leftZoomHandle_.getBoundingClientRect();var y=z.left+z.width/2;z=o.rightZoomHandle_.getBoundingClientRect();var B=z.left+z.width/2;return(A.clientX>y&&A.clientX<B)}};x=function(y){if(!c&&g(y)&&o.getZoomHandleStatus_().isZoomed){Dygraph.cancelEvent(y);c=true;q=y.screenX;o.dygraph_.addEvent(h,"mousemove",u);o.dygraph_.addEvent(h,"mouseup",r);return true}return false};u=function(C){if(!c){return false}Dygraph.cancelEvent(C);var z=C.screenX-q;if(Math.abs(z)<4){return true}q=C.screenX;z=j(z);var B=o.getZoomHandleStatus_();var E=B.leftHandlePos;var y=B.rightHandlePos;var D=y-E;if(E+z<=o.canvasRect_.x){E=o.canvasRect_.x;y=E+D}else{if(y+z>=o.canvasRect_.x+o.canvasRect_.w){y=o.canvasRect_.x+o.canvasRect_.w;E=y-D}else{E+=z;y+=z}}var A=o.leftZoomHandle_.width/2;o.leftZoomHandle_.style.left=(E-A)+"px";o.rightZoomHandle_.style.left=(y-A)+"px";o.drawInteractiveLayer_();if(f){b()}return true};r=function(y){if(!c){return false}c=false;Dygraph.removeEvent(h,"mousemove",u);Dygraph.removeEvent(h,"mouseup",r);if(!f){b()}return true};b=function(){try{o.isChangingRange_=true;o.dygraph_.dateWindow_=p(o.getZoomHandleStatus_());o.dygraph_.drawGraph_(false)}finally{o.isChangingRange_=false}};n=function(y){if(t||c){return}var z=g(y)?"move":"default";if(z!=o.fgcanvas_.style.cursor){o.fgcanvas_.style.cursor=z}};d=function(y){if(y.type=="touchstart"&&y.targetTouches.length==1){if(e(y.targetTouches[0])){Dygraph.cancelEvent(y)}}else{if(y.type=="touchmove"&&y.targetTouches.length==1){if(s(y.targetTouches[0])){Dygraph.cancelEvent(y)}}else{i(y)}}};m=function(y){if(y.type=="touchstart"&&y.targetTouches.length==1){if(x(y.targetTouches[0])){Dygraph.cancelEvent(y)}}else{if(y.type=="touchmove"&&y.targetTouches.length==1){if(u(y.targetTouches[0])){Dygraph.cancelEvent(y)}}else{r(y)}}};l=function(B,A){var z=["touchstart","touchend","touchmove","touchcancel"];for(var y=0;y<z.length;y++){o.dygraph_.addEvent(B,z[y],A)}};this.dygraph_.attrs_.interactionModel=Dygraph.Interaction.dragIsPanInteractionModel;this.dygraph_.attrs_.panEdgeFraction=0.0001;var a=window.opera?"mousedown":"dragstart";this.dygraph_.addEvent(this.leftZoomHandle_,a,e);this.dygraph_.addEvent(this.rightZoomHandle_,a,e);if(this.isUsingExcanvas_){this.dygraph_.addEvent(this.iePanOverlay_,"mousedown",x)}else{this.dygraph_.addEvent(this.fgcanvas_,"mousedown",x);this.dygraph_.addEvent(this.fgcanvas_,"mousemove",n)}if(this.hasTouchInterface_){l(this.leftZoomHandle_,d);l(this.rightZoomHandle_,d);l(this.fgcanvas_,m)}};DygraphRangeSelector.prototype.drawStaticLayer_=function(){var a=this.bgcanvas_ctx_;a.clearRect(0,0,this.canvasRect_.w,this.canvasRect_.h);try{this.drawMiniPlot_()}catch(b){Dygraph.warn(b)}var c=0.5;this.bgcanvas_ctx_.lineWidth=1;a.strokeStyle="gray";a.beginPath();a.moveTo(c,c);a.lineTo(c,this.canvasRect_.h-c);a.lineTo(this.canvasRect_.w-c,this.canvasRect_.h-c);a.lineTo(this.canvasRect_.w-c,c);a.stroke()};DygraphRangeSelector.prototype.drawMiniPlot_=function(){var e=this.attr_("rangeSelectorPlotFillColor");var q=this.attr_("rangeSelectorPlotStrokeColor");if(!e&&!q){return}var h=this.attr_("stepPlot");var u=this.computeCombinedSeriesAndLimits_();var p=u.yMax-u.yMin;var o=this.bgcanvas_ctx_;var m=0.5;var d=this.dygraph_.xAxisExtremes();var n=Math.max(d[1]-d[0],1e-30);var f=(this.canvasRect_.w-m)/n;var t=(this.canvasRect_.h-m)/p;var s=this.canvasRect_.w-m;var a=this.canvasRect_.h-m;var c=null,b=null;o.beginPath();o.moveTo(m,a);for(var r=0;r<u.data.length;r++){var g=u.data[r];var k=((g[0]!==null)?((g[0]-d[0])*f):NaN);var j=((g[1]!==null)?(a-(g[1]-u.yMin)*t):NaN);if(isFinite(k)&&isFinite(j)){if(c===null){o.lineTo(k,a)}else{if(h){o.lineTo(k,b)}}o.lineTo(k,j);c=k;b=j}else{if(c!==null){if(h){o.lineTo(k,b);o.lineTo(k,a)}else{o.lineTo(c,a)}}c=b=null}}o.lineTo(s,a);o.closePath();if(e){var l=this.bgcanvas_ctx_.createLinearGradient(0,0,0,a);l.addColorStop(0,"white");l.addColorStop(1,e);this.bgcanvas_ctx_.fillStyle=l;o.fill()}if(q){this.bgcanvas_ctx_.strokeStyle=q;this.bgcanvas_ctx_.lineWidth=1.5;o.stroke()}};DygraphRangeSelector.prototype.computeCombinedSeriesAndLimits_=function(){var u=this.dygraph_.rawData_;var t=this.attr_("logscale");var p=[];var c;var g;var l;var s,r,q;var d,f;for(s=0;s<u.length;s++){if(u[s].length>1&&u[s][1]!==null){l=typeof u[s][1]!="number";if(l){c=[];g=[];for(q=0;q<u[s][1].length;q++){c.push(0);g.push(0)}}break}}for(s=0;s<u.length;s++){var h=u[s];d=h[0];if(l){for(q=0;q<c.length;q++){c[q]=g[q]=0}}else{c=g=0}for(r=1;r<h.length;r++){if(this.dygraph_.visibility()[r-1]){var m;if(l){for(q=0;q<c.length;q++){m=h[r][q];if(m===null||isNaN(m)){continue}c[q]+=m;g[q]++}}else{m=h[r];if(m===null||isNaN(m)){continue}c+=m;g++}}}if(l){for(q=0;q<c.length;q++){c[q]/=g[q]}f=c.slice(0)}else{f=c/g}p.push([d,f])}p=this.dygraph_.rollingAverage(p,this.dygraph_.rollPeriod_);if(typeof p[0][1]!="number"){for(s=0;s<p.length;s++){f=p[s][1];p[s][1]=f[0]}}var a=Number.MAX_VALUE;var b=-Number.MAX_VALUE;for(s=0;s<p.length;s++){f=p[s][1];if(f!==null&&isFinite(f)&&(!t||f>0)){a=Math.min(a,f);b=Math.max(b,f)}}var n=0.25;if(t){b=Dygraph.log10(b);b+=b*n;a=Dygraph.log10(a);for(s=0;s<p.length;s++){p[s][1]=Dygraph.log10(p[s][1])}}else{var e;var o=b-a;if(o<=Number.MIN_VALUE){e=b*n}else{e=o*n}b+=e;a-=e}return{data:p,yMin:a,yMax:b}};DygraphRangeSelector.prototype.placeZoomHandles_=function(){var g=this.dygraph_.xAxisExtremes();var a=this.dygraph_.xAxisRange();var b=g[1]-g[0];var i=Math.max(0,(a[0]-g[0])/b);var e=Math.max(0,(g[1]-a[1])/b);var h=this.canvasRect_.x+this.canvasRect_.w*i;var d=this.canvasRect_.x+this.canvasRect_.w*(1-e);var c=Math.max(this.canvasRect_.y,this.canvasRect_.y+(this.canvasRect_.h-this.leftZoomHandle_.height)/2);var f=this.leftZoomHandle_.width/2;this.leftZoomHandle_.style.left=(h-f)+"px";this.leftZoomHandle_.style.top=c+"px";this.rightZoomHandle_.style.left=(d-f)+"px";this.rightZoomHandle_.style.top=this.leftZoomHandle_.style.top;this.leftZoomHandle_.style.visibility="visible";this.rightZoomHandle_.style.visibility="visible"};DygraphRangeSelector.prototype.drawInteractiveLayer_=function(){var b=this.fgcanvas_ctx_;b.clearRect(0,0,this.canvasRect_.w,this.canvasRect_.h);var e=1;var d=this.canvasRect_.w-e;var a=this.canvasRect_.h-e;var g=this.getZoomHandleStatus_();b.strokeStyle="black";if(!g.isZoomed){b.beginPath();b.moveTo(e,e);b.lineTo(e,a);b.lineTo(d,a);b.lineTo(d,e);b.stroke();if(this.iePanOverlay_){this.iePanOverlay_.style.display="none"}}else{var f=Math.max(e,g.leftHandlePos-this.canvasRect_.x);var c=Math.min(d,g.rightHandlePos-this.canvasRect_.x);b.fillStyle="rgba(240, 240, 240, 0.6)";b.fillRect(0,0,f,this.canvasRect_.h);b.fillRect(c,0,this.canvasRect_.w-c,this.canvasRect_.h);b.beginPath();b.moveTo(e,e);b.lineTo(f,e);b.lineTo(f,a);b.lineTo(c,a);b.lineTo(c,e);b.lineTo(d,e);b.stroke();if(this.isUsingExcanvas_){this.iePanOverlay_.style.width=(c-f)+"px";this.iePanOverlay_.style.left=f+"px";this.iePanOverlay_.style.height=a+"px";this.iePanOverlay_.style.display="inline"}}};DygraphRangeSelector.prototype.getZoomHandleStatus_=function(){var b=this.leftZoomHandle_.width/2;var c=parseInt(this.leftZoomHandle_.style.left,10)+b;var a=parseInt(this.rightZoomHandle_.style.left,10)+b;return{leftHandlePos:c,rightHandlePos:a,isZoomed:(c-1>this.canvasRect_.x||a+1<this.canvasRect_.x+this.canvasRect_.w)}};"use strict";Dygraph.TickList;Dygraph.Ticker;Dygraph.numericLinearTicks=function(d,c,i,g,f,h){var e=function(a){if(a==="logscale"){return false}return g(a)};return Dygraph.numericTicks(d,c,i,e,f,h)};Dygraph.numericTicks=function(S,R,p,w,u,F){var y=function(a,b){if(b<0){return 1/Math.pow(a,-b)}return Math.pow(a,b)};var d=(w("pixelsPerLabel"));var G=[];var N,L,h,q;if(F){for(N=0;N<F.length;N++){G.push({v:F[N]})}}else{if(w("logscale")){q=Math.floor(p/d);var r=Dygraph.binarySearch(S,Dygraph.PREFERRED_LOG_TICK_VALUES,1);var A=Dygraph.binarySearch(R,Dygraph.PREFERRED_LOG_TICK_VALUES,-1);if(r==-1){r=0}if(A==-1){A=Dygraph.PREFERRED_LOG_TICK_VALUES.length-1}var H=null;if(A-r>=q/4){for(var Q=A;Q>=r;Q--){var D=Dygraph.PREFERRED_LOG_TICK_VALUES[Q];var s=Math.log(D/S)/Math.log(R/S)*p;var e={v:D};if(H===null){H={tickValue:D,pixel_coord:s}}else{if(Math.abs(s-H.pixel_coord)>=d){H={tickValue:D,pixel_coord:s}}else{e.label=""}}G.push(e)}G.reverse()}}if(G.length===0){var o=w("labelsKMG2");var C,t;if(o){C=[1,2,4,8,16,32,64,128,256];t=16}else{C=[1,2,5,10,20,50,100];t=10}var l=Math.ceil(p/d);var O=Math.abs(R-S)/l;var P=Math.floor(Math.log(O)/Math.log(t));var z=Math.pow(t,P);var B,x,E,q,g;for(L=0;L<C.length;L++){B=z*C[L];x=Math.floor(S/B)*B;E=Math.ceil(R/B)*B;q=Math.abs(E-x)/B;g=p/q;if(g>d){break}}if(x>E){B*=-1}for(N=0;N<q;N++){h=x+N*B;G.push({v:h})}}}var K;var M=[];var f=[];if(w("labelsKMB")){K=1000;M=["K","M","B","T","Q"]}if(w("labelsKMG2")){if(K){Dygraph.warn("Setting both labelsKMB and labelsKMG2. Pick one!")}K=1024;M=["k","M","G","T","P","E","Z","Y"];f=["m","u","n","p","f","a","z","y"]}K=K||1;var m=(w("axisLabelFormatter"));var v=(w("digitsAfterDecimal"));for(N=0;N<G.length;N++){if(G[N].label!==undefined){continue}h=G[N].v;var c=Math.abs(h);var I=m(h,0,w,u);if(M.length>0){var J=y(K,M.length);for(L=M.length-1;L>=0;L--,J/=K){if(c>=J){I=Dygraph.round_(h/J,v)+M[L];break}}}if(w("labelsKMG2")){h=String(h.toExponential());if(h.split("e-").length===2&&h.split("e-")[1]>=3&&h.split("e-")[1]<=24){if(h.split("e-")[1]%3>0){I=Dygraph.round_(h.split("e-")[0]/y(10,(h.split("e-")[1]%3)),v)}else{I=Number(h.split("e-")[0]).toFixed(2)}I+=f[Math.floor(h.split("e-")[1]/3)-1]}}G[N].label=I}return G};Dygraph.dateTicker=function(e,c,i,g,f,h){var d=Dygraph.pickDateTickGranularity(e,c,i,g);if(d>=0){return Dygraph.getDateAxis(e,c,d,g,f)}else{return[]}};Dygraph.SECONDLY=0;Dygraph.TWO_SECONDLY=1;Dygraph.FIVE_SECONDLY=2;Dygraph.TEN_SECONDLY=3;Dygraph.THIRTY_SECONDLY=4;Dygraph.MINUTELY=5;Dygraph.TWO_MINUTELY=6;Dygraph.FIVE_MINUTELY=7;Dygraph.TEN_MINUTELY=8;Dygraph.THIRTY_MINUTELY=9;Dygraph.HOURLY=10;Dygraph.TWO_HOURLY=11;Dygraph.SIX_HOURLY=12;Dygraph.DAILY=13;Dygraph.WEEKLY=14;Dygraph.MONTHLY=15;Dygraph.QUARTERLY=16;Dygraph.BIANNUAL=17;Dygraph.ANNUAL=18;Dygraph.DECADAL=19;Dygraph.CENTENNIAL=20;Dygraph.NUM_GRANULARITIES=21;Dygraph.SHORT_SPACINGS=[];Dygraph.SHORT_SPACINGS[Dygraph.SECONDLY]=1000*1;Dygraph.SHORT_SPACINGS[Dygraph.TWO_SECONDLY]=1000*2;Dygraph.SHORT_SPACINGS[Dygraph.FIVE_SECONDLY]=1000*5;Dygraph.SHORT_SPACINGS[Dygraph.TEN_SECONDLY]=1000*10;Dygraph.SHORT_SPACINGS[Dygraph.THIRTY_SECONDLY]=1000*30;Dygraph.SHORT_SPACINGS[Dygraph.MINUTELY]=1000*60;Dygraph.SHORT_SPACINGS[Dygraph.TWO_MINUTELY]=1000*60*2;Dygraph.SHORT_SPACINGS[Dygraph.FIVE_MINUTELY]=1000*60*5;Dygraph.SHORT_SPACINGS[Dygraph.TEN_MINUTELY]=1000*60*10;Dygraph.SHORT_SPACINGS[Dygraph.THIRTY_MINUTELY]=1000*60*30;Dygraph.SHORT_SPACINGS[Dygraph.HOURLY]=1000*3600;Dygraph.SHORT_SPACINGS[Dygraph.TWO_HOURLY]=1000*3600*2;Dygraph.SHORT_SPACINGS[Dygraph.SIX_HOURLY]=1000*3600*6;Dygraph.SHORT_SPACINGS[Dygraph.DAILY]=1000*86400;Dygraph.SHORT_SPACINGS[Dygraph.WEEKLY]=1000*604800;Dygraph.PREFERRED_LOG_TICK_VALUES=function(){var c=[];for(var b=-39;b<=39;b++){var a=Math.pow(10,b);for(var d=1;d<=9;d++){var e=a*d;c.push(e)}}return c}();Dygraph.pickDateTickGranularity=function(d,c,j,h){var g=(h("pixelsPerLabel"));for(var f=0;f<Dygraph.NUM_GRANULARITIES;f++){var e=Dygraph.numDateTicks(d,c,f);if(j/e>=g){return f}}return -1};Dygraph.numDateTicks=function(e,b,g){if(g<Dygraph.MONTHLY){var h=Dygraph.SHORT_SPACINGS[g];return Math.floor(0.5+1*(b-e)/h)}else{var f=1;var d=12;if(g==Dygraph.QUARTERLY){d=3}if(g==Dygraph.BIANNUAL){d=2}if(g==Dygraph.ANNUAL){d=1}if(g==Dygraph.DECADAL){d=1;f=10}if(g==Dygraph.CENTENNIAL){d=1;f=100}var c=365.2524*24*3600*1000;var a=1*(b-e)/c;return Math.floor(0.5+1*a*d/f)}};Dygraph.getDateAxis=function(n,h,a,l,w){var u=(l("axisLabelFormatter"));var z=[];var k;if(a<Dygraph.MONTHLY){var c=Dygraph.SHORT_SPACINGS[a];var v=c/1000;var y=new Date(n);y.setMilliseconds(0);var f;if(v<=60){f=y.getSeconds();y.setSeconds(f-f%v)}else{y.setSeconds(0);v/=60;if(v<=60){f=y.getMinutes();y.setMinutes(f-f%v)}else{y.setMinutes(0);v/=60;if(v<=24){f=y.getHours();y.setHours(f-f%v)}else{y.setHours(0);v/=24;if(v==7){y.setDate(y.getDate()-y.getDay())}}}}n=y.getTime();for(k=n;k<=h;k+=c){z.push({v:k,label:u(new Date(k),a,l,w)})}}else{var e;var o=1;if(a==Dygraph.MONTHLY){e=[0,1,2,3,4,5,6,7,8,9,10,11]}else{if(a==Dygraph.QUARTERLY){e=[0,3,6,9]}else{if(a==Dygraph.BIANNUAL){e=[0,6]}else{if(a==Dygraph.ANNUAL){e=[0]}else{if(a==Dygraph.DECADAL){e=[0];o=10}else{if(a==Dygraph.CENTENNIAL){e=[0];o=100}else{Dygraph.warn("Span of dates is too long")}}}}}}var s=new Date(n).getFullYear();var p=new Date(h).getFullYear();var b=Dygraph.zeropad;for(var r=s;r<=p;r++){if(r%o!==0){continue}for(var q=0;q<e.length;q++){var m=r+"/"+b(1+e[q])+"/01";k=Dygraph.dateStrToMillis(m);if(k<n||k>h){continue}z.push({v:k,label:u(new Date(k),a,l,w)})}}}return z};Dygraph.DEFAULT_ATTRS.axes["x"]["ticker"]=Dygraph.dateTicker;Dygraph.DEFAULT_ATTRS.axes["y"]["ticker"]=Dygraph.numericTicks;Dygraph.DEFAULT_ATTRS.axes["y2"]["ticker"]=Dygraph.numericTicks;Dygraph.Plugins={};Dygraph.Plugins.Annotations=(function(){var a=function(){this.annotations_=[]};a.prototype.toString=function(){return"Annotations Plugin"};a.prototype.activate=function(b){return{clearChart:this.clearChart,didDrawChart:this.didDrawChart}};a.prototype.detachLabels=function(){for(var c=0;c<this.annotations_.length;c++){var b=this.annotations_[c];if(b.parentNode){b.parentNode.removeChild(b)}this.annotations_[c]=null}this.annotations_=[]};a.prototype.clearChart=function(b){this.detachLabels()};a.prototype.didDrawChart=function(o){var m=o.dygraph;var t=m.layout_.annotated_points;if(!t||t.length===0){return}var q=o.canvas.parentNode;var l={position:"absolute",fontSize:m.getOption("axisLabelFontSize")+"px",zIndex:10,overflow:"hidden"};var n=function(e,g,i){return function(w){var p=i.annotation;if(p.hasOwnProperty(e)){p[e](p,i,m,w)}else{if(m.getOption(g)){m.getOption(g)(p,i,m,w)}}}};var h=o.dygraph.plotter_.area;for(var k=0;k<t.length;k++){var f=t[k];if(f.canvasx<h.x||f.canvasx>h.x+h.w||f.canvasy<h.y||f.canvasy>h.y+h.h){continue}var r=f.annotation;var s=6;if(r.hasOwnProperty("tickHeight")){s=r.tickHeight}var c=document.createElement("div");for(var b in l){if(l.hasOwnProperty(b)){c.style[b]=l[b]}}if(!r.hasOwnProperty("icon")){c.className="dygraphDefaultAnnotation"}if(r.hasOwnProperty("cssClass")){c.className+=" "+r.cssClass}var d=r.hasOwnProperty("width")?r.width:16;var u=r.hasOwnProperty("height")?r.height:16;if(r.hasOwnProperty("icon")){var j=document.createElement("img");j.src=r.icon;j.width=d;j.height=u;c.appendChild(j)}else{if(f.annotation.hasOwnProperty("shortText")){c.appendChild(document.createTextNode(f.annotation.shortText))}}c.style.left=(f.canvasx-d/2)+"px";if(r.attachAtBottom){c.style.top=(h.h-u-s)+"px"}else{c.style.top=(f.canvasy-u-s)+"px"}c.style.width=d+"px";c.style.height=u+"px";c.title=f.annotation.text;c.style.color=m.colorsMap_[f.name];c.style.borderColor=m.colorsMap_[f.name];r.div=c;m.addEvent(c,"click",n("clickHandler","annotationClickHandler",f,this));m.addEvent(c,"mouseover",n("mouseOverHandler","annotationMouseOverHandler",f,this));m.addEvent(c,"mouseout",n("mouseOutHandler","annotationMouseOutHandler",f,this));m.addEvent(c,"dblclick",n("dblClickHandler","annotationDblClickHandler",f,this));q.appendChild(c);this.annotations_.push(c);var v=o.drawingContext;v.save();v.strokeStyle=m.colorsMap_[f.name];v.beginPath();if(!r.attachAtBottom){v.moveTo(f.canvasx,f.canvasy);v.lineTo(f.canvasx,f.canvasy-2-s)}else{v.moveTo(f.canvasx,h.h);v.lineTo(f.canvasx,h.h-2-s)}v.closePath();v.stroke();v.restore()}};a.prototype.destroy=function(){this.detachLabels()};return a})();Dygraph.Plugins.Axes=(function(){var a=function(){this.xlabels_=[];this.ylabels_=[]};a.prototype.toString=function(){return"Axes Plugin"};a.prototype.activate=function(b){return{layout:this.layout,clearChart:this.clearChart,willDrawChart:this.willDrawChart}};a.prototype.layout=function(k){var j=k.dygraph;if(j.getOption("drawYAxis")){var b=j.getOption("yAxisLabelWidth")+2*j.getOption("axisTickSize");var i=k.reserveSpaceLeft(b)}if(j.getOption("drawXAxis")){var f;if(j.getOption("xAxisHeight")){f=j.getOption("xAxisHeight")}else{f=j.getOptionForAxis("axisLabelFontSize","x")+2*j.getOption("axisTickSize")}var c=k.reserveSpaceBottom(f)}if(j.numAxes()==2){var b=j.getOption("yAxisLabelWidth")+2*j.getOption("axisTickSize");var d=k.reserveSpaceRight(b)}else{if(j.numAxes()>2){j.error("Only two y-axes are supported at this time. (Trying to use "+j.numAxes()+")")}}};a.prototype.detachLabels=function(){function b(d){for(var c=0;c<d.length;c++){var e=d[c];if(e.parentNode){e.parentNode.removeChild(e)}}}b(this.xlabels_);b(this.ylabels_);this.xlabels_=[];this.ylabels_=[]};a.prototype.clearChart=function(c){var b=c.dygraph;this.detachLabels()};a.prototype.willDrawChart=function(H){var F=H.dygraph;if(!F.getOption("drawXAxis")&&!F.getOption("drawYAxis")){return}function B(e){return Math.round(e)+0.5}function A(e){return Math.round(e)-0.5}var j=H.drawingContext;var v=H.canvas.parentNode;var J=H.canvas.width;var d=H.canvas.height;var s,u,t,E,D;var C=function(e){return{position:"absolute",fontSize:F.getOptionForAxis("axisLabelFontSize",e)+"px",zIndex:10,color:F.getOptionForAxis("axisLabelColor",e),width:F.getOption("axisLabelWidth")+"px",lineHeight:"normal",overflow:"hidden"}};var p={x:C("x"),y:C("y"),y2:C("y2"),};var m=function(g,x,y){var K=document.createElement("div");var e=p[y=="y2"?"y2":x];for(var r in e){if(e.hasOwnProperty(r)){K.style[r]=e[r]}}var i=document.createElement("div");i.className="dygraph-axis-label dygraph-axis-label-"+x+(y?" dygraph-axis-label-"+y:"");i.innerHTML=g;K.appendChild(i);return K};j.save();var I=F.layout_;var G=H.dygraph.plotter_.area;if(F.getOption("drawYAxis")){if(I.yticks&&I.yticks.length>0){var h=F.numAxes();for(D=0;D<I.yticks.length;D++){E=I.yticks[D];if(typeof(E)=="function"){return}u=G.x;var o=1;var f="y1";if(E[0]==1){u=G.x+G.w;o=-1;f="y2"}var k=F.getOptionForAxis("axisLabelFontSize",f);t=G.y+E[1]*G.h;s=m(E[2],"y",h==2?f:null);var z=(t-k/2);if(z<0){z=0}if(z+k+3>d){s.style.bottom="0px"}else{s.style.top=z+"px"}if(E[0]===0){s.style.left=(G.x-F.getOption("yAxisLabelWidth")-F.getOption("axisTickSize"))+"px";s.style.textAlign="right"}else{if(E[0]==1){s.style.left=(G.x+G.w+F.getOption("axisTickSize"))+"px";s.style.textAlign="left"}}s.style.width=F.getOption("yAxisLabelWidth")+"px";v.appendChild(s);this.ylabels_.push(s)}var n=this.ylabels_[0];var k=F.getOptionForAxis("axisLabelFontSize","y");var q=parseInt(n.style.top,10)+k;if(q>d-k){n.style.top=(parseInt(n.style.top,10)-k/2)+"px"}}var c;if(F.getOption("drawAxesAtZero")){var w=F.toPercentXCoord(0);if(w>1||w<0){w=0}c=B(G.x+w*G.w)}else{c=B(G.x)}j.strokeStyle=F.getOptionForAxis("axisLineColor","y");j.lineWidth=F.getOptionForAxis("axisLineWidth","y");j.beginPath();j.moveTo(c,A(G.y));j.lineTo(c,A(G.y+G.h));j.closePath();j.stroke();if(F.numAxes()==2){j.strokeStyle=F.getOptionForAxis("axisLineColor","y2");j.lineWidth=F.getOptionForAxis("axisLineWidth","y2");j.beginPath();j.moveTo(A(G.x+G.w),A(G.y));j.lineTo(A(G.x+G.w),A(G.y+G.h));j.closePath();j.stroke()}}if(F.getOption("drawXAxis")){if(I.xticks){for(D=0;D<I.xticks.length;D++){E=I.xticks[D];u=G.x+E[0]*G.w;t=G.y+G.h;s=m(E[1],"x");s.style.textAlign="center";s.style.top=(t+F.getOption("axisTickSize"))+"px";var l=(u-F.getOption("axisLabelWidth")/2);if(l+F.getOption("axisLabelWidth")>J){l=J-F.getOption("xAxisLabelWidth");s.style.textAlign="right"}if(l<0){l=0;s.style.textAlign="left"}s.style.left=l+"px";s.style.width=F.getOption("xAxisLabelWidth")+"px";v.appendChild(s);this.xlabels_.push(s)}}j.strokeStyle=F.getOptionForAxis("axisLineColor","x");j.lineWidth=F.getOptionForAxis("axisLineWidth","x");j.beginPath();var b;if(F.getOption("drawAxesAtZero")){var w=F.toPercentYCoord(0,0);if(w>1||w<0){w=1}b=A(G.y+w*G.h)}else{b=A(G.y+G.h)}j.moveTo(B(G.x),b);j.lineTo(B(G.x+G.w),b);j.closePath();j.stroke()}j.restore()};return a})();Dygraph.Plugins.ChartLabels=(function(){var c=function(){this.title_div_=null;this.xlabel_div_=null;this.ylabel_div_=null;this.y2label_div_=null};c.prototype.toString=function(){return"ChartLabels Plugin"};c.prototype.activate=function(d){return{layout:this.layout,didDrawChart:this.didDrawChart}};var b=function(d){var e=document.createElement("div");e.style.position="absolute";e.style.left=d.x+"px";e.style.top=d.y+"px";e.style.width=d.w+"px";e.style.height=d.h+"px";return e};c.prototype.detachLabels_=function(){var e=[this.title_div_,this.xlabel_div_,this.ylabel_div_,this.y2label_div_];for(var d=0;d<e.length;d++){var f=e[d];if(!f){continue}if(f.parentNode){f.parentNode.removeChild(f)}}this.title_div_=null;this.xlabel_div_=null;this.ylabel_div_=null;this.y2label_div_=null};var a=function(l,i,f,h,j){var d=document.createElement("div");d.style.position="absolute";if(f==1){d.style.left="0px"}else{d.style.left=i.x+"px"}d.style.top=i.y+"px";d.style.width=i.w+"px";d.style.height=i.h+"px";d.style.fontSize=(l.getOption("yLabelWidth")-2)+"px";var m=document.createElement("div");m.style.position="absolute";m.style.width=i.h+"px";m.style.height=i.w+"px";m.style.top=(i.h/2-i.w/2)+"px";m.style.left=(i.w/2-i.h/2)+"px";m.style.textAlign="center";var e="rotate("+(f==1?"-":"")+"90deg)";m.style.transform=e;m.style.WebkitTransform=e;m.style.MozTransform=e;m.style.OTransform=e;m.style.msTransform=e;if(typeof(document.documentMode)!=="undefined"&&document.documentMode<9){m.style.filter="progid:DXImageTransform.Microsoft.BasicImage(rotation="+(f==1?"3":"1")+")";m.style.left="0px";m.style.top="0px"}var k=document.createElement("div");k.className=h;k.innerHTML=j;m.appendChild(k);d.appendChild(m);return d};c.prototype.layout=function(k){this.detachLabels_();var i=k.dygraph;var m=k.chart_div;if(i.getOption("title")){var d=k.reserveSpaceTop(i.getOption("titleHeight"));this.title_div_=b(d);this.title_div_.style.textAlign="center";this.title_div_.style.fontSize=(i.getOption("titleHeight")-8)+"px";this.title_div_.style.fontWeight="bold";this.title_div_.style.zIndex=10;var f=document.createElement("div");f.className="dygraph-label dygraph-title";f.innerHTML=i.getOption("title");this.title_div_.appendChild(f);m.appendChild(this.title_div_)}if(i.getOption("xlabel")){var j=k.reserveSpaceBottom(i.getOption("xLabelHeight"));this.xlabel_div_=b(j);this.xlabel_div_.style.textAlign="center";this.xlabel_div_.style.fontSize=(i.getOption("xLabelHeight")-2)+"px";var f=document.createElement("div");f.className="dygraph-label dygraph-xlabel";f.innerHTML=i.getOption("xlabel");this.xlabel_div_.appendChild(f);m.appendChild(this.xlabel_div_)}if(i.getOption("ylabel")){var h=k.reserveSpaceLeft(0);this.ylabel_div_=a(i,h,1,"dygraph-label dygraph-ylabel",i.getOption("ylabel"));m.appendChild(this.ylabel_div_)}if(i.getOption("y2label")&&i.numAxes()==2){var l=k.reserveSpaceRight(0);this.y2label_div_=a(i,l,2,"dygraph-label dygraph-y2label",i.getOption("y2label"));m.appendChild(this.y2label_div_)}};c.prototype.didDrawChart=function(f){var d=f.dygraph;if(this.title_div_){this.title_div_.children[0].innerHTML=d.getOption("title")}if(this.xlabel_div_){this.xlabel_div_.children[0].innerHTML=d.getOption("xlabel")}if(this.ylabel_div_){this.ylabel_div_.children[0].children[0].innerHTML=d.getOption("ylabel")}if(this.y2label_div_){this.y2label_div_.children[0].children[0].innerHTML=d.getOption("y2label")}};c.prototype.clearChart=function(){};c.prototype.destroy=function(){this.detachLabels_()};return c})();Dygraph.Plugins.Grid=(function(){var a=function(){};a.prototype.toString=function(){return"Gridline Plugin"};a.prototype.activate=function(b){return{willDrawChart:this.willDrawChart}};a.prototype.willDrawChart=function(k){var h=k.dygraph;var o=k.drawingContext;var j=h.layout_;var c=k.dygraph.plotter_.area;function b(e){return Math.round(e)+0.5}function d(e){return Math.round(e)-0.5}var m,l,f,n;if(h.getOption("drawYGrid")){n=j.yticks;o.save();o.strokeStyle=h.getOption("gridLineColor");o.lineWidth=h.getOption("gridLineWidth");for(f=0;f<n.length;f++){if(n[f][0]!==0){continue}m=b(c.x);l=d(c.y+n[f][1]*c.h);o.beginPath();o.moveTo(m,l);o.lineTo(m+c.w,l);o.closePath();o.stroke()}o.restore()}if(h.getOption("drawXGrid")){n=j.xticks;o.save();o.strokeStyle=h.getOption("gridLineColor");o.lineWidth=h.getOption("gridLineWidth");for(f=0;f<n.length;f++){m=b(c.x+n[f][0]*c.w);l=d(c.y+c.h);o.beginPath();o.moveTo(m,l);o.lineTo(m,c.y);o.closePath();o.stroke()}o.restore()}};a.prototype.destroy=function(){};return a})();Dygraph.Plugins.Legend=(function(){var c=function(){this.legend_div_=null;this.is_generated_div_=false};c.prototype.toString=function(){return"Legend Plugin"};var a,d;c.prototype.activate=function(j){var m;var f=j.getOption("labelsDivWidth");var l=j.getOption("labelsDiv");if(l&&null!==l){if(typeof(l)=="string"||l instanceof String){m=document.getElementById(l)}else{m=l}}else{var i={position:"absolute",fontSize:"14px",zIndex:10,width:f+"px",top:"0px",left:(j.size().width-f-2)+"px",background:"white",lineHeight:"normal",textAlign:"left",overflow:"hidden"};Dygraph.update(i,j.getOption("labelsDivStyles"));m=document.createElement("div");m.className="dygraph-legend";for(var h in i){if(!i.hasOwnProperty(h)){continue}try{m.style[h]=i[h]}catch(k){this.warn("You are using unsupported css properties for your browser in labelsDivStyles")}}j.graphDiv.appendChild(m);this.is_generated_div_=true}this.legend_div_=m;this.one_em_width_=10;return{select:this.select,deselect:this.deselect,predraw:this.predraw,didDrawChart:this.didDrawChart}};var b=function(g){var f=document.createElement("span");f.setAttribute("style","margin: 0; padding: 0 0 0 1em; border: 0;");g.appendChild(f);var e=f.offsetWidth;g.removeChild(f);return e};c.prototype.select=function(i){var h=i.selectedX;var g=i.selectedPoints;var f=a(i.dygraph,h,g,this.one_em_width_);this.legend_div_.innerHTML=f};c.prototype.deselect=function(h){var f=b(this.legend_div_);this.one_em_width_=f;var g=a(h.dygraph,undefined,undefined,f);this.legend_div_.innerHTML=g};c.prototype.didDrawChart=function(f){this.deselect(f)};c.prototype.predraw=function(h){if(!this.is_generated_div_){return}h.dygraph.graphDiv.appendChild(this.legend_div_);var g=h.dygraph.plotter_.area;var f=h.dygraph.getOption("labelsDivWidth");this.legend_div_.style.left=g.x+g.w-f-1+"px";this.legend_div_.style.top=g.y+"px";this.legend_div_.style.width=f+"px"};c.prototype.destroy=function(){this.legend_div_=null};a=function(w,p,l,f){if(w.getOption("showLabelsOnHighlight")!==true){return""}var r,D,u,A,s,m;var z=w.getLabels();if(typeof(p)==="undefined"){if(w.getOption("legend")!="always"){return""}D=w.getOption("labelsSeparateLines");r="";for(u=1;u<z.length;u++){var q=w.getPropertiesForSeries(z[u]);if(!q.visible){continue}if(r!==""){r+=(D?"<br/>":" ")}m=w.getOption("strokePattern",z[u]);s=d(m,q.color,f);r+="<span style='font-weight: bold; color: "+q.color+";'>"+s+" "+z[u]+"</span>"}return r}var B=w.optionsViewForAxis_("x");var o=B("valueFormatter");r=o(p,B,z[0],w);if(r!==""){r+=":"}var v=[];var j=w.numAxes();for(u=0;u<j;u++){v[u]=w.optionsViewForAxis_("y"+(u?1+u:""))}var k=w.getOption("labelsShowZeroValues");D=w.getOption("labelsSeparateLines");var C=w.getHighlightSeries();for(u=0;u<l.length;u++){var t=l[u];if(t.yval===0&&!k){continue}if(!Dygraph.isOK(t.canvasy)){continue}if(D){r+="<br/>"}var q=w.getPropertiesForSeries(t.name);var n=v[q.axis-1];var y=n("valueFormatter");var e=y(t.yval,n,t.name,w);var h=(t.name==C)?" class='highlight'":"";r+="<span"+h+"> <b><span style='color: "+q.color+";'>"+t.name+"</span></b>:"+e+"</span>"}return r};d=function(s,h,r){var e=(/MSIE/.test(navigator.userAgent)&&!window.opera);if(e){return"&mdash;"}if(!s||s.length<=1){return'<div style="display: inline-block; position: relative; bottom: .5ex; padding-left: 1em; height: 1px; border-bottom: 2px solid '+h+';"></div>'}var l,k,f,o;var g=0,q=0;var p=[];var n;for(l=0;l<=s.length;l++){g+=s[l%s.length]}n=Math.floor(r/(g-s[0]));if(n>1){for(l=0;l<s.length;l++){p[l]=s[l]/r}q=p.length}else{n=1;for(l=0;l<s.length;l++){p[l]=s[l]/g}q=p.length+1}var m="";for(k=0;k<n;k++){for(l=0;l<q;l+=2){f=p[l%p.length];if(l<s.length){o=p[(l+1)%p.length]}else{o=0}m+='<div style="display: inline-block; position: relative; bottom: .5ex; margin-right: '+o+"em; padding-left: "+f+"em; height: 1px; border-bottom: 2px solid "+h+';"></div>'}}return m};return c})();Dygraph.PLUGINS.push(Dygraph.Plugins.Legend,Dygraph.Plugins.Axes,Dygraph.Plugins.ChartLabels,Dygraph.Plugins.Annotations,Dygraph.Plugins.Grid); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/fancybox/blank.gif b/SemanticResultFormats/resources/jquery/fancybox/blank.gif
new file mode 100644
index 00000000..35d42e80
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/blank.gif
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/closelabel.gif b/SemanticResultFormats/resources/jquery/fancybox/closelabel.gif
new file mode 100644
index 00000000..87b4f8bd
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/closelabel.gif
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_close.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_close.png
new file mode 100644
index 00000000..07035307
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_close.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_loading.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_loading.png
new file mode 100644
index 00000000..25030179
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_loading.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_left.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_left.png
new file mode 100644
index 00000000..ebaa6a4f
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_left.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_right.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_right.png
new file mode 100644
index 00000000..873294e9
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_nav_right.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_e.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_e.png
new file mode 100644
index 00000000..2eda0893
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_e.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_n.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_n.png
new file mode 100644
index 00000000..69aa10e2
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_n.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_ne.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_ne.png
new file mode 100644
index 00000000..79f6980a
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_ne.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_nw.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_nw.png
new file mode 100644
index 00000000..7182cd93
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_nw.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_s.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_s.png
new file mode 100644
index 00000000..d8858bfb
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_s.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_se.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_se.png
new file mode 100644
index 00000000..541e3ffd
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_se.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_sw.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_sw.png
new file mode 100644
index 00000000..b451689f
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_sw.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_w.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_w.png
new file mode 100644
index 00000000..8a4e4a88
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_shadow_w.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_title_left.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_title_left.png
new file mode 100644
index 00000000..6049223d
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_title_left.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_title_main.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_title_main.png
new file mode 100644
index 00000000..8044271f
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_title_main.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_title_over.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_title_over.png
new file mode 100644
index 00000000..d9f458f4
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_title_over.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancy_title_right.png b/SemanticResultFormats/resources/jquery/fancybox/fancy_title_right.png
new file mode 100644
index 00000000..e36d9db2
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancy_title_right.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancybox-x.png b/SemanticResultFormats/resources/jquery/fancybox/fancybox-x.png
new file mode 100644
index 00000000..c2130f86
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancybox-x.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancybox-y.png b/SemanticResultFormats/resources/jquery/fancybox/fancybox-y.png
new file mode 100644
index 00000000..7ef399b9
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancybox-y.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/fancybox.png b/SemanticResultFormats/resources/jquery/fancybox/fancybox.png
new file mode 100644
index 00000000..65e14f68
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/fancybox.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.css b/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.css
new file mode 100644
index 00000000..8fe0fbd5
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.css
@@ -0,0 +1,359 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+#fancybox-loading {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ width: 40px;
+ height: 40px;
+ margin-top: -20px;
+ margin-left: -20px;
+ cursor: pointer;
+ overflow: hidden;
+ z-index: 1104;
+ display: none;
+}
+
+#fancybox-loading div {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 40px;
+ height: 480px;
+ background-image: url('fancybox.png');
+}
+
+#fancybox-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ z-index: 1100;
+ display: none;
+}
+
+#fancybox-tmp {
+ padding: 0;
+ margin: 0;
+ border: 0;
+ overflow: auto;
+ display: none;
+}
+
+#fancybox-wrap {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: 20px;
+ z-index: 1101;
+ outline: none;
+ display: none;
+}
+
+#fancybox-outer {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ background: #fff;
+}
+
+#fancybox-content {
+ width: 0;
+ height: 0;
+ padding: 0;
+ outline: none;
+ position: relative;
+ overflow: hidden;
+ z-index: 1102;
+ border: 0px solid #fff;
+}
+
+#fancybox-hide-sel-frame {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: transparent;
+ z-index: 1101;
+}
+
+#fancybox-close {
+ position: absolute;
+ top: -15px;
+ right: -15px;
+ width: 30px;
+ height: 30px;
+ background: transparent url('fancybox.png') -40px 0px;
+ cursor: pointer;
+ z-index: 1103;
+ display: none;
+}
+
+#fancybox-error {
+ color: #444;
+ font: normal 12px/20px Arial;
+ padding: 14px;
+ margin: 0;
+}
+
+#fancybox-img {
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+ border: none;
+ outline: none;
+ line-height: 0;
+ vertical-align: top;
+}
+
+#fancybox-frame {
+ width: 100%;
+ height: 100%;
+ border: none;
+ display: block;
+}
+
+#fancybox-left, #fancybox-right {
+ position: absolute;
+ bottom: 0px;
+ height: 100%;
+ width: 35%;
+ cursor: pointer;
+ outline: none;
+ background: transparent url('blank.gif');
+ z-index: 1102;
+ display: none;
+}
+
+#fancybox-left {
+ left: 0px;
+}
+
+#fancybox-right {
+ right: 0px;
+}
+
+#fancybox-left-ico, #fancybox-right-ico {
+ position: absolute;
+ top: 50%;
+ left: -9999px;
+ width: 30px;
+ height: 30px;
+ margin-top: -15px;
+ cursor: pointer;
+ z-index: 1102;
+ display: block;
+}
+
+#fancybox-left-ico {
+ background-image: url('fancybox.png');
+ background-position: -40px -30px;
+}
+
+#fancybox-right-ico {
+ background-image: url('fancybox.png');
+ background-position: -40px -60px;
+}
+
+#fancybox-left:hover, #fancybox-right:hover {
+ visibility: visible; /* IE6 */
+}
+
+#fancybox-left:hover span {
+ left: 20px;
+}
+
+#fancybox-right:hover span {
+ left: auto;
+ right: 20px;
+}
+
+.fancybox-bg {
+ position: absolute;
+ padding: 0;
+ margin: 0;
+ border: 0;
+ width: 20px;
+ height: 20px;
+ z-index: 1001;
+}
+
+#fancybox-bg-n {
+ top: -20px;
+ left: 0;
+ width: 100%;
+ background-image: url('fancybox-x.png');
+}
+
+#fancybox-bg-ne {
+ top: -20px;
+ right: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -162px;
+}
+
+#fancybox-bg-e {
+ top: 0;
+ right: -20px;
+ height: 100%;
+ background-image: url('fancybox-y.png');
+ background-position: -20px 0px;
+}
+
+#fancybox-bg-se {
+ bottom: -20px;
+ right: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -182px;
+}
+
+#fancybox-bg-s {
+ bottom: -20px;
+ left: 0;
+ width: 100%;
+ background-image: url('fancybox-x.png');
+ background-position: 0px -20px;
+}
+
+#fancybox-bg-sw {
+ bottom: -20px;
+ left: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -142px;
+}
+
+#fancybox-bg-w {
+ top: 0;
+ left: -20px;
+ height: 100%;
+ background-image: url('fancybox-y.png');
+}
+
+#fancybox-bg-nw {
+ top: -20px;
+ left: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -122px;
+}
+
+#fancybox-title {
+ font-family: Helvetica;
+ font-size: 12px;
+ z-index: 1102;
+}
+
+.fancybox-title-inside {
+ padding-bottom: 10px;
+ text-align: center;
+ color: #333;
+ background: #fff;
+ position: relative;
+}
+
+.fancybox-title-outside {
+ padding-top: 10px;
+ color: #fff;
+}
+
+.fancybox-title-over {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ color: #FFF;
+ text-align: left;
+}
+
+#fancybox-title-over {
+ padding: 10px;
+ background-image: url('fancy_title_over.png');
+ display: block;
+}
+
+.fancybox-title-float {
+ position: absolute;
+ left: 0;
+ bottom: -20px;
+ height: 32px;
+}
+
+#fancybox-title-float-wrap {
+ border: none;
+ border-collapse: collapse;
+ width: auto;
+}
+
+#fancybox-title-float-wrap td {
+ border: none;
+ white-space: nowrap;
+}
+
+#fancybox-title-float-left {
+ padding: 0 0 0 15px;
+ background: url('fancybox.png') -40px -90px no-repeat;
+}
+
+#fancybox-title-float-main {
+ color: #FFF;
+ line-height: 29px;
+ font-weight: bold;
+ padding: 0 0 3px 0;
+ background: url('fancybox-x.png') 0px -40px;
+}
+
+#fancybox-title-float-right {
+ padding: 0 0 0 15px;
+ background: url('fancybox.png') -55px -90px no-repeat;
+}
+
+/* IE6 */
+
+.fancybox-ie6 #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_close.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_left.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_right.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }
+.fancybox-ie6 #fancybox-title-float-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_left.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-title-float-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_main.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-title-float-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_right.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-bg-w, .fancybox-ie6 #fancybox-bg-e, .fancybox-ie6 #fancybox-left, .fancybox-ie6 #fancybox-right, #fancybox-hide-sel-frame {
+ height: expression(this.parentNode.clientHeight + "px");
+}
+
+#fancybox-loading.fancybox-ie6 {
+ position: absolute; margin-top: 0;
+ top: expression( (-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px');
+}
+
+#fancybox-loading.fancybox-ie6 div { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_loading.png', sizingMethod='scale'); }
+
+/* IE6, IE7, IE8 */
+
+.fancybox-ie .fancybox-bg { background: transparent !important; }
+
+.fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); } \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.pack.js b/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.pack.js
new file mode 100644
index 00000000..1373ed08
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fancybox/jquery.fancybox-1.3.4.pack.js
@@ -0,0 +1,46 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+;(function(b){var m,t,u,f,D,j,E,n,z,A,q=0,e={},o=[],p=0,d={},l=[],G=null,v=new Image,J=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,W=/[^\.]\.(swf)\s*$/i,K,L=1,y=0,s="",r,i,h=false,B=b.extend(b("<div/>")[0],{prop:0}),M=b.browser.msie&&b.browser.version<7&&!window.XMLHttpRequest,N=function(){t.hide();v.onerror=v.onload=null;G&&G.abort();m.empty()},O=function(){if(false===e.onError(o,q,e)){t.hide();h=false}else{e.titleShow=false;e.width="auto";e.height="auto";m.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>');
+F()}},I=function(){var a=o[q],c,g,k,C,P,w;N();e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));w=e.onStart(o,q,e);if(w===false)h=false;else{if(typeof w=="object")e=b.extend(e,w);k=e.title||(a.nodeName?b(a).attr("title"):a.title)||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(k===""&&e.orig&&e.titleFromAlt)k=e.orig.attr("alt");c=e.href||(a.nodeName?b(a).attr("href"):a.href)||null;if(/^(?:javascript)/i.test(c)||
+c=="#")c=null;if(e.type){g=e.type;if(!c)c=e.content}else if(e.content)g="html";else if(c)g=c.match(J)?"image":c.match(W)?"swf":b(a).hasClass("iframe")?"iframe":c.indexOf("#")===0?"inline":"ajax";if(g){if(g=="inline"){a=c.substr(c.indexOf("#"));g=b(a).length>0?"inline":"ajax"}e.type=g;e.href=c;e.title=k;if(e.autoDimensions)if(e.type=="html"||e.type=="inline"||e.type=="ajax"){e.width="auto";e.height="auto"}else e.autoDimensions=false;if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=
+false;e.enableEscapeButton=false;e.showCloseButton=false}e.padding=parseInt(e.padding,10);e.margin=parseInt(e.margin,10);m.css("padding",e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(j.children())});switch(g){case "html":m.html(e.content);F();break;case "inline":if(b(a).parent().is("#fancybox-content")===true){h=false;break}b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(j.children())}).bind("fancybox-cancel",
+function(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case "image":h=false;b.fancybox.showActivity();v=new Image;v.onerror=function(){O()};v.onload=function(){h=true;v.onerror=v.onload=null;e.width=v.width;e.height=v.height;b("<img />").attr({id:"fancybox-img",src:v.src,alt:e.title}).appendTo(m);Q()};v.src=c;break;case "swf":e.scrolling="no";C='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+c+
+'"></param>';P="";b.each(e.swf,function(x,H){C+='<param name="'+x+'" value="'+H+'"></param>';P+=" "+x+'="'+H+'"'});C+='<embed src="'+c+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+P+"></embed></object>";m.html(C);F();break;case "ajax":h=false;b.fancybox.showActivity();e.ajax.win=e.ajax.success;G=b.ajax(b.extend({},e.ajax,{url:c,data:e.ajax.data||{},error:function(x){x.status>0&&O()},success:function(x,H,R){if((typeof R=="object"?R:G).status==200){if(typeof e.ajax.win==
+"function"){w=e.ajax.win(c,x,H,R);if(w===false){t.hide();return}else if(typeof w=="string"||typeof w=="object")x=w}m.html(x);F()}}}));break;case "iframe":Q()}}else O()}},F=function(){var a=e.width,c=e.height;a=a.toString().indexOf("%")>-1?parseInt((b(window).width()-e.margin*2)*parseFloat(a)/100,10)+"px":a=="auto"?"auto":a+"px";c=c.toString().indexOf("%")>-1?parseInt((b(window).height()-e.margin*2)*parseFloat(c)/100,10)+"px":c=="auto"?"auto":c+"px";m.wrapInner('<div style="width:'+a+";height:"+c+
+";overflow: "+(e.scrolling=="auto"?"auto":e.scrolling=="yes"?"scroll":"hidden")+';position:relative;"></div>');e.width=m.width();e.height=m.height();Q()},Q=function(){var a,c;t.hide();if(f.is(":visible")&&false===d.onCleanup(l,p,d)){b.event.trigger("fancybox-cancel");h=false}else{h=true;b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");f.is(":visible")&&d.titlePosition!=="outside"&&f.css("height",f.height());l=o;p=q;d=e;if(d.overlayShow){u.css({"background-color":d.overlayColor,
+opacity:d.overlayOpacity,cursor:d.hideOnOverlayClick?"pointer":"auto",height:b(document).height()});if(!u.is(":visible")){M&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});u.show()}}else u.hide();i=X();s=d.title||"";y=0;n.empty().removeAttr("style").removeClass();if(d.titleShow!==false){if(b.isFunction(d.titleFormat))a=d.titleFormat(s,l,p,d);else a=s&&s.length?
+d.titlePosition=="float"?'<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">'+s+'</td><td id="fancybox-title-float-right"></td></tr></table>':'<div id="fancybox-title-'+d.titlePosition+'">'+s+"</div>":false;s=a;if(!(!s||s==="")){n.addClass("fancybox-title-"+d.titlePosition).html(s).appendTo("body").show();switch(d.titlePosition){case "inside":n.css({width:i.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding});
+y=n.outerHeight(true);n.appendTo(D);i.height+=y;break;case "over":n.css({marginLeft:d.padding,width:i.width-d.padding*2,bottom:d.padding}).appendTo(D);break;case "float":n.css("left",parseInt((n.width()-i.width-40)/2,10)*-1).appendTo(f);break;default:n.css({width:i.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f)}}}n.hide();if(f.is(":visible")){b(E.add(z).add(A)).hide();a=f.position();r={top:a.top,left:a.left,width:f.width(),height:f.height()};c=r.width==i.width&&r.height==
+i.height;j.fadeTo(d.changeFade,0.3,function(){var g=function(){j.html(m.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger("fancybox-change");j.empty().removeAttr("filter").css({"border-width":d.padding,width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2});if(c)g();else{B.prop=0;b(B).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:g})}})}else{f.removeAttr("style");j.css("border-width",d.padding);if(d.transitionIn=="elastic"){r=V();j.html(m.contents());
+f.show();if(d.opacity)i.opacity=0;B.prop=0;b(B).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition=="inside"&&y>0&&n.show();j.css({width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2}).html(m.contents());f.css(i).fadeIn(d.transitionIn=="none"?0:d.speedIn,S)}}}},Y=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind("keydown.fb",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if((a.keyCode==
+37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!=="INPUT"&&a.target.tagName!=="TEXTAREA"&&a.target.tagName!=="SELECT"){a.preventDefault();b.fancybox[a.keyCode==37?"prev":"next"]()}});if(d.showNavArrows){if(d.cyclic&&l.length>1||p!==0)z.show();if(d.cyclic&&l.length>1||p!=l.length-1)A.show()}else{z.hide();A.hide()}},S=function(){if(!b.support.opacity){j.get(0).style.removeAttribute("filter");f.get(0).style.removeAttribute("filter")}e.autoDimensions&&j.css("height","auto");f.css("height","auto");
+s&&s.length&&n.show();d.showCloseButton&&E.show();Y();d.hideOnContentClick&&j.bind("click",b.fancybox.close);d.hideOnOverlayClick&&u.bind("click",b.fancybox.close);b(window).bind("resize.fb",b.fancybox.resize);d.centerOnScroll&&b(window).bind("scroll.fb",b.fancybox.center);if(d.type=="iframe")b('<iframe id="fancybox-frame" name="fancybox-frame'+(new Date).getTime()+'" frameborder="0" hspace="0" '+(b.browser.msie?'allowtransparency="true""':"")+' scrolling="'+e.scrolling+'" src="'+d.href+'"></iframe>').appendTo(j);
+f.show();h=false;b.fancybox.center();d.onComplete(l,p,d);var a,c;if(l.length-1>p){a=l[p+1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}if(p>0){a=l[p-1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(r.width+(i.width-r.width)*a,10),height:parseInt(r.height+(i.height-r.height)*a,10),top:parseInt(r.top+(i.top-r.top)*a,10),left:parseInt(r.left+(i.left-r.left)*a,10)};if(typeof i.opacity!=="undefined")c.opacity=a<0.5?0.5:a;f.css(c);
+j.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},X=function(){var a=U(),c={},g=d.autoScale,k=d.padding*2;c.width=d.width.toString().indexOf("%")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+k;c.height=d.height.toString().indexOf("%")>-1?parseInt(a[1]*parseFloat(d.height)/100,10):d.height+k;if(g&&(c.width>a[0]||c.height>a[1]))if(e.type==
+"image"||e.type=="swf"){g=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-k)/g+k,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-k)*g+k,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){c=a.offset();c.top+=parseInt(a.css("paddingTop"),
+10)||0;c.left+=parseInt(a.css("paddingLeft"),10)||0;c.top+=parseInt(a.css("border-top-width"),10)||0;c.left+=parseInt(a.css("border-left-width"),10)||0;c.width=a.width();c.height=a.height();c={width:c.width+d.padding*2,height:c.height+d.padding*2,top:c.top-d.padding-20,left:c.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+a[0]*0.5,10)}}return c},Z=function(){if(t.is(":visible")){b("div",t).css("top",L*-40+"px");L=(L+1)%12}else clearInterval(K)};
+b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr("rel")||"";if(!c||c==""||c==="nofollow")o.push(this);else{o=b("a[rel="+c+"], area[rel="+c+"]");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!=="undefined"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k=
+0,C=a.length;k<C;k++)if(typeof a[k]=="object")b(a[k]).data("fancybox",b.extend({},g,a[k]));else a[k]=b({}).data("fancybox",b.extend({content:a[k]},g));o=jQuery.merge(o,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},g,a));else a=b({}).data("fancybox",b.extend({content:a},g));o.push(a)}if(q>o.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+
+1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a<l.length){q=a;I()}else if(d.cyclic&&l.length>1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut("fast");n.empty().hide();f.hide();b.event.trigger("fancybox-cleanup");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(":hidden"))){h=
+true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1;
+b(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(":visible")&&u.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5-
+d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('<div id="fancybox-tmp"></div>'),t=b('<div id="fancybox-loading"><div></div></div>'),u=b('<div id="fancybox-overlay"></div>'),f=b('<div id="fancybox-wrap"></div>'));D=b('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(f);
+D.append(j=b('<div id="fancybox-content"></div>'),E=b('<a id="fancybox-close"></a>'),n=b('<div id="fancybox-title"></div>'),z=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),A=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()});
+b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(D)}}};
+b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",
+easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/flot/jquery.flot.js b/SemanticResultFormats/resources/jquery/flot/jquery.flot.js
new file mode 100644
index 00000000..ccf380dd
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/flot/jquery.flot.js
@@ -0,0 +1,2605 @@
+/*! Javascript plotting library for jQuery, v. 0.7.
+ *
+ * Released under the MIT license by IOLA, December 2007.
+ *
+ */
+
+// first an inline dependency, jquery.colorhelpers.js, we inline it here
+// for convenience
+
+/* Plugin for jQuery for working with colors.
+ *
+ * Version 1.1.
+ *
+ * Inspiration from jQuery color animation plugin by John Resig.
+ *
+ * Released under the MIT license by Ole Laursen, October 2009.
+ *
+ * Examples:
+ *
+ * $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString()
+ * var c = $.color.extract($("#mydiv"), 'background-color');
+ * console.log(c.r, c.g, c.b, c.a);
+ * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"
+ *
+ * Note that .scale() and .add() return the same modified object
+ * instead of making a new one.
+ *
+ * V. 1.1: Fix error handling so e.g. parsing an empty string does
+ * produce a color rather than just crashing.
+ */
+(function(B){B.color={};B.color.make=function(F,E,C,D){var G={};G.r=F||0;G.g=E||0;G.b=C||0;G.a=D!=null?D:1;G.add=function(J,I){for(var H=0;H<J.length;++H){G[J.charAt(H)]+=I}return G.normalize()};G.scale=function(J,I){for(var H=0;H<J.length;++H){G[J.charAt(H)]*=I}return G.normalize()};G.toString=function(){if(G.a>=1){return"rgb("+[G.r,G.g,G.b].join(",")+")"}else{return"rgba("+[G.r,G.g,G.b,G.a].join(",")+")"}};G.normalize=function(){function H(J,K,I){return K<J?J:(K>I?I:K)}G.r=H(0,parseInt(G.r),255);G.g=H(0,parseInt(G.g),255);G.b=H(0,parseInt(G.b),255);G.a=H(0,G.a,1);return G};G.clone=function(){return B.color.make(G.r,G.b,G.g,G.a)};return G.normalize()};B.color.extract=function(D,C){var E;do{E=D.css(C).toLowerCase();if(E!=""&&E!="transparent"){break}D=D.parent()}while(!B.nodeName(D.get(0),"body"));if(E=="rgba(0, 0, 0, 0)"){E="transparent"}return B.color.parse(E)};B.color.parse=function(F){var E,C=B.color.make;if(E=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(F)){return C(parseInt(E[1],10),parseInt(E[2],10),parseInt(E[3],10))}if(E=/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(F)){return C(parseInt(E[1],10),parseInt(E[2],10),parseInt(E[3],10),parseFloat(E[4]))}if(E=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(F)){return C(parseFloat(E[1])*2.55,parseFloat(E[2])*2.55,parseFloat(E[3])*2.55)}if(E=/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(F)){return C(parseFloat(E[1])*2.55,parseFloat(E[2])*2.55,parseFloat(E[3])*2.55,parseFloat(E[4]))}if(E=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(F)){return C(parseInt(E[1],16),parseInt(E[2],16),parseInt(E[3],16))}if(E=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(F)){return C(parseInt(E[1]+E[1],16),parseInt(E[2]+E[2],16),parseInt(E[3]+E[3],16))}var D=B.trim(F).toLowerCase();if(D=="transparent"){return C(255,255,255,0)}else{E=A[D]||[0,0,0];return C(E[0],E[1],E[2])}};var A={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);
+
+// the actual Flot code
+(function($) {
+ function Plot(placeholder, data_, options_, plugins) {
+ // data is on the form:
+ // [ series1, series2 ... ]
+ // where series is either just the data as [ [x1, y1], [x2, y2], ... ]
+ // or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... }
+
+ var series = [],
+ options = {
+ // the color theme used for graphs
+ colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"],
+ legend: {
+ show: true,
+ noColumns: 1, // number of colums in legend table
+ labelFormatter: null, // fn: string -> string
+ labelBoxBorderColor: "#ccc", // border color for the little label boxes
+ container: null, // container (as jQuery object) to put legend in, null means default on top of graph
+ position: "ne", // position of default legend container within plot
+ margin: 5, // distance from grid edge to default legend container within plot
+ backgroundColor: null, // null means auto-detect
+ backgroundOpacity: 0.85 // set to 0 to avoid background
+ },
+ xaxis: {
+ show: null, // null = auto-detect, true = always, false = never
+ position: "bottom", // or "top"
+ mode: null, // null or "time"
+ color: null, // base color, labels, ticks
+ tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)"
+ transform: null, // null or f: number -> number to transform axis
+ inverseTransform: null, // if transform is set, this should be the inverse function
+ min: null, // min. value to show, null means set automatically
+ max: null, // max. value to show, null means set automatically
+ autoscaleMargin: null, // margin in % to add if auto-setting min/max
+ ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks
+ tickFormatter: null, // fn: number -> string
+ labelWidth: null, // size of tick labels in pixels
+ labelHeight: null,
+ reserveSpace: null, // whether to reserve space even if axis isn't shown
+ tickLength: null, // size in pixels of ticks, or "full" for whole line
+ alignTicksWithAxis: null, // axis number or null for no sync
+
+ // mode specific options
+ tickDecimals: null, // no. of decimals, null means auto
+ tickSize: null, // number or [number, "unit"]
+ minTickSize: null, // number or [number, "unit"]
+ monthNames: null, // list of names of months
+ timeformat: null, // format string to use
+ twelveHourClock: false // 12 or 24 time in time mode
+ },
+ yaxis: {
+ autoscaleMargin: 0.02,
+ position: "left" // or "right"
+ },
+ xaxes: [],
+ yaxes: [],
+ series: {
+ points: {
+ show: false,
+ radius: 3,
+ lineWidth: 2, // in pixels
+ fill: true,
+ fillColor: "#ffffff",
+ symbol: "circle" // or callback
+ },
+ lines: {
+ // we don't put in show: false so we can see
+ // whether lines were actively disabled
+ lineWidth: 2, // in pixels
+ fill: false,
+ fillColor: null,
+ steps: false
+ },
+ bars: {
+ show: false,
+ lineWidth: 2, // in pixels
+ barWidth: 1, // in units of the x axis
+ fill: true,
+ fillColor: null,
+ align: "left", // or "center"
+ horizontal: false
+ },
+ shadowSize: 3
+ },
+ grid: {
+ show: true,
+ aboveData: false,
+ color: "#545454", // primary color used for outline and labels
+ backgroundColor: null, // null for transparent, else color
+ borderColor: null, // set if different from the grid color
+ tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)"
+ labelMargin: 5, // in pixels
+ axisMargin: 8, // in pixels
+ borderWidth: 2, // in pixels
+ minBorderMargin: null, // in pixels, null means taken from points radius
+ markings: null, // array of ranges or fn: axes -> array of ranges
+ markingsColor: "#f4f4f4",
+ markingsLineWidth: 2,
+ // interactive stuff
+ clickable: false,
+ hoverable: false,
+ autoHighlight: true, // highlight in case mouse is near
+ mouseActiveRadius: 10 // how far the mouse can be away to activate an item
+ },
+ hooks: {}
+ },
+ canvas = null, // the canvas for the plot itself
+ overlay = null, // canvas for interactive stuff on top of plot
+ eventHolder = null, // jQuery object that events should be bound to
+ ctx = null, octx = null,
+ xaxes = [], yaxes = [],
+ plotOffset = { left: 0, right: 0, top: 0, bottom: 0},
+ canvasWidth = 0, canvasHeight = 0,
+ plotWidth = 0, plotHeight = 0,
+ hooks = {
+ processOptions: [],
+ processRawData: [],
+ processDatapoints: [],
+ drawSeries: [],
+ draw: [],
+ bindEvents: [],
+ drawOverlay: [],
+ shutdown: []
+ },
+ plot = this;
+
+ // public functions
+ plot.setData = setData;
+ plot.setupGrid = setupGrid;
+ plot.draw = draw;
+ plot.getPlaceholder = function() { return placeholder; };
+ plot.getCanvas = function() { return canvas; };
+ plot.getPlotOffset = function() { return plotOffset; };
+ plot.width = function () { return plotWidth; };
+ plot.height = function () { return plotHeight; };
+ plot.offset = function () {
+ var o = eventHolder.offset();
+ o.left += plotOffset.left;
+ o.top += plotOffset.top;
+ return o;
+ };
+ plot.getData = function () { return series; };
+ plot.getAxes = function () {
+ var res = {}, i;
+ $.each(xaxes.concat(yaxes), function (_, axis) {
+ if (axis)
+ res[axis.direction + (axis.n != 1 ? axis.n : "") + "axis"] = axis;
+ });
+ return res;
+ };
+ plot.getXAxes = function () { return xaxes; };
+ plot.getYAxes = function () { return yaxes; };
+ plot.c2p = canvasToAxisCoords;
+ plot.p2c = axisToCanvasCoords;
+ plot.getOptions = function () { return options; };
+ plot.highlight = highlight;
+ plot.unhighlight = unhighlight;
+ plot.triggerRedrawOverlay = triggerRedrawOverlay;
+ plot.pointOffset = function(point) {
+ return {
+ left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left),
+ top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top)
+ };
+ };
+ plot.shutdown = shutdown;
+ plot.resize = function () {
+ getCanvasDimensions();
+ resizeCanvas(canvas);
+ resizeCanvas(overlay);
+ };
+
+ // public attributes
+ plot.hooks = hooks;
+
+ // initialize
+ initPlugins(plot);
+ parseOptions(options_);
+ setupCanvases();
+ setData(data_);
+ setupGrid();
+ draw();
+ bindEvents();
+
+
+ function executeHooks(hook, args) {
+ args = [plot].concat(args);
+ for (var i = 0; i < hook.length; ++i)
+ hook[i].apply(this, args);
+ }
+
+ function initPlugins() {
+ for (var i = 0; i < plugins.length; ++i) {
+ var p = plugins[i];
+ p.init(plot);
+ if (p.options)
+ $.extend(true, options, p.options);
+ }
+ }
+
+ function parseOptions(opts) {
+ var i;
+
+ $.extend(true, options, opts);
+
+ if (options.xaxis.color == null)
+ options.xaxis.color = options.grid.color;
+ if (options.yaxis.color == null)
+ options.yaxis.color = options.grid.color;
+
+ if (options.xaxis.tickColor == null) // backwards-compatibility
+ options.xaxis.tickColor = options.grid.tickColor;
+ if (options.yaxis.tickColor == null) // backwards-compatibility
+ options.yaxis.tickColor = options.grid.tickColor;
+
+ if (options.grid.borderColor == null)
+ options.grid.borderColor = options.grid.color;
+ if (options.grid.tickColor == null)
+ options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString();
+
+ // fill in defaults in axes, copy at least always the
+ // first as the rest of the code assumes it'll be there
+ for (i = 0; i < Math.max(1, options.xaxes.length); ++i)
+ options.xaxes[i] = $.extend(true, {}, options.xaxis, options.xaxes[i]);
+ for (i = 0; i < Math.max(1, options.yaxes.length); ++i)
+ options.yaxes[i] = $.extend(true, {}, options.yaxis, options.yaxes[i]);
+
+ // backwards compatibility, to be removed in future
+ if (options.xaxis.noTicks && options.xaxis.ticks == null)
+ options.xaxis.ticks = options.xaxis.noTicks;
+ if (options.yaxis.noTicks && options.yaxis.ticks == null)
+ options.yaxis.ticks = options.yaxis.noTicks;
+ if (options.x2axis) {
+ options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis);
+ options.xaxes[1].position = "top";
+ }
+ if (options.y2axis) {
+ options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis);
+ options.yaxes[1].position = "right";
+ }
+ if (options.grid.coloredAreas)
+ options.grid.markings = options.grid.coloredAreas;
+ if (options.grid.coloredAreasColor)
+ options.grid.markingsColor = options.grid.coloredAreasColor;
+ if (options.lines)
+ $.extend(true, options.series.lines, options.lines);
+ if (options.points)
+ $.extend(true, options.series.points, options.points);
+ if (options.bars)
+ $.extend(true, options.series.bars, options.bars);
+ if (options.shadowSize != null)
+ options.series.shadowSize = options.shadowSize;
+
+ // save options on axes for future reference
+ for (i = 0; i < options.xaxes.length; ++i)
+ getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i];
+ for (i = 0; i < options.yaxes.length; ++i)
+ getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i];
+
+ // add hooks from options
+ for (var n in hooks)
+ if (options.hooks[n] && options.hooks[n].length)
+ hooks[n] = hooks[n].concat(options.hooks[n]);
+
+ executeHooks(hooks.processOptions, [options]);
+ }
+
+ function setData(d) {
+ series = parseData(d);
+ fillInSeriesOptions();
+ processData();
+ }
+
+ function parseData(d) {
+ var res = [];
+ for (var i = 0; i < d.length; ++i) {
+ var s = $.extend(true, {}, options.series);
+
+ if (d[i].data != null) {
+ s.data = d[i].data; // move the data instead of deep-copy
+ delete d[i].data;
+
+ $.extend(true, s, d[i]);
+
+ d[i].data = s.data;
+ }
+ else
+ s.data = d[i];
+ res.push(s);
+ }
+
+ return res;
+ }
+
+ function axisNumber(obj, coord) {
+ var a = obj[coord + "axis"];
+ if (typeof a == "object") // if we got a real axis, extract number
+ a = a.n;
+ if (typeof a != "number")
+ a = 1; // default to first axis
+ return a;
+ }
+
+ function allAxes() {
+ // return flat array without annoying null entries
+ return $.grep(xaxes.concat(yaxes), function (a) { return a; });
+ }
+
+ function canvasToAxisCoords(pos) {
+ // return an object with x/y corresponding to all used axes
+ var res = {}, i, axis;
+ for (i = 0; i < xaxes.length; ++i) {
+ axis = xaxes[i];
+ if (axis && axis.used)
+ res["x" + axis.n] = axis.c2p(pos.left);
+ }
+
+ for (i = 0; i < yaxes.length; ++i) {
+ axis = yaxes[i];
+ if (axis && axis.used)
+ res["y" + axis.n] = axis.c2p(pos.top);
+ }
+
+ if (res.x1 !== undefined)
+ res.x = res.x1;
+ if (res.y1 !== undefined)
+ res.y = res.y1;
+
+ return res;
+ }
+
+ function axisToCanvasCoords(pos) {
+ // get canvas coords from the first pair of x/y found in pos
+ var res = {}, i, axis, key;
+
+ for (i = 0; i < xaxes.length; ++i) {
+ axis = xaxes[i];
+ if (axis && axis.used) {
+ key = "x" + axis.n;
+ if (pos[key] == null && axis.n == 1)
+ key = "x";
+
+ if (pos[key] != null) {
+ res.left = axis.p2c(pos[key]);
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < yaxes.length; ++i) {
+ axis = yaxes[i];
+ if (axis && axis.used) {
+ key = "y" + axis.n;
+ if (pos[key] == null && axis.n == 1)
+ key = "y";
+
+ if (pos[key] != null) {
+ res.top = axis.p2c(pos[key]);
+ break;
+ }
+ }
+ }
+
+ return res;
+ }
+
+ function getOrCreateAxis(axes, number) {
+ if (!axes[number - 1])
+ axes[number - 1] = {
+ n: number, // save the number for future reference
+ direction: axes == xaxes ? "x" : "y",
+ options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis)
+ };
+
+ return axes[number - 1];
+ }
+
+ function fillInSeriesOptions() {
+ var i;
+
+ // collect what we already got of colors
+ var neededColors = series.length,
+ usedColors = [],
+ assignedColors = [];
+ for (i = 0; i < series.length; ++i) {
+ var sc = series[i].color;
+ if (sc != null) {
+ --neededColors;
+ if (typeof sc == "number")
+ assignedColors.push(sc);
+ else
+ usedColors.push($.color.parse(series[i].color));
+ }
+ }
+
+ // we might need to generate more colors if higher indices
+ // are assigned
+ for (i = 0; i < assignedColors.length; ++i) {
+ neededColors = Math.max(neededColors, assignedColors[i] + 1);
+ }
+
+ // produce colors as needed
+ var colors = [], variation = 0;
+ i = 0;
+ while (colors.length < neededColors) {
+ var c;
+ if (options.colors.length == i) // check degenerate case
+ c = $.color.make(100, 100, 100);
+ else
+ c = $.color.parse(options.colors[i]);
+
+ // vary color if needed
+ var sign = variation % 2 == 1 ? -1 : 1;
+ c.scale('rgb', 1 + sign * Math.ceil(variation / 2) * 0.2)
+
+ // FIXME: if we're getting to close to something else,
+ // we should probably skip this one
+ colors.push(c);
+
+ ++i;
+ if (i >= options.colors.length) {
+ i = 0;
+ ++variation;
+ }
+ }
+
+ // fill in the options
+ var colori = 0, s;
+ for (i = 0; i < series.length; ++i) {
+ s = series[i];
+
+ // assign colors
+ if (s.color == null) {
+ s.color = colors[colori].toString();
+ ++colori;
+ }
+ else if (typeof s.color == "number")
+ s.color = colors[s.color].toString();
+
+ // turn on lines automatically in case nothing is set
+ if (s.lines.show == null) {
+ var v, show = true;
+ for (v in s)
+ if (s[v] && s[v].show) {
+ show = false;
+ break;
+ }
+ if (show)
+ s.lines.show = true;
+ }
+
+ // setup axes
+ s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x"));
+ s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y"));
+ }
+ }
+
+ function processData() {
+ var topSentry = Number.POSITIVE_INFINITY,
+ bottomSentry = Number.NEGATIVE_INFINITY,
+ fakeInfinity = Number.MAX_VALUE,
+ i, j, k, m, length,
+ s, points, ps, x, y, axis, val, f, p;
+
+ function updateAxis(axis, min, max) {
+ if (min < axis.datamin && min != -fakeInfinity)
+ axis.datamin = min;
+ if (max > axis.datamax && max != fakeInfinity)
+ axis.datamax = max;
+ }
+
+ $.each(allAxes(), function (_, axis) {
+ // init axis
+ axis.datamin = topSentry;
+ axis.datamax = bottomSentry;
+ axis.used = false;
+ });
+
+ for (i = 0; i < series.length; ++i) {
+ s = series[i];
+ s.datapoints = { points: [] };
+
+ executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]);
+ }
+
+ // first pass: clean and copy data
+ for (i = 0; i < series.length; ++i) {
+ s = series[i];
+
+ var data = s.data, format = s.datapoints.format;
+
+ if (!format) {
+ format = [];
+ // find out how to copy
+ format.push({ x: true, number: true, required: true });
+ format.push({ y: true, number: true, required: true });
+
+ if (s.bars.show || (s.lines.show && s.lines.fill)) {
+ format.push({ y: true, number: true, required: false, defaultValue: 0 });
+ if (s.bars.horizontal) {
+ delete format[format.length - 1].y;
+ format[format.length - 1].x = true;
+ }
+ }
+
+ s.datapoints.format = format;
+ }
+
+ if (s.datapoints.pointsize != null)
+ continue; // already filled in
+
+ s.datapoints.pointsize = format.length;
+
+ ps = s.datapoints.pointsize;
+ points = s.datapoints.points;
+
+ insertSteps = s.lines.show && s.lines.steps;
+ s.xaxis.used = s.yaxis.used = true;
+
+ for (j = k = 0; j < data.length; ++j, k += ps) {
+ p = data[j];
+
+ var nullify = p == null;
+ if (!nullify) {
+ for (m = 0; m < ps; ++m) {
+ val = p[m];
+ f = format[m];
+
+ if (f) {
+ if (f.number && val != null) {
+ val = +val; // convert to number
+ if (isNaN(val))
+ val = null;
+ else if (val == Infinity)
+ val = fakeInfinity;
+ else if (val == -Infinity)
+ val = -fakeInfinity;
+ }
+
+ if (val == null) {
+ if (f.required)
+ nullify = true;
+
+ if (f.defaultValue != null)
+ val = f.defaultValue;
+ }
+ }
+
+ points[k + m] = val;
+ }
+ }
+
+ if (nullify) {
+ for (m = 0; m < ps; ++m) {
+ val = points[k + m];
+ if (val != null) {
+ f = format[m];
+ // extract min/max info
+ if (f.x)
+ updateAxis(s.xaxis, val, val);
+ if (f.y)
+ updateAxis(s.yaxis, val, val);
+ }
+ points[k + m] = null;
+ }
+ }
+ else {
+ // a little bit of line specific stuff that
+ // perhaps shouldn't be here, but lacking
+ // better means...
+ if (insertSteps && k > 0
+ && points[k - ps] != null
+ && points[k - ps] != points[k]
+ && points[k - ps + 1] != points[k + 1]) {
+ // copy the point to make room for a middle point
+ for (m = 0; m < ps; ++m)
+ points[k + ps + m] = points[k + m];
+
+ // middle point has same y
+ points[k + 1] = points[k - ps + 1];
+
+ // we've added a point, better reflect that
+ k += ps;
+ }
+ }
+ }
+ }
+
+ // give the hooks a chance to run
+ for (i = 0; i < series.length; ++i) {
+ s = series[i];
+
+ executeHooks(hooks.processDatapoints, [ s, s.datapoints]);
+ }
+
+ // second pass: find datamax/datamin for auto-scaling
+ for (i = 0; i < series.length; ++i) {
+ s = series[i];
+ points = s.datapoints.points,
+ ps = s.datapoints.pointsize;
+
+ var xmin = topSentry, ymin = topSentry,
+ xmax = bottomSentry, ymax = bottomSentry;
+
+ for (j = 0; j < points.length; j += ps) {
+ if (points[j] == null)
+ continue;
+
+ for (m = 0; m < ps; ++m) {
+ val = points[j + m];
+ f = format[m];
+ if (!f || val == fakeInfinity || val == -fakeInfinity)
+ continue;
+
+ if (f.x) {
+ if (val < xmin)
+ xmin = val;
+ if (val > xmax)
+ xmax = val;
+ }
+ if (f.y) {
+ if (val < ymin)
+ ymin = val;
+ if (val > ymax)
+ ymax = val;
+ }
+ }
+ }
+
+ if (s.bars.show) {
+ // make sure we got room for the bar on the dancing floor
+ var delta = s.bars.align == "left" ? 0 : -s.bars.barWidth/2;
+ if (s.bars.horizontal) {
+ ymin += delta;
+ ymax += delta + s.bars.barWidth;
+ }
+ else {
+ xmin += delta;
+ xmax += delta + s.bars.barWidth;
+ }
+ }
+
+ updateAxis(s.xaxis, xmin, xmax);
+ updateAxis(s.yaxis, ymin, ymax);
+ }
+
+ $.each(allAxes(), function (_, axis) {
+ if (axis.datamin == topSentry)
+ axis.datamin = null;
+ if (axis.datamax == bottomSentry)
+ axis.datamax = null;
+ });
+ }
+
+ function makeCanvas(skipPositioning, cls) {
+ var c = document.createElement('canvas');
+ c.className = cls;
+ c.width = canvasWidth;
+ c.height = canvasHeight;
+
+ if (!skipPositioning)
+ $(c).css({ position: 'absolute', left: 0, top: 0 });
+
+ $(c).appendTo(placeholder);
+
+ if (!c.getContext) // excanvas hack
+ c = window.G_vmlCanvasManager.initElement(c);
+
+ // used for resetting in case we get replotted
+ c.getContext("2d").save();
+
+ return c;
+ }
+
+ function getCanvasDimensions() {
+ canvasWidth = placeholder.width();
+ canvasHeight = placeholder.height();
+
+ if (canvasWidth <= 0 || canvasHeight <= 0)
+ throw "Invalid dimensions for plot, width = " + canvasWidth + ", height = " + canvasHeight;
+ }
+
+ function resizeCanvas(c) {
+ // resizing should reset the state (excanvas seems to be
+ // buggy though)
+ if (c.width != canvasWidth)
+ c.width = canvasWidth;
+
+ if (c.height != canvasHeight)
+ c.height = canvasHeight;
+
+ // so try to get back to the initial state (even if it's
+ // gone now, this should be safe according to the spec)
+ var cctx = c.getContext("2d");
+ cctx.restore();
+
+ // and save again
+ cctx.save();
+ }
+
+ function setupCanvases() {
+ var reused,
+ existingCanvas = placeholder.children("canvas.base"),
+ existingOverlay = placeholder.children("canvas.overlay");
+
+ if (existingCanvas.length == 0 || existingOverlay == 0) {
+ // init everything
+
+ placeholder.html(""); // make sure placeholder is clear
+
+ placeholder.css({ padding: 0 }); // padding messes up the positioning
+
+ if (placeholder.css("position") == 'static')
+ placeholder.css("position", "relative"); // for positioning labels and overlay
+
+ getCanvasDimensions();
+
+ canvas = makeCanvas(true, "base");
+ overlay = makeCanvas(false, "overlay"); // overlay canvas for interactive features
+
+ reused = false;
+ }
+ else {
+ // reuse existing elements
+
+ canvas = existingCanvas.get(0);
+ overlay = existingOverlay.get(0);
+
+ reused = true;
+ }
+
+ ctx = canvas.getContext("2d");
+ octx = overlay.getContext("2d");
+
+ // we include the canvas in the event holder too, because IE 7
+ // sometimes has trouble with the stacking order
+ eventHolder = $([overlay, canvas]);
+
+ if (reused) {
+ // run shutdown in the old plot object
+ placeholder.data("plot").shutdown();
+
+ // reset reused canvases
+ plot.resize();
+
+ // make sure overlay pixels are cleared (canvas is cleared when we redraw)
+ octx.clearRect(0, 0, canvasWidth, canvasHeight);
+
+ // then whack any remaining obvious garbage left
+ eventHolder.unbind();
+ placeholder.children().not([canvas, overlay]).remove();
+ }
+
+ // save in case we get replotted
+ placeholder.data("plot", plot);
+ }
+
+ function bindEvents() {
+ // bind events
+ if (options.grid.hoverable) {
+ eventHolder.mousemove(onMouseMove);
+ eventHolder.mouseleave(onMouseLeave);
+ }
+
+ if (options.grid.clickable)
+ eventHolder.click(onClick);
+
+ executeHooks(hooks.bindEvents, [eventHolder]);
+ }
+
+ function shutdown() {
+ if (redrawTimeout)
+ clearTimeout(redrawTimeout);
+
+ eventHolder.unbind("mousemove", onMouseMove);
+ eventHolder.unbind("mouseleave", onMouseLeave);
+ eventHolder.unbind("click", onClick);
+
+ executeHooks(hooks.shutdown, [eventHolder]);
+ }
+
+ function setTransformationHelpers(axis) {
+ // set helper functions on the axis, assumes plot area
+ // has been computed already
+
+ function identity(x) { return x; }
+
+ var s, m, t = axis.options.transform || identity,
+ it = axis.options.inverseTransform;
+
+ // precompute how much the axis is scaling a point
+ // in canvas space
+ if (axis.direction == "x") {
+ s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min));
+ m = Math.min(t(axis.max), t(axis.min));
+ }
+ else {
+ s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min));
+ s = -s;
+ m = Math.max(t(axis.max), t(axis.min));
+ }
+
+ // data point to canvas coordinate
+ if (t == identity) // slight optimization
+ axis.p2c = function (p) { return (p - m) * s; };
+ else
+ axis.p2c = function (p) { return (t(p) - m) * s; };
+ // canvas coordinate to data point
+ if (!it)
+ axis.c2p = function (c) { return m + c / s; };
+ else
+ axis.c2p = function (c) { return it(m + c / s); };
+ }
+
+ function measureTickLabels(axis) {
+ var opts = axis.options, i, ticks = axis.ticks || [], labels = [],
+ l, w = opts.labelWidth, h = opts.labelHeight, dummyDiv;
+
+ function makeDummyDiv(labels, width) {
+ return $('<div style="position:absolute;top:-10000px;' + width + 'font-size:smaller">' +
+ '<div class="' + axis.direction + 'Axis ' + axis.direction + axis.n + 'Axis">'
+ + labels.join("") + '</div></div>')
+ .appendTo(placeholder);
+ }
+
+ if (axis.direction == "x") {
+ // to avoid measuring the widths of the labels (it's slow), we
+ // construct fixed-size boxes and put the labels inside
+ // them, we don't need the exact figures and the
+ // fixed-size box content is easy to center
+ if (w == null)
+ w = Math.floor(canvasWidth / (ticks.length > 0 ? ticks.length : 1));
+
+ // measure x label heights
+ if (h == null) {
+ labels = [];
+ for (i = 0; i < ticks.length; ++i) {
+ l = ticks[i].label;
+ if (l)
+ labels.push('<div class="tickLabel" style="float:left;width:' + w + 'px">' + l + '</div>');
+ }
+
+ if (labels.length > 0) {
+ // stick them all in the same div and measure
+ // collective height
+ labels.push('<div style="clear:left"></div>');
+ dummyDiv = makeDummyDiv(labels, "width:10000px;");
+ h = dummyDiv.height();
+ dummyDiv.remove();
+ }
+ }
+ }
+ else if (w == null || h == null) {
+ // calculate y label dimensions
+ for (i = 0; i < ticks.length; ++i) {
+ l = ticks[i].label;
+ if (l)
+ labels.push('<div class="tickLabel">' + l + '</div>');
+ }
+
+ if (labels.length > 0) {
+ dummyDiv = makeDummyDiv(labels, "");
+ if (w == null)
+ w = dummyDiv.children().width();
+ if (h == null)
+ h = dummyDiv.find("div.tickLabel").height();
+ dummyDiv.remove();
+ }
+ }
+
+ if (w == null)
+ w = 0;
+ if (h == null)
+ h = 0;
+
+ axis.labelWidth = w;
+ axis.labelHeight = h;
+ }
+
+ function allocateAxisBoxFirstPhase(axis) {
+ // find the bounding box of the axis by looking at label
+ // widths/heights and ticks, make room by diminishing the
+ // plotOffset
+
+ var lw = axis.labelWidth,
+ lh = axis.labelHeight,
+ pos = axis.options.position,
+ tickLength = axis.options.tickLength,
+ axismargin = options.grid.axisMargin,
+ padding = options.grid.labelMargin,
+ all = axis.direction == "x" ? xaxes : yaxes,
+ index;
+
+ // determine axis margin
+ var samePosition = $.grep(all, function (a) {
+ return a && a.options.position == pos && a.reserveSpace;
+ });
+ if ($.inArray(axis, samePosition) == samePosition.length - 1)
+ axismargin = 0; // outermost
+
+ // determine tick length - if we're innermost, we can use "full"
+ if (tickLength == null)
+ tickLength = "full";
+
+ var sameDirection = $.grep(all, function (a) {
+ return a && a.reserveSpace;
+ });
+
+ var innermost = $.inArray(axis, sameDirection) == 0;
+ if (!innermost && tickLength == "full")
+ tickLength = 5;
+
+ if (!isNaN(+tickLength))
+ padding += +tickLength;
+
+ // compute box
+ if (axis.direction == "x") {
+ lh += padding;
+
+ if (pos == "bottom") {
+ plotOffset.bottom += lh + axismargin;
+ axis.box = { top: canvasHeight - plotOffset.bottom, height: lh };
+ }
+ else {
+ axis.box = { top: plotOffset.top + axismargin, height: lh };
+ plotOffset.top += lh + axismargin;
+ }
+ }
+ else {
+ lw += padding;
+
+ if (pos == "left") {
+ axis.box = { left: plotOffset.left + axismargin, width: lw };
+ plotOffset.left += lw + axismargin;
+ }
+ else {
+ plotOffset.right += lw + axismargin;
+ axis.box = { left: canvasWidth - plotOffset.right, width: lw };
+ }
+ }
+
+ // save for future reference
+ axis.position = pos;
+ axis.tickLength = tickLength;
+ axis.box.padding = padding;
+ axis.innermost = innermost;
+ }
+
+ function allocateAxisBoxSecondPhase(axis) {
+ // set remaining bounding box coordinates
+ if (axis.direction == "x") {
+ axis.box.left = plotOffset.left;
+ axis.box.width = plotWidth;
+ }
+ else {
+ axis.box.top = plotOffset.top;
+ axis.box.height = plotHeight;
+ }
+ }
+
+ function setupGrid() {
+ var i, axes = allAxes();
+
+ // first calculate the plot and axis box dimensions
+
+ $.each(axes, function (_, axis) {
+ axis.show = axis.options.show;
+ if (axis.show == null)
+ axis.show = axis.used; // by default an axis is visible if it's got data
+
+ axis.reserveSpace = axis.show || axis.options.reserveSpace;
+
+ setRange(axis);
+ });
+
+ allocatedAxes = $.grep(axes, function (axis) { return axis.reserveSpace; });
+
+ plotOffset.left = plotOffset.right = plotOffset.top = plotOffset.bottom = 0;
+ if (options.grid.show) {
+ $.each(allocatedAxes, function (_, axis) {
+ // make the ticks
+ setupTickGeneration(axis);
+ setTicks(axis);
+ snapRangeToTicks(axis, axis.ticks);
+
+ // find labelWidth/Height for axis
+ measureTickLabels(axis);
+ });
+
+ // with all dimensions in house, we can compute the
+ // axis boxes, start from the outside (reverse order)
+ for (i = allocatedAxes.length - 1; i >= 0; --i)
+ allocateAxisBoxFirstPhase(allocatedAxes[i]);
+
+ // make sure we've got enough space for things that
+ // might stick out
+ var minMargin = options.grid.minBorderMargin;
+ if (minMargin == null) {
+ minMargin = 0;
+ for (i = 0; i < series.length; ++i)
+ minMargin = Math.max(minMargin, series[i].points.radius + series[i].points.lineWidth/2);
+ }
+
+ for (var a in plotOffset) {
+ plotOffset[a] += options.grid.borderWidth;
+ plotOffset[a] = Math.max(minMargin, plotOffset[a]);
+ }
+ }
+
+ plotWidth = canvasWidth - plotOffset.left - plotOffset.right;
+ plotHeight = canvasHeight - plotOffset.bottom - plotOffset.top;
+
+ // now we got the proper plotWidth/Height, we can compute the scaling
+ $.each(axes, function (_, axis) {
+ setTransformationHelpers(axis);
+ });
+
+ if (options.grid.show) {
+ $.each(allocatedAxes, function (_, axis) {
+ allocateAxisBoxSecondPhase(axis);
+ });
+
+ insertAxisLabels();
+ }
+
+ insertLegend();
+ }
+
+ function setRange(axis) {
+ var opts = axis.options,
+ min = +(opts.min != null ? opts.min : axis.datamin),
+ max = +(opts.max != null ? opts.max : axis.datamax),
+ delta = max - min;
+
+ if (delta == 0.0) {
+ // degenerate case
+ var widen = max == 0 ? 1 : 0.01;
+
+ if (opts.min == null)
+ min -= widen;
+ // always widen max if we couldn't widen min to ensure we
+ // don't fall into min == max which doesn't work
+ if (opts.max == null || opts.min != null)
+ max += widen;
+ }
+ else {
+ // consider autoscaling
+ var margin = opts.autoscaleMargin;
+ if (margin != null) {
+ if (opts.min == null) {
+ min -= delta * margin;
+ // make sure we don't go below zero if all values
+ // are positive
+ if (min < 0 && axis.datamin != null && axis.datamin >= 0)
+ min = 0;
+ }
+ if (opts.max == null) {
+ max += delta * margin;
+ if (max > 0 && axis.datamax != null && axis.datamax <= 0)
+ max = 0;
+ }
+ }
+ }
+ axis.min = min;
+ axis.max = max;
+ }
+
+ function setupTickGeneration(axis) {
+ var opts = axis.options;
+
+ // estimate number of ticks
+ var noTicks;
+ if (typeof opts.ticks == "number" && opts.ticks > 0)
+ noTicks = opts.ticks;
+ else
+ // heuristic based on the model a*sqrt(x) fitted to
+ // some data points that seemed reasonable
+ noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? canvasWidth : canvasHeight);
+
+ var delta = (axis.max - axis.min) / noTicks,
+ size, generator, unit, formatter, i, magn, norm;
+
+ if (opts.mode == "time") {
+ // pretty handling of time
+
+ // 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 (opts.minTickSize != null) {
+ if (typeof opts.tickSize == "number")
+ minSize = opts.tickSize;
+ else
+ minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]];
+ }
+
+ for (var 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;
+ }
+
+ axis.tickSize = opts.tickSize || [size, unit];
+
+ 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.setUTCSeconds(floorInBase(d.getUTCSeconds(), tickSize));
+ if (unit == "minute")
+ d.setUTCMinutes(floorInBase(d.getUTCMinutes(), tickSize));
+ if (unit == "hour")
+ d.setUTCHours(floorInBase(d.getUTCHours(), tickSize));
+ if (unit == "month")
+ d.setUTCMonth(floorInBase(d.getUTCMonth(), tickSize));
+ if (unit == "year")
+ d.setUTCFullYear(floorInBase(d.getUTCFullYear(), tickSize));
+
+ // reset smaller components
+ d.setUTCMilliseconds(0);
+ if (step >= timeUnitSize.minute)
+ d.setUTCSeconds(0);
+ if (step >= timeUnitSize.hour)
+ d.setUTCMinutes(0);
+ if (step >= timeUnitSize.day)
+ d.setUTCHours(0);
+ if (step >= timeUnitSize.day * 4)
+ d.setUTCDate(1);
+ if (step >= timeUnitSize.year)
+ d.setUTCMonth(0);
+
+
+ var carry = 0, v = Number.NaN, prev;
+ do {
+ prev = v;
+ v = d.getTime();
+ ticks.push(v);
+ if (unit == "month") {
+ if (tickSize < 1) {
+ // a bit complicated - we'll divide the month
+ // up but we need to take care of fractions
+ // so we don't end up in the middle of a day
+ d.setUTCDate(1);
+ var start = d.getTime();
+ d.setUTCMonth(d.getUTCMonth() + 1);
+ var end = d.getTime();
+ d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize);
+ carry = d.getUTCHours();
+ d.setUTCHours(0);
+ }
+ else
+ d.setUTCMonth(d.getUTCMonth() + tickSize);
+ }
+ else if (unit == "year") {
+ d.setUTCFullYear(d.getUTCFullYear() + tickSize);
+ }
+ else
+ d.setTime(v + step);
+ } while (v < axis.max && v != prev);
+
+ return ticks;
+ };
+
+ formatter = function (v, axis) {
+ var d = new Date(v);
+
+ // first check global format
+ if (opts.timeformat != null)
+ return $.plot.formatDate(d, opts.timeformat, opts.monthNames);
+
+ var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];
+ var span = axis.max - axis.min;
+ var suffix = (opts.twelveHourClock) ? " %p" : "";
+
+ if (t < timeUnitSize.minute)
+ fmt = "%h:%M:%S" + suffix;
+ else if (t < timeUnitSize.day) {
+ if (span < 2 * timeUnitSize.day)
+ fmt = "%h:%M" + suffix;
+ else
+ fmt = "%b %d %h:%M" + suffix;
+ }
+ 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 $.plot.formatDate(d, fmt, opts.monthNames);
+ };
+ }
+ else {
+ // pretty rounding of base-10 numbers
+ var maxDec = opts.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 (opts.minTickSize != null && size < opts.minTickSize)
+ size = opts.minTickSize;
+
+ //add a checker to determine if we really have a decimeal or integer. if axis.delta = int, dec =0
+ var integerChecker = axis.delta - Math.floor(axis.delta);
+ if (integerChecker < 0.00000001 || integerChecker > 0.999999999) dec = 0;
+
+ //axis.delta is within floating point error of an integer
+
+ axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);
+ axis.tickSize = opts.tickSize || size;
+
+ generator = function (axis) {
+ var ticks = [];
+
+ // spew out all possible ticks
+ var start = floorInBase(axis.min, axis.tickSize),
+ i = 0, v = Number.NaN, prev;
+ do {
+ prev = v;
+ v = start + i * axis.tickSize;
+ ticks.push(v);
+ ++i;
+ } while (v < axis.max && v != prev);
+ return ticks;
+ };
+
+ formatter = function (v, axis) {
+ return v.toFixed(axis.tickDecimals);
+ };
+ }
+
+ if (opts.alignTicksWithAxis != null) {
+ var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1];
+ if (otherAxis && otherAxis.used && otherAxis != axis) {
+ // consider snapping min/max to outermost nice ticks
+ var niceTicks = generator(axis);
+ if (niceTicks.length > 0) {
+ if (opts.min == null)
+ axis.min = Math.min(axis.min, niceTicks[0]);
+ if (opts.max == null && niceTicks.length > 1)
+ axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]);
+ }
+
+ generator = function (axis) {
+ // copy ticks, scaled to this axis
+ var ticks = [], v, i;
+ for (i = 0; i < otherAxis.ticks.length; ++i) {
+ v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min);
+ v = axis.min + v * (axis.max - axis.min);
+ ticks.push(v);
+ }
+ return ticks;
+ };
+
+ // we might need an extra decimal since forced
+ // ticks don't necessarily fit naturally
+ if (axis.mode != "time" && opts.tickDecimals == null) {
+ var extraDec = Math.max(0, -Math.floor(Math.log(delta) / Math.LN10) + 1),
+ ts = generator(axis);
+
+ // only proceed if the tick interval rounded
+ // with an extra decimal doesn't give us a
+ // zero at end
+ if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec))))
+ axis.tickDecimals = extraDec;
+ }
+ }
+ }
+
+ axis.tickGenerator = generator;
+ if ($.isFunction(opts.tickFormatter))
+ axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); };
+ else
+ axis.tickFormatter = formatter;
+ }
+
+ function setTicks(axis) {
+ var oticks = axis.options.ticks, ticks = [];
+ if (oticks == null || (typeof oticks == "number" && oticks > 0))
+ ticks = axis.tickGenerator(axis);
+ else if (oticks) {
+ if ($.isFunction(oticks))
+ // generate the ticks
+ ticks = oticks({ min: axis.min, max: axis.max });
+ else
+ ticks = oticks;
+ }
+
+ // clean up/labelify the supplied ticks, copy them over
+ var i, v;
+ axis.ticks = [];
+ for (i = 0; i < ticks.length; ++i) {
+ var label = null;
+ var t = ticks[i];
+ if (typeof t == "object") {
+ v = +t[0];
+ if (t.length > 1)
+ label = t[1];
+ }
+ else
+ v = +t;
+ if (label == null)
+ label = axis.tickFormatter(v, axis);
+ if (!isNaN(v))
+ axis.ticks.push({ v: v, label: label });
+ }
+ }
+
+ function snapRangeToTicks(axis, ticks) {
+ if (axis.options.autoscaleMargin && ticks.length > 0) {
+ // snap to ticks
+ if (axis.options.min == null)
+ axis.min = Math.min(axis.min, ticks[0].v);
+ if (axis.options.max == null && ticks.length > 1)
+ axis.max = Math.max(axis.max, ticks[ticks.length - 1].v);
+ }
+ }
+
+ function draw() {
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
+
+ var grid = options.grid;
+
+ // draw background, if any
+ if (grid.show && grid.backgroundColor)
+ drawBackground();
+
+ if (grid.show && !grid.aboveData)
+ drawGrid();
+
+ for (var i = 0; i < series.length; ++i) {
+ executeHooks(hooks.drawSeries, [ctx, series[i]]);
+ drawSeries(series[i]);
+ }
+
+ executeHooks(hooks.draw, [ctx]);
+
+ if (grid.show && grid.aboveData)
+ drawGrid();
+ }
+
+ function extractRange(ranges, coord) {
+ var axis, from, to, key, axes = allAxes();
+
+ for (i = 0; i < axes.length; ++i) {
+ axis = axes[i];
+ if (axis.direction == coord) {
+ key = coord + axis.n + "axis";
+ if (!ranges[key] && axis.n == 1)
+ key = coord + "axis"; // support x1axis as xaxis
+ if (ranges[key]) {
+ from = ranges[key].from;
+ to = ranges[key].to;
+ break;
+ }
+ }
+ }
+
+ // backwards-compat stuff - to be removed in future
+ if (!ranges[key]) {
+ axis = coord == "x" ? xaxes[0] : yaxes[0];
+ from = ranges[coord + "1"];
+ to = ranges[coord + "2"];
+ }
+
+ // auto-reverse as an added bonus
+ if (from != null && to != null && from > to) {
+ var tmp = from;
+ from = to;
+ to = tmp;
+ }
+
+ return { from: from, to: to, axis: axis };
+ }
+
+ function drawBackground() {
+ ctx.save();
+ ctx.translate(plotOffset.left, plotOffset.top);
+
+ ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)");
+ ctx.fillRect(0, 0, plotWidth, plotHeight);
+ ctx.restore();
+ }
+
+ function drawGrid() {
+ var i;
+
+ ctx.save();
+ ctx.translate(plotOffset.left, plotOffset.top);
+
+ // draw markings
+ var markings = options.grid.markings;
+ if (markings) {
+ if ($.isFunction(markings)) {
+ var axes = plot.getAxes();
+ // xmin etc. is backwards compatibility, to be
+ // removed in the future
+ axes.xmin = axes.xaxis.min;
+ axes.xmax = axes.xaxis.max;
+ axes.ymin = axes.yaxis.min;
+ axes.ymax = axes.yaxis.max;
+
+ markings = markings(axes);
+ }
+
+ for (i = 0; i < markings.length; ++i) {
+ var m = markings[i],
+ xrange = extractRange(m, "x"),
+ yrange = extractRange(m, "y");
+
+ // fill in missing
+ if (xrange.from == null)
+ xrange.from = xrange.axis.min;
+ if (xrange.to == null)
+ xrange.to = xrange.axis.max;
+ if (yrange.from == null)
+ yrange.from = yrange.axis.min;
+ if (yrange.to == null)
+ yrange.to = yrange.axis.max;
+
+ // clip
+ if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max ||
+ yrange.to < yrange.axis.min || yrange.from > yrange.axis.max)
+ continue;
+
+ xrange.from = Math.max(xrange.from, xrange.axis.min);
+ xrange.to = Math.min(xrange.to, xrange.axis.max);
+ yrange.from = Math.max(yrange.from, yrange.axis.min);
+ yrange.to = Math.min(yrange.to, yrange.axis.max);
+
+ if (xrange.from == xrange.to && yrange.from == yrange.to)
+ continue;
+
+ // then draw
+ xrange.from = xrange.axis.p2c(xrange.from);
+ xrange.to = xrange.axis.p2c(xrange.to);
+ yrange.from = yrange.axis.p2c(yrange.from);
+ yrange.to = yrange.axis.p2c(yrange.to);
+
+ if (xrange.from == xrange.to || yrange.from == yrange.to) {
+ // draw line
+ ctx.beginPath();
+ ctx.strokeStyle = m.color || options.grid.markingsColor;
+ ctx.lineWidth = m.lineWidth || options.grid.markingsLineWidth;
+ ctx.moveTo(xrange.from, yrange.from);
+ ctx.lineTo(xrange.to, yrange.to);
+ ctx.stroke();
+ }
+ else {
+ // fill area
+ ctx.fillStyle = m.color || options.grid.markingsColor;
+ ctx.fillRect(xrange.from, yrange.to,
+ xrange.to - xrange.from,
+ yrange.from - yrange.to);
+ }
+ }
+ }
+
+ // draw the ticks
+ var axes = allAxes(), bw = options.grid.borderWidth;
+
+ for (var j = 0; j < axes.length; ++j) {
+ var axis = axes[j], box = axis.box,
+ t = axis.tickLength, x, y, xoff, yoff;
+ if (!axis.show || axis.ticks.length == 0)
+ continue
+
+ ctx.strokeStyle = axis.options.tickColor || $.color.parse(axis.options.color).scale('a', 0.22).toString();
+ ctx.lineWidth = 1;
+
+ // find the edges
+ if (axis.direction == "x") {
+ x = 0;
+ if (t == "full")
+ y = (axis.position == "top" ? 0 : plotHeight);
+ else
+ y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0);
+ }
+ else {
+ y = 0;
+ if (t == "full")
+ x = (axis.position == "left" ? 0 : plotWidth);
+ else
+ x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0);
+ }
+
+ // draw tick bar
+ if (!axis.innermost) {
+ ctx.beginPath();
+ xoff = yoff = 0;
+ if (axis.direction == "x")
+ xoff = plotWidth;
+ else
+ yoff = plotHeight;
+
+ if (ctx.lineWidth == 1) {
+ x = Math.floor(x) + 0.5;
+ y = Math.floor(y) + 0.5;
+ }
+
+ ctx.moveTo(x, y);
+ ctx.lineTo(x + xoff, y + yoff);
+ ctx.stroke();
+ }
+
+ // draw ticks
+ ctx.beginPath();
+ for (i = 0; i < axis.ticks.length; ++i) {
+ var v = axis.ticks[i].v;
+
+ xoff = yoff = 0;
+
+ if (v < axis.min || v > axis.max
+ // skip those lying on the axes if we got a border
+ || (t == "full" && bw > 0
+ && (v == axis.min || v == axis.max)))
+ continue;
+
+ if (axis.direction == "x") {
+ x = axis.p2c(v);
+ yoff = t == "full" ? -plotHeight : t;
+
+ if (axis.position == "top")
+ yoff = -yoff;
+ }
+ else {
+ y = axis.p2c(v);
+ xoff = t == "full" ? -plotWidth : t;
+
+ if (axis.position == "left")
+ xoff = -xoff;
+ }
+
+ if (ctx.lineWidth == 1) {
+ if (axis.direction == "x")
+ x = Math.floor(x) + 0.5;
+ else
+ y = Math.floor(y) + 0.5;
+ }
+
+ ctx.moveTo(x, y);
+ ctx.lineTo(x + xoff, y + yoff);
+ }
+
+ ctx.stroke();
+ }
+
+
+ // draw border
+ if (bw) {
+ ctx.lineWidth = bw;
+ ctx.strokeStyle = options.grid.borderColor;
+ ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw);
+ }
+
+ ctx.restore();
+ }
+
+ function insertAxisLabels() {
+ placeholder.find(".tickLabels").remove();
+
+ var html = ['<div class="tickLabels" style="font-size:smaller">'];
+
+ var axes = allAxes();
+ for (var j = 0; j < axes.length; ++j) {
+ var axis = axes[j], box = axis.box;
+ if (!axis.show)
+ continue;
+ //debug: html.push('<div style="position:absolute;opacity:0.10;background-color:red;left:' + box.left + 'px;top:' + box.top + 'px;width:' + box.width + 'px;height:' + box.height + 'px"></div>')
+ html.push('<div class="' + axis.direction + 'Axis ' + axis.direction + axis.n + 'Axis" style="color:' + axis.options.color + '">');
+ for (var i = 0; i < axis.ticks.length; ++i) {
+ var tick = axis.ticks[i];
+ if (!tick.label || tick.v < axis.min || tick.v > axis.max)
+ continue;
+
+ var pos = {}, align;
+
+ if (axis.direction == "x") {
+ align = "center";
+ pos.left = Math.round(plotOffset.left + axis.p2c(tick.v) - axis.labelWidth/2);
+ if (axis.position == "bottom")
+ pos.top = box.top + box.padding;
+ else
+ pos.bottom = canvasHeight - (box.top + box.height - box.padding);
+ }
+ else {
+ pos.top = Math.round(plotOffset.top + axis.p2c(tick.v) - axis.labelHeight/2);
+ if (axis.position == "left") {
+ pos.right = canvasWidth - (box.left + box.width - box.padding)
+ align = "right";
+ }
+ else {
+ pos.left = box.left + box.padding;
+ align = "left";
+ }
+ }
+
+ pos.width = axis.labelWidth;
+
+ var style = ["position:absolute", "text-align:" + align ];
+ for (var a in pos)
+ style.push(a + ":" + pos[a] + "px")
+
+ html.push('<div class="tickLabel" style="' + style.join(';') + '">' + tick.label + '</div>');
+ }
+ html.push('</div>');
+ }
+
+ html.push('</div>');
+
+ placeholder.append(html.join(""));
+ }
+
+ function drawSeries(series) {
+ if (series.lines.show)
+ drawSeriesLines(series);
+ if (series.bars.show)
+ drawSeriesBars(series);
+ if (series.points.show)
+ drawSeriesPoints(series);
+ }
+
+ function drawSeriesLines(series) {
+ function plotLine(datapoints, xoffset, yoffset, axisx, axisy) {
+ var points = datapoints.points,
+ ps = datapoints.pointsize,
+ prevx = null, prevy = null;
+
+ ctx.beginPath();
+ for (var i = ps; i < points.length; i += ps) {
+ var x1 = points[i - ps], y1 = points[i - ps + 1],
+ x2 = points[i], y2 = points[i + 1];
+
+ if (x1 == null || x2 == null)
+ continue;
+
+ // clip with ymin
+ if (y1 <= y2 && y1 < axisy.min) {
+ if (y2 < axisy.min)
+ continue; // line segment is outside
+ // compute new intersection point
+ x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y1 = axisy.min;
+ }
+ else if (y2 <= y1 && y2 < axisy.min) {
+ if (y1 < axisy.min)
+ continue;
+ x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y2 = axisy.min;
+ }
+
+ // clip with ymax
+ if (y1 >= y2 && y1 > axisy.max) {
+ if (y2 > axisy.max)
+ continue;
+ x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y1 = axisy.max;
+ }
+ else if (y2 >= y1 && y2 > axisy.max) {
+ if (y1 > axisy.max)
+ continue;
+ x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y2 = axisy.max;
+ }
+
+ // clip with xmin
+ if (x1 <= x2 && x1 < axisx.min) {
+ if (x2 < axisx.min)
+ continue;
+ y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x1 = axisx.min;
+ }
+ else if (x2 <= x1 && x2 < axisx.min) {
+ if (x1 < axisx.min)
+ continue;
+ y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x2 = axisx.min;
+ }
+
+ // clip with xmax
+ if (x1 >= x2 && x1 > axisx.max) {
+ if (x2 > axisx.max)
+ continue;
+ y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x1 = axisx.max;
+ }
+ else if (x2 >= x1 && x2 > axisx.max) {
+ if (x1 > axisx.max)
+ continue;
+ y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x2 = axisx.max;
+ }
+
+ if (x1 != prevx || y1 != prevy)
+ ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);
+
+ prevx = x2;
+ prevy = y2;
+ ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset);
+ }
+ ctx.stroke();
+ }
+
+ function plotLineArea(datapoints, axisx, axisy) {
+ var points = datapoints.points,
+ ps = datapoints.pointsize,
+ bottom = Math.min(Math.max(0, axisy.min), axisy.max),
+ i = 0, top, areaOpen = false,
+ ypos = 1, segmentStart = 0, segmentEnd = 0;
+
+ // we process each segment in two turns, first forward
+ // direction to sketch out top, then once we hit the
+ // end we go backwards to sketch the bottom
+ while (true) {
+ if (ps > 0 && i > points.length + ps)
+ break;
+
+ i += ps; // ps is negative if going backwards
+
+ var x1 = points[i - ps],
+ y1 = points[i - ps + ypos],
+ x2 = points[i], y2 = points[i + ypos];
+
+ if (areaOpen) {
+ if (ps > 0 && x1 != null && x2 == null) {
+ // at turning point
+ segmentEnd = i;
+ ps = -ps;
+ ypos = 2;
+ continue;
+ }
+
+ if (ps < 0 && i == segmentStart + ps) {
+ // done with the reverse sweep
+ ctx.fill();
+ areaOpen = false;
+ ps = -ps;
+ ypos = 1;
+ i = segmentStart = segmentEnd + ps;
+ continue;
+ }
+ }
+
+ if (x1 == null || x2 == null)
+ continue;
+
+ // clip x values
+
+ // clip with xmin
+ if (x1 <= x2 && x1 < axisx.min) {
+ if (x2 < axisx.min)
+ continue;
+ y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x1 = axisx.min;
+ }
+ else if (x2 <= x1 && x2 < axisx.min) {
+ if (x1 < axisx.min)
+ continue;
+ y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x2 = axisx.min;
+ }
+
+ // clip with xmax
+ if (x1 >= x2 && x1 > axisx.max) {
+ if (x2 > axisx.max)
+ continue;
+ y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x1 = axisx.max;
+ }
+ else if (x2 >= x1 && x2 > axisx.max) {
+ if (x1 > axisx.max)
+ continue;
+ y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+ x2 = axisx.max;
+ }
+
+ if (!areaOpen) {
+ // open area
+ ctx.beginPath();
+ ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));
+ areaOpen = true;
+ }
+
+ // now first check the case where both is outside
+ if (y1 >= axisy.max && y2 >= axisy.max) {
+ ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));
+ ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max));
+ continue;
+ }
+ else if (y1 <= axisy.min && y2 <= axisy.min) {
+ ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min));
+ ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));
+ continue;
+ }
+
+ // else it's a bit more complicated, there might
+ // be a flat maxed out rectangle first, then a
+ // triangular cutout or reverse; to find these
+ // keep track of the current x values
+ var x1old = x1, x2old = x2;
+
+ // clip the y values, without shortcutting, we
+ // go through all cases in turn
+
+ // clip with ymin
+ if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {
+ x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y1 = axisy.min;
+ }
+ else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) {
+ x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y2 = axisy.min;
+ }
+
+ // clip with ymax
+ if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) {
+ x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y1 = axisy.max;
+ }
+ else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) {
+ x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+ y2 = axisy.max;
+ }
+
+ // if the x value was changed we got a rectangle
+ // to fill
+ if (x1 != x1old) {
+ ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1));
+ // it goes to (x1, y1), but we fill that below
+ }
+
+ // fill triangular section, this sometimes result
+ // in redundant points if (x1, y1) hasn't changed
+ // from previous line to, but we just ignore that
+ ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));
+ ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
+
+ // fill the other rectangle if it's there
+ if (x2 != x2old) {
+ ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
+ ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2));
+ }
+ }
+ }
+
+ ctx.save();
+ ctx.translate(plotOffset.left, plotOffset.top);
+ ctx.lineJoin = "round";
+
+ var lw = series.lines.lineWidth,
+ sw = series.shadowSize;
+ // FIXME: consider another form of shadow when filling is turned on
+ if (lw > 0 && sw > 0) {
+ // draw shadow as a thick and thin line with transparency
+ ctx.lineWidth = sw;
+ ctx.strokeStyle = "rgba(0,0,0,0.1)";
+ // position shadow at angle from the mid of line
+ var angle = Math.PI/18;
+ plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2), series.xaxis, series.yaxis);
+ ctx.lineWidth = sw/2;
+ plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4), series.xaxis, series.yaxis);
+ }
+
+ ctx.lineWidth = lw;
+ ctx.strokeStyle = series.color;
+ var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight);
+ if (fillStyle) {
+ ctx.fillStyle = fillStyle;
+ plotLineArea(series.datapoints, series.xaxis, series.yaxis);
+ }
+
+ if (lw > 0)
+ plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis);
+ ctx.restore();
+ }
+
+ function drawSeriesPoints(series) {
+ function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) {
+ var points = datapoints.points, ps = datapoints.pointsize;
+
+ for (var i = 0; i < points.length; i += ps) {
+ var x = points[i], y = points[i + 1];
+ if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
+ continue;
+
+ ctx.beginPath();
+ x = axisx.p2c(x);
+ y = axisy.p2c(y) + offset;
+ if (symbol == "circle")
+ ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false);
+ else
+ symbol(ctx, x, y, radius, shadow);
+ ctx.closePath();
+
+ if (fillStyle) {
+ ctx.fillStyle = fillStyle;
+ ctx.fill();
+ }
+ ctx.stroke();
+ }
+ }
+
+ ctx.save();
+ ctx.translate(plotOffset.left, plotOffset.top);
+
+ var lw = series.points.lineWidth,
+ sw = series.shadowSize,
+ radius = series.points.radius,
+ symbol = series.points.symbol;
+ if (lw > 0 && sw > 0) {
+ // draw shadow in two steps
+ var w = sw / 2;
+ ctx.lineWidth = w;
+ ctx.strokeStyle = "rgba(0,0,0,0.1)";
+ plotPoints(series.datapoints, radius, null, w + w/2, true,
+ series.xaxis, series.yaxis, symbol);
+
+ ctx.strokeStyle = "rgba(0,0,0,0.2)";
+ plotPoints(series.datapoints, radius, null, w/2, true,
+ series.xaxis, series.yaxis, symbol);
+ }
+
+ ctx.lineWidth = lw;
+ ctx.strokeStyle = series.color;
+ plotPoints(series.datapoints, radius,
+ getFillStyle(series.points, series.color), 0, false,
+ series.xaxis, series.yaxis, symbol);
+ ctx.restore();
+ }
+
+ function drawBar(x, y, b, barLeft, barRight, offset, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {
+ var left, right, bottom, top,
+ drawLeft, drawRight, drawTop, drawBottom,
+ tmp;
+
+ // in horizontal mode, we start the bar from the left
+ // instead of from the bottom so it appears to be
+ // horizontal rather than vertical
+ if (horizontal) {
+ drawBottom = drawRight = drawTop = true;
+ drawLeft = false;
+ left = b;
+ right = x;
+ top = y + barLeft;
+ bottom = y + barRight;
+
+ // account for negative bars
+ if (right < left) {
+ tmp = right;
+ right = left;
+ left = tmp;
+ drawLeft = true;
+ drawRight = false;
+ }
+ }
+ else {
+ drawLeft = drawRight = drawTop = true;
+ drawBottom = false;
+ left = x + barLeft;
+ right = x + barRight;
+ bottom = b;
+ top = y;
+
+ // account for negative bars
+ if (top < bottom) {
+ tmp = top;
+ top = bottom;
+ bottom = tmp;
+ drawBottom = true;
+ drawTop = false;
+ }
+ }
+
+ // clip
+ if (right < axisx.min || left > axisx.max ||
+ top < axisy.min || bottom > axisy.max)
+ return;
+
+ if (left < axisx.min) {
+ left = axisx.min;
+ drawLeft = false;
+ }
+
+ if (right > axisx.max) {
+ right = axisx.max;
+ drawRight = false;
+ }
+
+ if (bottom < axisy.min) {
+ bottom = axisy.min;
+ drawBottom = false;
+ }
+
+ if (top > axisy.max) {
+ top = axisy.max;
+ drawTop = false;
+ }
+
+ left = axisx.p2c(left);
+ bottom = axisy.p2c(bottom);
+ right = axisx.p2c(right);
+ top = axisy.p2c(top);
+
+ // fill the bar
+ if (fillStyleCallback) {
+ c.beginPath();
+ c.moveTo(left, bottom);
+ c.lineTo(left, top);
+ c.lineTo(right, top);
+ c.lineTo(right, bottom);
+ c.fillStyle = fillStyleCallback(bottom, top);
+ c.fill();
+ }
+
+ // draw outline
+ if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) {
+ c.beginPath();
+
+ // FIXME: inline moveTo is buggy with excanvas
+ c.moveTo(left, bottom + offset);
+ if (drawLeft)
+ c.lineTo(left, top + offset);
+ else
+ c.moveTo(left, top + offset);
+ if (drawTop)
+ c.lineTo(right, top + offset);
+ else
+ c.moveTo(right, top + offset);
+ if (drawRight)
+ c.lineTo(right, bottom + offset);
+ else
+ c.moveTo(right, bottom + offset);
+ if (drawBottom)
+ c.lineTo(left, bottom + offset);
+ else
+ c.moveTo(left, bottom + offset);
+ c.stroke();
+ }
+ }
+
+ function drawSeriesBars(series) {
+ function plotBars(datapoints, barLeft, barRight, offset, fillStyleCallback, axisx, axisy) {
+ var points = datapoints.points, ps = datapoints.pointsize;
+
+ for (var i = 0; i < points.length; i += ps) {
+ if (points[i] == null)
+ continue;
+ drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, offset, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);
+ }
+ }
+
+ ctx.save();
+ ctx.translate(plotOffset.left, plotOffset.top);
+
+ // FIXME: figure out a way to add shadows (for instance along the right edge)
+ ctx.lineWidth = series.bars.lineWidth;
+ ctx.strokeStyle = series.color;
+ var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;
+ var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null;
+ plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, 0, fillStyleCallback, series.xaxis, series.yaxis);
+ ctx.restore();
+ }
+
+ function getFillStyle(filloptions, seriesColor, bottom, top) {
+ var fill = filloptions.fill;
+ if (!fill)
+ return null;
+
+ if (filloptions.fillColor)
+ return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor);
+
+ var c = $.color.parse(seriesColor);
+ c.a = typeof fill == "number" ? fill : 0.4;
+ c.normalize();
+ return c.toString();
+ }
+
+ function insertLegend() {
+ placeholder.find(".legend").remove();
+
+ if (!options.legend.show)
+ return;
+
+ var fragments = [], rowStarted = false,
+ lf = options.legend.labelFormatter, s, label;
+ for (var i = 0; i < series.length; ++i) {
+ s = series[i];
+ label = s.label;
+ if (!label)
+ continue;
+
+ if (i % options.legend.noColumns == 0) {
+ if (rowStarted)
+ fragments.push('</tr>');
+ fragments.push('<tr>');
+ rowStarted = true;
+ }
+
+ if (lf)
+ label = lf(label, s);
+
+ fragments.push(
+ '<td class="legendColorBox"><div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px"><div style="width:4px;height:0;border:5px solid ' + s.color + ';overflow:hidden"></div></div></td>' +
+ '<td class="legendLabel">' + label + '</td>');
+ }
+ if (rowStarted)
+ fragments.push('</tr>');
+
+ if (fragments.length == 0)
+ return;
+
+ var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>';
+ if (options.legend.container != null)
+ $(options.legend.container).html(table);
+ else {
+ var pos = "",
+ p = options.legend.position,
+ m = options.legend.margin;
+ if (m[0] == null)
+ m = [m, m];
+ if (p.charAt(0) == "n")
+ pos += 'top:' + (m[1] + plotOffset.top) + 'px;';
+ else if (p.charAt(0) == "s")
+ pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;';
+ if (p.charAt(1) == "e")
+ pos += 'right:' + (m[0] + plotOffset.right) + 'px;';
+ else if (p.charAt(1) == "w")
+ pos += 'left:' + (m[0] + plotOffset.left) + 'px;';
+ var legend = $('<div class="legend">' + table.replace('style="', 'style="position:absolute;' + pos +';') + '</div>').appendTo(placeholder);
+ if (options.legend.backgroundOpacity != 0.0) {
+ // put in the transparent background
+ // separately to avoid blended labels and
+ // label boxes
+ var c = options.legend.backgroundColor;
+ if (c == null) {
+ c = options.grid.backgroundColor;
+ if (c && typeof c == "string")
+ c = $.color.parse(c);
+ else
+ c = $.color.extract(legend, 'background-color');
+ c.a = 1;
+ c = c.toString();
+ }
+ var div = legend.children();
+ $('<div style="position:absolute;width:' + div.width() + 'px;height:' + div.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').prependTo(legend).css('opacity', options.legend.backgroundOpacity);
+ }
+ }
+ }
+
+
+ // interactive features
+
+ var highlights = [],
+ redrawTimeout = null;
+
+ // returns the data item the mouse is over, or null if none is found
+ function findNearbyItem(mouseX, mouseY, seriesFilter) {
+ var maxDistance = options.grid.mouseActiveRadius,
+ smallestDistance = maxDistance * maxDistance + 1,
+ item = null, foundPoint = false, i, j;
+
+ for (i = series.length - 1; i >= 0; --i) {
+ if (!seriesFilter(series[i]))
+ continue;
+
+ var s = series[i],
+ axisx = s.xaxis,
+ axisy = s.yaxis,
+ points = s.datapoints.points,
+ ps = s.datapoints.pointsize,
+ mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster
+ my = axisy.c2p(mouseY),
+ maxx = maxDistance / axisx.scale,
+ maxy = maxDistance / axisy.scale;
+
+ // with inverse transforms, we can't use the maxx/maxy
+ // optimization, sadly
+ if (axisx.options.inverseTransform)
+ maxx = Number.MAX_VALUE;
+ if (axisy.options.inverseTransform)
+ maxy = Number.MAX_VALUE;
+
+ if (s.lines.show || s.points.show) {
+ for (j = 0; j < points.length; j += ps) {
+ var x = points[j], y = points[j + 1];
+ if (x == null)
+ continue;
+
+ // For points and lines, the cursor must be within a
+ // certain distance to the data point
+ if (x - mx > maxx || x - mx < -maxx ||
+ y - my > maxy || y - my < -maxy)
+ continue;
+
+ // We have to calculate distances in pixels, not in
+ // data units, because the scales of the axes may be different
+ var dx = Math.abs(axisx.p2c(x) - mouseX),
+ dy = Math.abs(axisy.p2c(y) - mouseY),
+ dist = dx * dx + dy * dy; // we save the sqrt
+
+ // use <= to ensure last point takes precedence
+ // (last generally means on top of)
+ if (dist < smallestDistance) {
+ smallestDistance = dist;
+ item = [i, j / ps];
+ }
+ }
+ }
+
+ if (s.bars.show && !item) { // no other point can be nearby
+ var barLeft = s.bars.align == "left" ? 0 : -s.bars.barWidth/2,
+ barRight = barLeft + s.bars.barWidth;
+
+ for (j = 0; j < points.length; j += ps) {
+ var x = points[j], y = points[j + 1], b = points[j + 2];
+ if (x == null)
+ continue;
+
+ // for a bar graph, the cursor must be inside the bar
+ if (series[i].bars.horizontal ?
+ (mx <= Math.max(b, x) && mx >= Math.min(b, x) &&
+ my >= y + barLeft && my <= y + barRight) :
+ (mx >= x + barLeft && mx <= x + barRight &&
+ my >= Math.min(b, y) && my <= Math.max(b, y)))
+ item = [i, j / ps];
+ }
+ }
+ }
+
+ if (item) {
+ i = item[0];
+ j = item[1];
+ ps = series[i].datapoints.pointsize;
+
+ return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps),
+ dataIndex: j,
+ series: series[i],
+ seriesIndex: i };
+ }
+
+ return null;
+ }
+
+ function onMouseMove(e) {
+ if (options.grid.hoverable)
+ triggerClickHoverEvent("plothover", e,
+ function (s) { return s["hoverable"] != false; });
+ }
+
+ function onMouseLeave(e) {
+ if (options.grid.hoverable)
+ triggerClickHoverEvent("plothover", e,
+ function (s) { return false; });
+ }
+
+ function onClick(e) {
+ triggerClickHoverEvent("plotclick", e,
+ function (s) { return s["clickable"] != false; });
+ }
+
+ // trigger click or hover event (they send the same parameters
+ // so we share their code)
+ function triggerClickHoverEvent(eventname, event, seriesFilter) {
+ var offset = eventHolder.offset(),
+ canvasX = event.pageX - offset.left - plotOffset.left,
+ canvasY = event.pageY - offset.top - plotOffset.top,
+ pos = canvasToAxisCoords({ left: canvasX, top: canvasY });
+
+ pos.pageX = event.pageX;
+ pos.pageY = event.pageY;
+
+ var item = findNearbyItem(canvasX, canvasY, seriesFilter);
+
+ if (item) {
+ // fill in mouse pos for any listeners out there
+ item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left);
+ item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top);
+ }
+
+ if (options.grid.autoHighlight) {
+ // clear auto-highlights
+ for (var i = 0; i < highlights.length; ++i) {
+ var h = highlights[i];
+ if (h.auto == eventname &&
+ !(item && h.series == item.series &&
+ h.point[0] == item.datapoint[0] &&
+ h.point[1] == item.datapoint[1]))
+ unhighlight(h.series, h.point);
+ }
+
+ if (item)
+ highlight(item.series, item.datapoint, eventname);
+ }
+
+ placeholder.trigger(eventname, [ pos, item ]);
+ }
+
+ function triggerRedrawOverlay() {
+ if (!redrawTimeout)
+ redrawTimeout = setTimeout(drawOverlay, 30);
+ }
+
+ function drawOverlay() {
+ redrawTimeout = null;
+
+ // draw highlights
+ octx.save();
+ octx.clearRect(0, 0, canvasWidth, canvasHeight);
+ octx.translate(plotOffset.left, plotOffset.top);
+
+ var i, hi;
+ for (i = 0; i < highlights.length; ++i) {
+ hi = highlights[i];
+
+ if (hi.series.bars.show)
+ drawBarHighlight(hi.series, hi.point);
+ else
+ drawPointHighlight(hi.series, hi.point);
+ }
+ octx.restore();
+
+ executeHooks(hooks.drawOverlay, [octx]);
+ }
+
+ function highlight(s, point, auto) {
+ if (typeof s == "number")
+ s = series[s];
+
+ if (typeof point == "number") {
+ var ps = s.datapoints.pointsize;
+ point = s.datapoints.points.slice(ps * point, ps * (point + 1));
+ }
+
+ var i = indexOfHighlight(s, point);
+ if (i == -1) {
+ highlights.push({ series: s, point: point, auto: auto });
+
+ triggerRedrawOverlay();
+ }
+ else if (!auto)
+ highlights[i].auto = false;
+ }
+
+ function unhighlight(s, point) {
+ if (s == null && point == null) {
+ highlights = [];
+ triggerRedrawOverlay();
+ }
+
+ if (typeof s == "number")
+ s = series[s];
+
+ if (typeof point == "number")
+ point = s.data[point];
+
+ var i = indexOfHighlight(s, point);
+ if (i != -1) {
+ highlights.splice(i, 1);
+
+ triggerRedrawOverlay();
+ }
+ }
+
+ function indexOfHighlight(s, p) {
+ for (var i = 0; i < highlights.length; ++i) {
+ var h = highlights[i];
+ if (h.series == s && h.point[0] == p[0]
+ && h.point[1] == p[1])
+ return i;
+ }
+ return -1;
+ }
+
+ function drawPointHighlight(series, point) {
+ var x = point[0], y = point[1],
+ axisx = series.xaxis, axisy = series.yaxis;
+
+ if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
+ return;
+
+ var pointRadius = series.points.radius + series.points.lineWidth / 2;
+ octx.lineWidth = pointRadius;
+ octx.strokeStyle = $.color.parse(series.color).scale('a', 0.5).toString();
+ var radius = 1.5 * pointRadius,
+ x = axisx.p2c(x),
+ y = axisy.p2c(y);
+
+ octx.beginPath();
+ if (series.points.symbol == "circle")
+ octx.arc(x, y, radius, 0, 2 * Math.PI, false);
+ else
+ series.points.symbol(octx, x, y, radius, false);
+ octx.closePath();
+ octx.stroke();
+ }
+
+ function drawBarHighlight(series, point) {
+ octx.lineWidth = series.bars.lineWidth;
+ octx.strokeStyle = $.color.parse(series.color).scale('a', 0.5).toString();
+ var fillStyle = $.color.parse(series.color).scale('a', 0.5).toString();
+ var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;
+ drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth,
+ 0, function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
+ }
+
+ function getColorOrGradient(spec, bottom, top, defaultColor) {
+ if (typeof spec == "string")
+ return spec;
+ else {
+ // assume this is a gradient spec; IE currently only
+ // supports a simple vertical gradient properly, so that's
+ // what we support too
+ var gradient = ctx.createLinearGradient(0, top, 0, bottom);
+
+ for (var i = 0, l = spec.colors.length; i < l; ++i) {
+ var c = spec.colors[i];
+ if (typeof c != "string") {
+ var co = $.color.parse(defaultColor);
+ if (c.brightness != null)
+ co = co.scale('rgb', c.brightness)
+ if (c.opacity != null)
+ co.a *= c.opacity;
+ c = co.toString();
+ }
+ gradient.addColorStop(i / (l - 1), c);
+ }
+
+ return gradient;
+ }
+ }
+ }
+
+ $.plot = function(placeholder, data, options) {
+ //var t0 = new Date();
+ var plot = new Plot($(placeholder), data, options, $.plot.plugins);
+ //(window.console ? console.log : alert)("time used (msecs): " + ((new Date()).getTime() - t0.getTime()));
+ return plot;
+ };
+
+ $.plot.version = "0.7";
+
+ $.plot.plugins = [];
+
+ // returns a string with the date d formatted according to fmt
+ $.plot.formatDate = function(d, fmt, monthNames) {
+ var leftPad = function(n) {
+ n = "" + n;
+ return n.length == 1 ? "0" + n : n;
+ };
+
+ var r = [];
+ var escape = false, padNext = false;
+ var hours = d.getUTCHours();
+ var isAM = hours < 12;
+ if (monthNames == null)
+ monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
+
+ if (fmt.search(/%p|%P/) != -1) {
+ if (hours > 12) {
+ hours = hours - 12;
+ } else if (hours == 0) {
+ hours = 12;
+ }
+ }
+ for (var i = 0; i < fmt.length; ++i) {
+ var c = fmt.charAt(i);
+
+ if (escape) {
+ switch (c) {
+ case 'h': c = "" + hours; break;
+ case 'H': c = leftPad(hours); break;
+ case 'M': c = leftPad(d.getUTCMinutes()); break;
+ case 'S': c = leftPad(d.getUTCSeconds()); break;
+ case 'd': c = "" + d.getUTCDate(); break;
+ case 'm': c = "" + (d.getUTCMonth() + 1); break;
+ case 'y': c = "" + d.getUTCFullYear(); break;
+ case 'b': c = "" + monthNames[d.getUTCMonth()]; break;
+ case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break;
+ case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break;
+ case '0': c = ""; padNext = true; break;
+ }
+ if (c && padNext) {
+ c = leftPad(c);
+ padNext = false;
+ }
+ r.push(c);
+ if (!padNext)
+ escape = false;
+ }
+ else {
+ if (c == "%")
+ escape = true;
+ else
+ r.push(c);
+ }
+ }
+ return r.join("");
+ };
+
+ // round to nearby lower multiple of base
+ function floorInBase(n, base) {
+ return base * Math.floor(n / base);
+ }
+
+})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/flot/jquery.flot.pie.js b/SemanticResultFormats/resources/jquery/flot/jquery.flot.pie.js
new file mode 100644
index 00000000..b46c03c2
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/flot/jquery.flot.pie.js
@@ -0,0 +1,750 @@
+/*
+Flot plugin for rendering pie charts. The plugin assumes the data is
+coming is as a single data value for each series, and each of those
+values is a positive value or zero (negative numbers don't make
+any sense and will cause strange effects). The data values do
+NOT need to be passed in as percentage values because it
+internally calculates the total and percentages.
+
+* Created by Brian Medendorp, June 2009
+* Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars
+
+* Changes:
+ 2009-10-22: lineJoin set to round
+ 2009-10-23: IE full circle fix, donut
+ 2009-11-11: Added basic hover from btburnett3 - does not work in IE, and center is off in Chrome and Opera
+ 2009-11-17: Added IE hover capability submitted by Anthony Aragues
+ 2009-11-18: Added bug fix submitted by Xavi Ivars (issues with arrays when other JS libraries are included as well)
+
+
+Available options are:
+series: {
+ pie: {
+ show: true/false
+ radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'
+ innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect
+ startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result
+ tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)
+ offset: {
+ top: integer value to move the pie up or down
+ left: integer value to move the pie left or right, or 'auto'
+ },
+ stroke: {
+ color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')
+ width: integer pixel width of the stroke
+ },
+ label: {
+ show: true/false, or 'auto'
+ formatter: a user-defined function that modifies the text/style of the label text
+ radius: 0-1 for percentage of fullsize, or a specified pixel length
+ background: {
+ color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')
+ opacity: 0-1
+ },
+ threshold: 0-1 for the percentage value at which to hide labels (if they're too small)
+ },
+ combine: {
+ threshold: 0-1 for the percentage value at which to combine slices (if they're too small)
+ color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined
+ label: any text value of what the combined slice should be labeled
+ }
+ highlight: {
+ opacity: 0-1
+ }
+ }
+}
+
+More detail and specific examples can be found in the included HTML file.
+
+*/
+
+(function ($)
+{
+ function init(plot) // this is the "body" of the plugin
+ {
+ var canvas = null;
+ var target = null;
+ var maxRadius = null;
+ var centerLeft = null;
+ var centerTop = null;
+ var total = 0;
+ var redraw = true;
+ var redrawAttempts = 10;
+ var shrink = 0.95;
+ var legendWidth = 0;
+ var processed = false;
+ var raw = false;
+
+ // interactive variables
+ var highlights = [];
+
+ // add hook to determine if pie plugin in enabled, and then perform necessary operations
+ plot.hooks.processOptions.push(checkPieEnabled);
+ plot.hooks.bindEvents.push(bindEvents);
+
+ // check to see if the pie plugin is enabled
+ function checkPieEnabled(plot, options)
+ {
+ if (options.series.pie.show)
+ {
+ //disable grid
+ options.grid.show = false;
+
+ // set labels.show
+ if (options.series.pie.label.show=='auto')
+ if (options.legend.show)
+ options.series.pie.label.show = false;
+ else
+ options.series.pie.label.show = true;
+
+ // set radius
+ if (options.series.pie.radius=='auto')
+ if (options.series.pie.label.show)
+ options.series.pie.radius = 3/4;
+ else
+ options.series.pie.radius = 1;
+
+ // ensure sane tilt
+ if (options.series.pie.tilt>1)
+ options.series.pie.tilt=1;
+ if (options.series.pie.tilt<0)
+ options.series.pie.tilt=0;
+
+ // add processData hook to do transformations on the data
+ plot.hooks.processDatapoints.push(processDatapoints);
+ plot.hooks.drawOverlay.push(drawOverlay);
+
+ // add draw hook
+ plot.hooks.draw.push(draw);
+ }
+ }
+
+ // bind hoverable events
+ function bindEvents(plot, eventHolder)
+ {
+ var options = plot.getOptions();
+
+ if (options.series.pie.show && options.grid.hoverable)
+ eventHolder.unbind('mousemove').mousemove(onMouseMove);
+
+ if (options.series.pie.show && options.grid.clickable)
+ eventHolder.unbind('click').click(onClick);
+ }
+
+
+ // debugging function that prints out an object
+ function alertObject(obj)
+ {
+ var msg = '';
+ function traverse(obj, depth)
+ {
+ if (!depth)
+ depth = 0;
+ for (var i = 0; i < obj.length; ++i)
+ {
+ for (var j=0; j<depth; j++)
+ msg += '\t';
+
+ if( typeof obj[i] == "object")
+ { // its an object
+ msg += ''+i+':\n';
+ traverse(obj[i], depth+1);
+ }
+ else
+ { // its a value
+ msg += ''+i+': '+obj[i]+'\n';
+ }
+ }
+ }
+ traverse(obj);
+ alert(msg);
+ }
+
+ function calcTotal(data)
+ {
+ for (var i = 0; i < data.length; ++i)
+ {
+ var item = parseFloat(data[i].data[0][1]);
+ if (item)
+ total += item;
+ }
+ }
+
+ function processDatapoints(plot, series, data, datapoints)
+ {
+ if (!processed)
+ {
+ processed = true;
+
+ canvas = plot.getCanvas();
+ target = $(canvas).parent();
+ options = plot.getOptions();
+
+ plot.setData(combine(plot.getData()));
+ }
+ }
+
+ function setupPie()
+ {
+ legendWidth = target.children().filter('.legend').children().width();
+
+ // calculate maximum radius and center point
+ maxRadius = Math.min(canvas.width,(canvas.height/options.series.pie.tilt))/2;
+ centerTop = (canvas.height/2)+options.series.pie.offset.top;
+ centerLeft = (canvas.width/2);
+
+ if (options.series.pie.offset.left=='auto')
+ if (options.legend.position.match('w'))
+ centerLeft += legendWidth/2;
+ else
+ centerLeft -= legendWidth/2;
+ else
+ centerLeft += options.series.pie.offset.left;
+
+ if (centerLeft<maxRadius)
+ centerLeft = maxRadius;
+ else if (centerLeft>canvas.width-maxRadius)
+ centerLeft = canvas.width-maxRadius;
+ }
+
+ function fixData(data)
+ {
+ for (var i = 0; i < data.length; ++i)
+ {
+ if (typeof(data[i].data)=='number')
+ data[i].data = [[1,data[i].data]];
+ else if (typeof(data[i].data)=='undefined' || typeof(data[i].data[0])=='undefined')
+ {
+ if (typeof(data[i].data)!='undefined' && typeof(data[i].data.label)!='undefined')
+ data[i].label = data[i].data.label; // fix weirdness coming from flot
+ data[i].data = [[1,0]];
+
+ }
+ }
+ return data;
+ }
+
+ function combine(data)
+ {
+ data = fixData(data);
+ calcTotal(data);
+ var combined = 0;
+ var numCombined = 0;
+ var color = options.series.pie.combine.color;
+
+ var newdata = [];
+ for (var i = 0; i < data.length; ++i)
+ {
+ // make sure its a number
+ data[i].data[0][1] = parseFloat(data[i].data[0][1]);
+ if (!data[i].data[0][1])
+ data[i].data[0][1] = 0;
+
+ if (data[i].data[0][1]/total<=options.series.pie.combine.threshold)
+ {
+ combined += data[i].data[0][1];
+ numCombined++;
+ if (!color)
+ color = data[i].color;
+ }
+ else
+ {
+ newdata.push({
+ data: [[1,data[i].data[0][1]]],
+ color: data[i].color,
+ label: data[i].label,
+ angle: (data[i].data[0][1]*(Math.PI*2))/total,
+ percent: (data[i].data[0][1]/total*100)
+ });
+ }
+ }
+ if (numCombined>0)
+ newdata.push({
+ data: [[1,combined]],
+ color: color,
+ label: options.series.pie.combine.label,
+ angle: (combined*(Math.PI*2))/total,
+ percent: (combined/total*100)
+ });
+ return newdata;
+ }
+
+ function draw(plot, newCtx)
+ {
+ if (!target) return; // if no series were passed
+ ctx = newCtx;
+
+ setupPie();
+ var slices = plot.getData();
+
+ var attempts = 0;
+ while (redraw && attempts<redrawAttempts)
+ {
+ redraw = false;
+ if (attempts>0)
+ maxRadius *= shrink;
+ attempts += 1;
+ clear();
+ if (options.series.pie.tilt<=0.8)
+ drawShadow();
+ drawPie();
+ }
+ if (attempts >= redrawAttempts) {
+ clear();
+ target.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>');
+ }
+
+ if ( plot.setSeries && plot.insertLegend )
+ {
+ plot.setSeries(slices);
+ plot.insertLegend();
+ }
+
+ // we're actually done at this point, just defining internal functions at this point
+
+ function clear()
+ {
+ ctx.clearRect(0,0,canvas.width,canvas.height);
+ target.children().filter('.pieLabel, .pieLabelBackground').remove();
+ }
+
+ function drawShadow()
+ {
+ var shadowLeft = 5;
+ var shadowTop = 15;
+ var edge = 10;
+ var alpha = 0.02;
+
+ // set radius
+ if (options.series.pie.radius>1)
+ var radius = options.series.pie.radius;
+ else
+ var radius = maxRadius * options.series.pie.radius;
+
+ if (radius>=(canvas.width/2)-shadowLeft || radius*options.series.pie.tilt>=(canvas.height/2)-shadowTop || radius<=edge)
+ return; // shadow would be outside canvas, so don't draw it
+
+ ctx.save();
+ ctx.translate(shadowLeft,shadowTop);
+ ctx.globalAlpha = alpha;
+ ctx.fillStyle = '#000';
+
+ // center and rotate to starting position
+ ctx.translate(centerLeft,centerTop);
+ ctx.scale(1, options.series.pie.tilt);
+
+ //radius -= edge;
+ for (var i=1; i<=edge; i++)
+ {
+ ctx.beginPath();
+ ctx.arc(0,0,radius,0,Math.PI*2,false);
+ ctx.fill();
+ radius -= i;
+ }
+
+ ctx.restore();
+ }
+
+ function drawPie()
+ {
+ startAngle = Math.PI*options.series.pie.startAngle;
+
+ // set radius
+ if (options.series.pie.radius>1)
+ var radius = options.series.pie.radius;
+ else
+ var radius = maxRadius * options.series.pie.radius;
+
+ // center and rotate to starting position
+ ctx.save();
+ ctx.translate(centerLeft,centerTop);
+ ctx.scale(1, options.series.pie.tilt);
+ //ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera
+
+ // draw slices
+ ctx.save();
+ var currentAngle = startAngle;
+ for (var i = 0; i < slices.length; ++i)
+ {
+ slices[i].startAngle = currentAngle;
+ drawSlice(slices[i].angle, slices[i].color, true);
+ }
+ ctx.restore();
+
+ // draw slice outlines
+ ctx.save();
+ ctx.lineWidth = options.series.pie.stroke.width;
+ currentAngle = startAngle;
+ for (var i = 0; i < slices.length; ++i)
+ drawSlice(slices[i].angle, options.series.pie.stroke.color, false);
+ ctx.restore();
+
+ // draw donut hole
+ drawDonutHole(ctx);
+
+ // draw labels
+ if (options.series.pie.label.show)
+ drawLabels();
+
+ // restore to original state
+ ctx.restore();
+
+ function drawSlice(angle, color, fill)
+ {
+ if (angle<=0)
+ return;
+
+ if (fill)
+ ctx.fillStyle = color;
+ else
+ {
+ ctx.strokeStyle = color;
+ ctx.lineJoin = 'round';
+ }
+
+ ctx.beginPath();
+ if (Math.abs(angle - Math.PI*2) > 0.000000001)
+ ctx.moveTo(0,0); // Center of the pie
+ else if ($.browser.msie)
+ angle -= 0.0001;
+ //ctx.arc(0,0,radius,0,angle,false); // This doesn't work properly in Opera
+ ctx.arc(0,0,radius,currentAngle,currentAngle+angle,false);
+ ctx.closePath();
+ //ctx.rotate(angle); // This doesn't work properly in Opera
+ currentAngle += angle;
+
+ if (fill)
+ ctx.fill();
+ else
+ ctx.stroke();
+ }
+
+ function drawLabels()
+ {
+ var currentAngle = startAngle;
+
+ // set radius
+ if (options.series.pie.label.radius>1)
+ var radius = options.series.pie.label.radius;
+ else
+ var radius = maxRadius * options.series.pie.label.radius;
+
+ for (var i = 0; i < slices.length; ++i)
+ {
+ if (slices[i].percent >= options.series.pie.label.threshold*100)
+ drawLabel(slices[i], currentAngle, i);
+ currentAngle += slices[i].angle;
+ }
+
+ function drawLabel(slice, startAngle, index)
+ {
+ if (slice.data[0][1]==0)
+ return;
+
+ // format label text
+ var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter;
+ if (lf)
+ text = lf(slice.label, slice);
+ else
+ text = slice.label;
+ if (plf)
+ text = plf(text, slice);
+
+ var halfAngle = ((startAngle+slice.angle) + startAngle)/2;
+ var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
+ var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;
+
+ var html = '<span class="pieLabel" id="pieLabel'+index+'" style="position:absolute;top:' + y + 'px;left:' + x + 'px;">' + text + "</span>";
+ target.append(html);
+ var label = target.children('#pieLabel'+index);
+ var labelTop = (y - label.height()/2);
+ var labelLeft = (x - label.width()/2);
+ label.css('top', labelTop);
+ label.css('left', labelLeft);
+
+ // check to make sure that the label is not outside the canvas
+ if (0-labelTop>0 || 0-labelLeft>0 || canvas.height-(labelTop+label.height())<0 || canvas.width-(labelLeft+label.width())<0)
+ redraw = true;
+
+ if (options.series.pie.label.background.opacity != 0) {
+ // put in the transparent background separately to avoid blended labels and label boxes
+ var c = options.series.pie.label.background.color;
+ if (c == null) {
+ c = slice.color;
+ }
+ var pos = 'top:'+labelTop+'px;left:'+labelLeft+'px;';
+ $('<div class="pieLabelBackground" style="position:absolute;width:' + label.width() + 'px;height:' + label.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').insertBefore(label).css('opacity', options.series.pie.label.background.opacity);
+ }
+ } // end individual label function
+ } // end drawLabels function
+ } // end drawPie function
+ } // end draw function
+
+ // Placed here because it needs to be accessed from multiple locations
+ function drawDonutHole(layer)
+ {
+ // draw donut hole
+ if(options.series.pie.innerRadius > 0)
+ {
+ // subtract the center
+ layer.save();
+ innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;
+ layer.globalCompositeOperation = 'destination-out'; // this does not work with excanvas, but it will fall back to using the stroke color
+ layer.beginPath();
+ layer.fillStyle = options.series.pie.stroke.color;
+ layer.arc(0,0,innerRadius,0,Math.PI*2,false);
+ layer.fill();
+ layer.closePath();
+ layer.restore();
+
+ // add inner stroke
+ layer.save();
+ layer.beginPath();
+ layer.strokeStyle = options.series.pie.stroke.color;
+ layer.arc(0,0,innerRadius,0,Math.PI*2,false);
+ layer.stroke();
+ layer.closePath();
+ layer.restore();
+ // TODO: add extra shadow inside hole (with a mask) if the pie is tilted.
+ }
+ }
+
+ //-- Additional Interactive related functions --
+
+ function isPointInPoly(poly, pt)
+ {
+ for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
+ ((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))
+ && (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
+ && (c = !c);
+ return c;
+ }
+
+ function findNearbySlice(mouseX, mouseY)
+ {
+ var slices = plot.getData(),
+ options = plot.getOptions(),
+ radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
+
+ for (var i = 0; i < slices.length; ++i)
+ {
+ var s = slices[i];
+
+ if(s.pie.show)
+ {
+ ctx.save();
+ ctx.beginPath();
+ ctx.moveTo(0,0); // Center of the pie
+ //ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here.
+ ctx.arc(0,0,radius,s.startAngle,s.startAngle+s.angle,false);
+ ctx.closePath();
+ x = mouseX-centerLeft;
+ y = mouseY-centerTop;
+ if(ctx.isPointInPath)
+ {
+ if (ctx.isPointInPath(mouseX-centerLeft, mouseY-centerTop))
+ {
+ //alert('found slice!');
+ ctx.restore();
+ return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
+ }
+ }
+ else
+ {
+ // excanvas for IE doesn;t support isPointInPath, this is a workaround.
+ p1X = (radius * Math.cos(s.startAngle));
+ p1Y = (radius * Math.sin(s.startAngle));
+ p2X = (radius * Math.cos(s.startAngle+(s.angle/4)));
+ p2Y = (radius * Math.sin(s.startAngle+(s.angle/4)));
+ p3X = (radius * Math.cos(s.startAngle+(s.angle/2)));
+ p3Y = (radius * Math.sin(s.startAngle+(s.angle/2)));
+ p4X = (radius * Math.cos(s.startAngle+(s.angle/1.5)));
+ p4Y = (radius * Math.sin(s.startAngle+(s.angle/1.5)));
+ p5X = (radius * Math.cos(s.startAngle+s.angle));
+ p5Y = (radius * Math.sin(s.startAngle+s.angle));
+ arrPoly = [[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];
+ arrPoint = [x,y];
+ // TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt?
+ if(isPointInPoly(arrPoly, arrPoint))
+ {
+ ctx.restore();
+ return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
+ }
+ }
+ ctx.restore();
+ }
+ }
+
+ return null;
+ }
+
+ function onMouseMove(e)
+ {
+ triggerClickHoverEvent('plothover', e);
+ }
+
+ function onClick(e)
+ {
+ triggerClickHoverEvent('plotclick', e);
+ }
+
+ // trigger click or hover event (they send the same parameters so we share their code)
+ function triggerClickHoverEvent(eventname, e)
+ {
+ var offset = plot.offset(),
+ canvasX = parseInt(e.pageX - offset.left),
+ canvasY = parseInt(e.pageY - offset.top),
+ item = findNearbySlice(canvasX, canvasY);
+
+ if (options.grid.autoHighlight)
+ {
+ // clear auto-highlights
+ for (var i = 0; i < highlights.length; ++i)
+ {
+ var h = highlights[i];
+ if (h.auto == eventname && !(item && h.series == item.series))
+ unhighlight(h.series);
+ }
+ }
+
+ // highlight the slice
+ if (item)
+ highlight(item.series, eventname);
+
+ // trigger any hover bind events
+ var pos = { pageX: e.pageX, pageY: e.pageY };
+ target.trigger(eventname, [ pos, item ]);
+ }
+
+ function highlight(s, auto)
+ {
+ if (typeof s == "number")
+ s = series[s];
+
+ var i = indexOfHighlight(s);
+ if (i == -1)
+ {
+ highlights.push({ series: s, auto: auto });
+ plot.triggerRedrawOverlay();
+ }
+ else if (!auto)
+ highlights[i].auto = false;
+ }
+
+ function unhighlight(s)
+ {
+ if (s == null)
+ {
+ highlights = [];
+ plot.triggerRedrawOverlay();
+ }
+
+ if (typeof s == "number")
+ s = series[s];
+
+ var i = indexOfHighlight(s);
+ if (i != -1)
+ {
+ highlights.splice(i, 1);
+ plot.triggerRedrawOverlay();
+ }
+ }
+
+ function indexOfHighlight(s)
+ {
+ for (var i = 0; i < highlights.length; ++i)
+ {
+ var h = highlights[i];
+ if (h.series == s)
+ return i;
+ }
+ return -1;
+ }
+
+ function drawOverlay(plot, octx)
+ {
+ //alert(options.series.pie.radius);
+ var options = plot.getOptions();
+ //alert(options.series.pie.radius);
+
+ var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
+
+ octx.save();
+ octx.translate(centerLeft, centerTop);
+ octx.scale(1, options.series.pie.tilt);
+
+ for (i = 0; i < highlights.length; ++i)
+ drawHighlight(highlights[i].series);
+
+ drawDonutHole(octx);
+
+ octx.restore();
+
+ function drawHighlight(series)
+ {
+ if (series.angle < 0) return;
+
+ //octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString();
+ octx.fillStyle = "rgba(255, 255, 255, "+options.series.pie.highlight.opacity+")"; // this is temporary until we have access to parseColor
+
+ octx.beginPath();
+ if (Math.abs(series.angle - Math.PI*2) > 0.000000001)
+ octx.moveTo(0,0); // Center of the pie
+ octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false);
+ octx.closePath();
+ octx.fill();
+ }
+
+ }
+
+ } // end init (plugin body)
+
+ // define pie specific options and their default values
+ var options = {
+ series: {
+ pie: {
+ show: false,
+ radius: 'auto', // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value)
+ innerRadius:0, /* for donut */
+ startAngle: 3/2,
+ tilt: 1,
+ offset: {
+ top: 0,
+ left: 'auto'
+ },
+ stroke: {
+ color: '#FFF',
+ width: 1
+ },
+ label: {
+ show: 'auto',
+ formatter: function(label, slice){
+ return '<div style="font-size:x-small;text-align:center;padding:2px;color:'+slice.color+';">'+label+'<br/>'+Math.round(slice.percent)+'%</div>';
+ }, // formatter function
+ radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)
+ background: {
+ color: null,
+ opacity: 0
+ },
+ threshold: 0 // percentage at which to hide the label (i.e. the slice is too narrow)
+ },
+ combine: {
+ threshold: -1, // percentage at which to combine little slices into one larger slice
+ color: null, // color to give the new slice (auto-generated if null)
+ label: 'Other' // label to give the new slice
+ },
+ highlight: {
+ //color: '#FFF', // will add this functionality once parseColor is available
+ opacity: 0.5
+ }
+ }
+ }
+ };
+
+ $.plot.plugins.push({
+ init: init,
+ options: options,
+ name: "pie",
+ version: "1.0"
+ });
+})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/flot/jquery.flot.selection.js b/SemanticResultFormats/resources/jquery/flot/jquery.flot.selection.js
new file mode 100644
index 00000000..7f7b3269
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/flot/jquery.flot.selection.js
@@ -0,0 +1,344 @@
+/*
+Flot plugin for selecting regions.
+
+The plugin defines the following options:
+
+ selection: {
+ mode: null or "x" or "y" or "xy",
+ color: color
+ }
+
+Selection support is enabled by setting the mode to one of "x", "y" or
+"xy". In "x" mode, the user will only be able to specify the x range,
+similarly for "y" mode. For "xy", the selection becomes a rectangle
+where both ranges can be specified. "color" is color of the selection
+(if you need to change the color later on, you can get to it with
+plot.getOptions().selection.color).
+
+When selection support is enabled, a "plotselected" event will be
+emitted on the DOM element you passed into the plot function. The
+event handler gets a parameter with the ranges selected on the axes,
+like this:
+
+ placeholder.bind("plotselected", function(event, ranges) {
+ alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
+ // similar for yaxis - with multiple axes, the extra ones are in
+ // x2axis, x3axis, ...
+ });
+
+The "plotselected" event is only fired when the user has finished
+making the selection. A "plotselecting" event is fired during the
+process with the same parameters as the "plotselected" event, in case
+you want to know what's happening while it's happening,
+
+A "plotunselected" event with no arguments is emitted when the user
+clicks the mouse to remove the selection.
+
+The plugin allso adds the following methods to the plot object:
+
+- setSelection(ranges, preventEvent)
+
+ Set the selection rectangle. The passed in ranges is on the same
+ form as returned in the "plotselected" event. If the selection mode
+ is "x", you should put in either an xaxis range, if the mode is "y"
+ you need to put in an yaxis range and both xaxis and yaxis if the
+ selection mode is "xy", like this:
+
+ setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
+
+ setSelection will trigger the "plotselected" event when called. If
+ you don't want that to happen, e.g. if you're inside a
+ "plotselected" handler, pass true as the second parameter. If you
+ are using multiple axes, you can specify the ranges on any of those,
+ e.g. as x2axis/x3axis/... instead of xaxis, the plugin picks the
+ first one it sees.
+
+- clearSelection(preventEvent)
+
+ Clear the selection rectangle. Pass in true to avoid getting a
+ "plotunselected" event.
+
+- getSelection()
+
+ Returns the current selection in the same format as the
+ "plotselected" event. If there's currently no selection, the
+ function returns null.
+
+*/
+
+(function ($) {
+ function init(plot) {
+ var selection = {
+ first: { x: -1, y: -1}, second: { x: -1, y: -1},
+ show: false,
+ active: false
+ };
+
+ // FIXME: The drag handling implemented here should be
+ // abstracted out, there's some similar code from a library in
+ // the navigation plugin, this should be massaged a bit to fit
+ // the Flot cases here better and reused. Doing this would
+ // make this plugin much slimmer.
+ var savedhandlers = {};
+
+ var mouseUpHandler = null;
+
+ function onMouseMove(e) {
+ if (selection.active) {
+ updateSelection(e);
+
+ plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
+ }
+ }
+
+ function onMouseDown(e) {
+ if (e.which != 1) // only accept left-click
+ return;
+
+ // cancel out any text selections
+ document.body.focus();
+
+ // prevent text selection and drag in old-school browsers
+ if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) {
+ savedhandlers.onselectstart = document.onselectstart;
+ document.onselectstart = function () { return false; };
+ }
+ if (document.ondrag !== undefined && savedhandlers.ondrag == null) {
+ savedhandlers.ondrag = document.ondrag;
+ document.ondrag = function () { return false; };
+ }
+
+ setSelectionPos(selection.first, e);
+
+ selection.active = true;
+
+ // this is a bit silly, but we have to use a closure to be
+ // able to whack the same handler again
+ mouseUpHandler = function (e) { onMouseUp(e); };
+
+ $(document).one("mouseup", mouseUpHandler);
+ }
+
+ function onMouseUp(e) {
+ mouseUpHandler = null;
+
+ // revert drag stuff for old-school browsers
+ if (document.onselectstart !== undefined)
+ document.onselectstart = savedhandlers.onselectstart;
+ if (document.ondrag !== undefined)
+ document.ondrag = savedhandlers.ondrag;
+
+ // no more dragging
+ selection.active = false;
+ updateSelection(e);
+
+ if (selectionIsSane())
+ triggerSelectedEvent();
+ else {
+ // this counts as a clear
+ plot.getPlaceholder().trigger("plotunselected", [ ]);
+ plot.getPlaceholder().trigger("plotselecting", [ null ]);
+ }
+
+ return false;
+ }
+
+ function getSelection() {
+ if (!selectionIsSane())
+ return null;
+
+ var r = {}, c1 = selection.first, c2 = selection.second;
+ $.each(plot.getAxes(), function (name, axis) {
+ if (axis.used) {
+ var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]);
+ r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) };
+ }
+ });
+ return r;
+ }
+
+ function triggerSelectedEvent() {
+ var r = getSelection();
+
+ plot.getPlaceholder().trigger("plotselected", [ r ]);
+
+ // backwards-compat stuff, to be removed in future
+ if (r.xaxis && r.yaxis)
+ plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
+ }
+
+ function clamp(min, value, max) {
+ return value < min ? min: (value > max ? max: value);
+ }
+
+ function setSelectionPos(pos, e) {
+ var o = plot.getOptions();
+ var offset = plot.getPlaceholder().offset();
+ var plotOffset = plot.getPlotOffset();
+ pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());
+ pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
+
+ if (o.selection.mode == "y")
+ pos.x = pos == selection.first ? 0 : plot.width();
+
+ if (o.selection.mode == "x")
+ pos.y = pos == selection.first ? 0 : plot.height();
+ }
+
+ function updateSelection(pos) {
+ if (pos.pageX == null)
+ return;
+
+ setSelectionPos(selection.second, pos);
+ if (selectionIsSane()) {
+ selection.show = true;
+ plot.triggerRedrawOverlay();
+ }
+ else
+ clearSelection(true);
+ }
+
+ function clearSelection(preventEvent) {
+ if (selection.show) {
+ selection.show = false;
+ plot.triggerRedrawOverlay();
+ if (!preventEvent)
+ plot.getPlaceholder().trigger("plotunselected", [ ]);
+ }
+ }
+
+ // function taken from markings support in Flot
+ function extractRange(ranges, coord) {
+ var axis, from, to, key, axes = plot.getAxes();
+
+ for (var k in axes) {
+ axis = axes[k];
+ if (axis.direction == coord) {
+ key = coord + axis.n + "axis";
+ if (!ranges[key] && axis.n == 1)
+ key = coord + "axis"; // support x1axis as xaxis
+ if (ranges[key]) {
+ from = ranges[key].from;
+ to = ranges[key].to;
+ break;
+ }
+ }
+ }
+
+ // backwards-compat stuff - to be removed in future
+ if (!ranges[key]) {
+ axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
+ from = ranges[coord + "1"];
+ to = ranges[coord + "2"];
+ }
+
+ // auto-reverse as an added bonus
+ if (from != null && to != null && from > to) {
+ var tmp = from;
+ from = to;
+ to = tmp;
+ }
+
+ return { from: from, to: to, axis: axis };
+ }
+
+ function setSelection(ranges, preventEvent) {
+ var axis, range, o = plot.getOptions();
+
+ if (o.selection.mode == "y") {
+ selection.first.x = 0;
+ selection.second.x = plot.width();
+ }
+ else {
+ range = extractRange(ranges, "x");
+
+ selection.first.x = range.axis.p2c(range.from);
+ selection.second.x = range.axis.p2c(range.to);
+ }
+
+ if (o.selection.mode == "x") {
+ selection.first.y = 0;
+ selection.second.y = plot.height();
+ }
+ else {
+ range = extractRange(ranges, "y");
+
+ selection.first.y = range.axis.p2c(range.from);
+ selection.second.y = range.axis.p2c(range.to);
+ }
+
+ selection.show = true;
+ plot.triggerRedrawOverlay();
+ if (!preventEvent && selectionIsSane())
+ triggerSelectedEvent();
+ }
+
+ function selectionIsSane() {
+ var minSize = 5;
+ return Math.abs(selection.second.x - selection.first.x) >= minSize &&
+ Math.abs(selection.second.y - selection.first.y) >= minSize;
+ }
+
+ plot.clearSelection = clearSelection;
+ plot.setSelection = setSelection;
+ plot.getSelection = getSelection;
+
+ plot.hooks.bindEvents.push(function(plot, eventHolder) {
+ var o = plot.getOptions();
+ if (o.selection.mode != null) {
+ eventHolder.mousemove(onMouseMove);
+ eventHolder.mousedown(onMouseDown);
+ }
+ });
+
+
+ plot.hooks.drawOverlay.push(function (plot, ctx) {
+ // draw selection
+ if (selection.show && selectionIsSane()) {
+ var plotOffset = plot.getPlotOffset();
+ var o = plot.getOptions();
+
+ ctx.save();
+ ctx.translate(plotOffset.left, plotOffset.top);
+
+ var c = $.color.parse(o.selection.color);
+
+ ctx.strokeStyle = c.scale('a', 0.8).toString();
+ ctx.lineWidth = 1;
+ ctx.lineJoin = "round";
+ ctx.fillStyle = c.scale('a', 0.4).toString();
+
+ var x = Math.min(selection.first.x, selection.second.x),
+ y = Math.min(selection.first.y, selection.second.y),
+ w = Math.abs(selection.second.x - selection.first.x),
+ h = Math.abs(selection.second.y - selection.first.y);
+
+ ctx.fillRect(x, y, w, h);
+ ctx.strokeRect(x, y, w, h);
+
+ ctx.restore();
+ }
+ });
+
+ plot.hooks.shutdown.push(function (plot, eventHolder) {
+ eventHolder.unbind("mousemove", onMouseMove);
+ eventHolder.unbind("mousedown", onMouseDown);
+
+ if (mouseUpHandler)
+ $(document).unbind("mouseup", mouseUpHandler);
+ });
+
+ }
+
+ $.plot.plugins.push({
+ init: init,
+ options: {
+ selection: {
+ mode: null, // one of null, "x", "y" or "xy"
+ color: "#e8cfac"
+ }
+ },
+ name: 'selection',
+ version: '1.1'
+ });
+})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/fullcalendar/GPL-LICENSE.txt b/SemanticResultFormats/resources/jquery/fullcalendar/GPL-LICENSE.txt
new file mode 100644
index 00000000..11dddd00
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fullcalendar/GPL-LICENSE.txt
@@ -0,0 +1,278 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
diff --git a/SemanticResultFormats/resources/jquery/fullcalendar/MIT-LICENSE.txt b/SemanticResultFormats/resources/jquery/fullcalendar/MIT-LICENSE.txt
new file mode 100644
index 00000000..46d47544
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fullcalendar/MIT-LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Adam Shaw
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/SemanticResultFormats/resources/jquery/fullcalendar/changelog.txt b/SemanticResultFormats/resources/jquery/fullcalendar/changelog.txt
new file mode 100644
index 00000000..67068f7c
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fullcalendar/changelog.txt
@@ -0,0 +1,322 @@
+
+version 1.5.4 (9/5/12)
+ - made compatible with jQuery 1.8.* (thx archaeron)
+ - bundled with jQuery 1.8.1 and jQuery UI 1.8.23
+
+version 1.5.3 (2/6/12)
+ - fixed dragging issue with jQuery UI 1.8.16 (issue 1168)
+ - bundled with jQuery 1.7.1 and jQuery UI 1.8.17
+
+version 1.5.2 (8/21/11)
+ - correctly process UTC "Z" ISO8601 date strings (issue 750)
+
+version 1.5.1 (4/9/11)
+ - more flexible ISO8601 date parsing (issue 814)
+ - more flexible parsing of UNIX timestamps (issue 826)
+ - FullCalendar now buildable from source on a Mac (issue 795)
+ - FullCalendar QA'd in FF4 (issue 883)
+ - upgraded to jQuery 1.5.2 (which supports IE9) and jQuery UI 1.8.11
+
+version 1.5 (3/19/11)
+ - slicker default styling for buttons
+ - reworked a lot of the calendar's HTML and accompanying CSS
+ (solves issues 327 and 395)
+ - more printer-friendly (fullcalendar-print.css)
+ - fullcalendar now inherits styles from jquery-ui themes differently.
+ styles for buttons are distinct from styles for calendar cells.
+ (solves issue 299)
+ - can now color events through FullCalendar options and Event-Object properties (issue 117)
+ THIS IS NOW THE PREFERRED METHOD OF COLORING EVENTS (as opposed to using className and CSS)
+ - FullCalendar options:
+ - eventColor (changes both background and border)
+ - eventBackgroundColor
+ - eventBorderColor
+ - eventTextColor
+ - Event-Object options:
+ - color (changes both background and border)
+ - backgroundColor
+ - borderColor
+ - textColor
+ - can now specify an event source as an *object* with a `url` property (json feed) or
+ an `events` property (function or array) with additional properties that will
+ be applied to the entire event source:
+ - color (changes both background and border)
+ - backgroudColor
+ - borderColor
+ - textColor
+ - className
+ - editable
+ - allDayDefault
+ - ignoreTimezone
+ - startParam (for a feed)
+ - endParam (for a feed)
+ - ANY OF THE JQUERY $.ajax OPTIONS
+ allows for easily changing from GET to POST and sending additional parameters (issue 386)
+ allows for easily attaching ajax handlers such as `error` (issue 754)
+ allows for turning caching on (issue 355)
+ - Google Calendar feeds are now specified differently:
+ - specify a simple string of your feed's URL
+ - specify an *object* with a `url` property of your feed's URL.
+ you can include any of the new Event-Source options in this object.
+ - the old `$.fullCalendar.gcalFeed` method still works
+ - no more IE7 SSL popup (issue 504)
+ - remove `cacheParam` - use json event source `cache` option instead
+ - latest jquery/jquery-ui
+
+version 1.4.11 (2/22/11)
+ - fixed rerenderEvents bug (issue 790)
+ - fixed bug with faulty dragging of events from all-day slot in agenda views
+ - bundled with jquery 1.5 and jquery-ui 1.8.9
+
+version 1.4.10 (1/2/11)
+ - fixed bug with resizing event to different week in 5-day month view (issue 740)
+ - fixed bug with events not sticking after a removeEvents call (issue 757)
+ - fixed bug with underlying parseTime method, and other uses of parseInt (issue 688)
+
+version 1.4.9 (11/16/10)
+ - new algorithm for vertically stacking events (issue 111)
+ - resizing an event to a different week (issue 306)
+ - bug: some events not rendered with consecutive calls to addEventSource (issue 679)
+
+version 1.4.8 (10/16/10)
+ - ignoreTimezone option (set to `false` to process UTC offsets in ISO8601 dates)
+ - bugfixes
+ - event refetching not being called under certain conditions (issues 417, 554)
+ - event refetching being called multiple times under certain conditions (issues 586, 616)
+ - selection cannot be triggered by right mouse button (issue 558)
+ - agenda view left axis sized incorrectly (issue 465)
+ - IE js error when calendar is too narrow (issue 517)
+ - agenda view looks strange when no scrollbars (issue 235)
+ - improved parsing of ISO8601 dates with UTC offsets
+ - $.fullCalendar.version
+ - an internal refactor of the code, for easier future development and modularity
+
+version 1.4.7 (7/5/10)
+ - "dropping" external objects onto the calendar
+ - droppable (boolean, to turn on/off)
+ - dropAccept (to filter which events the calendar will accept)
+ - drop (trigger)
+ - selectable options can now be specified with a View Option Hash
+ - bugfixes
+ - dragged & reverted events having wrong time text (issue 406)
+ - bug rendering events that have an endtime with seconds, but no hours/minutes (issue 477)
+ - gotoDate date overflow bug (issue 429)
+ - wrong date reported when clicking on edge of last column in agenda views (412)
+ - support newlines in event titles
+ - select/unselect callbacks now passes native js event
+
+version 1.4.6 (5/31/10)
+ - "selecting" days or timeslots
+ - options: selectable, selectHelper, unselectAuto, unselectCancel
+ - callbacks: select, unselect
+ - methods: select, unselect
+ - when dragging an event, the highlighting reflects the duration of the event
+ - code compressing by Google Closure Compiler
+ - bundled with jQuery 1.4.2 and jQuery UI 1.8.1
+
+version 1.4.5 (2/21/10)
+ - lazyFetching option, which can force the calendar to fetch events on every view/date change
+ - scroll state of agenda views are preserved when switching back to view
+ - bugfixes
+ - calling methods on an uninitialized fullcalendar throws error
+ - IE6/7 bug where an entire view becomes invisible (issue 320)
+ - error when rendering a hidden calendar (in jquery ui tabs for example) in IE (issue 340)
+ - interconnected bugs related to calendar resizing and scrollbars
+ - when switching views or clicking prev/next, calendar would "blink" (issue 333)
+ - liquid-width calendar's events shifted (depending on initial height of browser) (issue 341)
+ - more robust underlying algorithm for calendar resizing
+
+version 1.4.4 (2/3/10)
+ - optimized event rendering in all views (events render in 1/10 the time)
+ - gotoDate() does not force the calendar to unnecessarily rerender
+ - render() method now correctly readjusts height
+
+version 1.4.3 (12/22/09)
+ - added destroy method
+ - Google Calendar event pages respect currentTimezone
+ - caching now handled by jQuery's ajax
+ - protection from setting aspectRatio to zero
+ - bugfixes
+ - parseISO8601 and DST caused certain events to display day before
+ - button positioning problem in IE6
+ - ajax event source removed after recently being added, events still displayed
+ - event not displayed when end is an empty string
+ - dynamically setting calendar height when no events have been fetched, throws error
+
+version 1.4.2 (12/02/09)
+ - eventAfterRender trigger
+ - getDate & getView methods
+ - height & contentHeight options (explicitly sets the pixel height)
+ - minTime & maxTime options (restricts shown hours in agenda view)
+ - getters [for all options] and setters [for height, contentHeight, and aspectRatio ONLY! stay tuned..]
+ - render method now readjusts calendar's size
+ - bugfixes
+ - lightbox scripts that use iframes (like fancybox)
+ - day-of-week classNames were off when firstDay=1
+ - guaranteed space on right side of agenda events (even when stacked)
+ - accepts ISO8601 dates with a space (instead of 'T')
+
+version 1.4.1 (10/31/09)
+ - can exclude weekends with new 'weekends' option
+ - gcal feed 'currentTimezone' option
+ - bugfixes
+ - year/month/date option sometimes wouldn't set correctly (depending on current date)
+ - daylight savings issue caused agenda views to start at 1am (for BST users)
+ - cleanup of gcal.js code
+
+version 1.4 (10/19/09)
+ - agendaWeek and agendaDay views
+ - added some options for agenda views:
+ - allDaySlot
+ - allDayText
+ - firstHour
+ - slotMinutes
+ - defaultEventMinutes
+ - axisFormat
+ - modified some existing options/triggers to work with agenda views:
+ - dragOpacity and timeFormat can now accept a "View Hash" (a new concept)
+ - dayClick now has an allDay parameter
+ - eventDrop now has an an allDay parameter
+ (this will affect those who use revertFunc, adjust parameter list)
+ - added 'prevYear' and 'nextYear' for buttons in header
+ - minor change for theme users, ui-state-hover not applied to active/inactive buttons
+ - added event-color-changing example in docs
+ - better defaults for right-to-left themed button icons
+
+version 1.3.2 (10/13/09)
+ - Bugfixes (please upgrade from 1.3.1!)
+ - squashed potential infinite loop when addMonths and addDays
+ is called with an invalid date
+ - $.fullCalendar.parseDate() now correctly parses IETF format
+ - when switching views, the 'today' button sticks inactive, fixed
+ - gotoDate now can accept a single Date argument
+ - documentation for changes in 1.3.1 and 1.3.2 now on website
+
+version 1.3.1 (9/30/09)
+ - Important Bugfixes (please upgrade from 1.3!)
+ - When current date was late in the month, for long months, and prev/next buttons
+ were clicked in month-view, some months would be skipped/repeated
+ - In certain time zones, daylight savings time would cause certain days
+ to be misnumbered in month-view
+ - Subtle change in way week interval is chosen when switching from month to basicWeek/basicDay view
+ - Added 'allDayDefault' option
+ - Added 'changeView' and 'render' methods
+
+version 1.3 (9/21/09)
+ - different 'views': month/basicWeek/basicDay
+ - more flexible 'header' system for buttons
+ - themable by jQuery UI themes
+ - resizable events (require jQuery UI resizable plugin)
+ - rescoped & rewritten CSS, enhanced default look
+ - cleaner css & rendering techniques for right-to-left
+ - reworked options & API to support multiple views / be consistent with jQuery UI
+ - refactoring of entire codebase
+ - broken into different JS & CSS files, assembled w/ build scripts
+ - new test suite for new features, uses firebug-lite
+ - refactored docs
+ - Options
+ + date
+ + defaultView
+ + aspectRatio
+ + disableResizing
+ + monthNames (use instead of $.fullCalendar.monthNames)
+ + monthNamesShort (use instead of $.fullCalendar.monthAbbrevs)
+ + dayNames (use instead of $.fullCalendar.dayNames)
+ + dayNamesShort (use instead of $.fullCalendar.dayAbbrevs)
+ + theme
+ + buttonText
+ + buttonIcons
+ x draggable -> editable/disableDragging
+ x fixedWeeks -> weekMode
+ x abbrevDayHeadings -> columnFormat
+ x buttons/title -> header
+ x eventDragOpacity -> dragOpacity
+ x eventRevertDuration -> dragRevertDuration
+ x weekStart -> firstDay
+ x rightToLeft -> isRTL
+ x showTime (use 'allDay' CalEvent property instead)
+ - Triggered Actions
+ + eventResizeStart
+ + eventResizeStop
+ + eventResize
+ x monthDisplay -> viewDisplay
+ x resize -> windowResize
+ 'eventDrop' params changed, can revert if ajax cuts out
+ - CalEvent Properties
+ x showTime -> allDay
+ x draggable -> editable
+ 'end' is now INCLUSIVE when allDay=true
+ 'url' now produces a real <a> tag, more native clicking/tab behavior
+ - Methods:
+ + renderEvent
+ x prevMonth -> prev
+ x nextMonth -> next
+ x prevYear/nextYear -> moveDate
+ x refresh -> rerenderEvents/refetchEvents
+ x removeEvent -> removeEvents
+ x getEventsByID -> clientEvents
+ - Utilities:
+ 'formatDate' format string completely changed (inspired by jQuery UI datepicker + datejs)
+ 'formatDates' added to support date-ranges
+ - Google Calendar Options:
+ x draggable -> editable
+ - Bugfixes
+ - gcal extension fetched 25 results max, now fetches all
+
+version 1.2.1 (6/29/09)
+ - bugfixes
+ - allows and corrects invalid end dates for events
+ - doesn't throw an error in IE while rendering when display:none
+ - fixed 'loading' callback when used w/ multiple addEventSource calls
+ - gcal className can now be an array
+
+version 1.2 (5/31/09)
+ - expanded API
+ - 'className' CalEvent attribute
+ - 'source' CalEvent attribute
+ - dynamically get/add/remove/update events of current month
+ - locale improvements: change month/day name text
+ - better date formatting ($.fullCalendar.formatDate)
+ - multiple 'event sources' allowed
+ - dynamically add/remove event sources
+ - options for prevYear and nextYear buttons
+ - docs have been reworked (include addition of Google Calendar docs)
+ - changed behavior of parseDate for number strings
+ (now interpets as unix timestamp, not MS times)
+ - bugfixes
+ - rightToLeft month start bug
+ - off-by-one errors with month formatting commands
+ - events from previous months sticking when clicking prev/next quickly
+ - Google Calendar API changed to work w/ multiple event sources
+ - can also provide 'className' and 'draggable' options
+ - date utilties moved from $ to $.fullCalendar
+ - more documentation in source code
+ - minified version of fullcalendar.js
+ - test suit (available from svn)
+ - top buttons now use <button> w/ an inner <span> for better css cusomization
+ - thus CSS has changed. IF UPGRADING FROM PREVIOUS VERSIONS,
+ UPGRADE YOUR FULLCALENDAR.CSS FILE!!!
+
+version 1.1 (5/10/09)
+ - Added the following options:
+ - weekStart
+ - rightToLeft
+ - titleFormat
+ - timeFormat
+ - cacheParam
+ - resize
+ - Fixed rendering bugs
+ - Opera 9.25 (events placement & window resizing)
+ - IE6 (window resizing)
+ - Optimized window resizing for ALL browsers
+ - Events on same day now sorted by start time (but first by timespan)
+ - Correct z-index when dragging
+ - Dragging contained in overflow DIV for IE6
+ - Modified fullcalendar.css
+ - for right-to-left support
+ - for variable start-of-week
+ - for IE6 resizing bug
+ - for THEAD and TBODY (in 1.0, just used TBODY, restructured in 1.1)
+ - IF UPGRADING FROM FULLCALENDAR 1.0, YOU MUST UPGRADE FULLCALENDAR.CSS
+ !!!!!!!!!!!
+
diff --git a/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.css b/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.css
new file mode 100644
index 00000000..1f02ba42
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.css
@@ -0,0 +1,618 @@
+/*
+ * FullCalendar v1.5.4 Stylesheet
+ *
+ * Copyright (c) 2011 Adam Shaw
+ * Dual licensed under the MIT and GPL licenses, located in
+ * MIT-LICENSE.txt and GPL-LICENSE.txt respectively.
+ *
+ * Date: Tue Sep 4 23:38:33 2012 -0700
+ *
+ */
+
+
+.fc {
+ direction: ltr;
+ text-align: left;
+ }
+
+.fc table {
+ border-collapse: collapse;
+ border-spacing: 0;
+ }
+
+html .fc,
+.fc table {
+ font-size: 1em;
+ }
+
+.fc td,
+.fc th {
+ padding: 0;
+ vertical-align: top;
+ }
+
+
+
+/* Header
+------------------------------------------------------------------------*/
+
+.fc-header td {
+ white-space: nowrap;
+ }
+
+.fc-header-left {
+ width: 25%;
+ text-align: left;
+ }
+
+.fc-header-center {
+ text-align: center;
+ }
+
+.fc-header-right {
+ width: 25%;
+ text-align: right;
+ }
+
+.fc-header-title {
+ display: inline-block;
+ vertical-align: top;
+ }
+
+.fc-header-title h2 {
+ margin-top: 0;
+ white-space: nowrap;
+ }
+
+.fc .fc-header-space {
+ padding-left: 10px;
+ }
+
+.fc-header .fc-button {
+ margin-bottom: 1em;
+ vertical-align: top;
+ }
+
+/* buttons edges butting together */
+
+.fc-header .fc-button {
+ margin-right: -1px;
+ }
+
+.fc-header .fc-corner-right {
+ margin-right: 1px; /* back to normal */
+ }
+
+.fc-header .ui-corner-right {
+ margin-right: 0; /* back to normal */
+ }
+
+/* button layering (for border precedence) */
+
+.fc-header .fc-state-hover,
+.fc-header .ui-state-hover {
+ z-index: 2;
+ }
+
+.fc-header .fc-state-down {
+ z-index: 3;
+ }
+
+.fc-header .fc-state-active,
+.fc-header .ui-state-active {
+ z-index: 4;
+ }
+
+
+
+/* Content
+------------------------------------------------------------------------*/
+
+.fc-content {
+ clear: both;
+ }
+
+.fc-view {
+ width: 100%; /* needed for view switching (when view is absolute) */
+ overflow: hidden;
+ }
+
+
+
+/* Cell Styles
+------------------------------------------------------------------------*/
+
+.fc-widget-header, /* <th>, usually */
+.fc-widget-content { /* <td>, usually */
+ border: 1px solid #ccc;
+ }
+
+.fc-state-highlight { /* <td> today cell */ /* TODO: add .fc-today to <th> */
+ background: #ffc;
+ }
+
+.fc-cell-overlay { /* semi-transparent rectangle while dragging */
+ background: #9cf;
+ opacity: .2;
+ filter: alpha(opacity=20); /* for IE */
+ }
+
+
+
+/* Buttons
+------------------------------------------------------------------------*/
+
+.fc-button {
+ position: relative;
+ display: inline-block;
+ cursor: pointer;
+ }
+
+.fc-state-default { /* non-theme */
+ border-style: solid;
+ border-width: 1px 0;
+ }
+
+.fc-button-inner {
+ position: relative;
+ float: left;
+ overflow: hidden;
+ }
+
+.fc-state-default .fc-button-inner { /* non-theme */
+ border-style: solid;
+ border-width: 0 1px;
+ }
+
+.fc-button-content {
+ position: relative;
+ float: left;
+ height: 1.9em;
+ line-height: 1.9em;
+ padding: 0 .6em;
+ white-space: nowrap;
+ }
+
+/* icon (for jquery ui) */
+
+.fc-button-content .fc-icon-wrap {
+ position: relative;
+ float: left;
+ top: 50%;
+ }
+
+.fc-button-content .ui-icon {
+ position: relative;
+ float: left;
+ margin-top: -50%;
+ *margin-top: 0;
+ *top: -50%;
+ }
+
+/* gloss effect */
+
+.fc-state-default .fc-button-effect {
+ position: absolute;
+ top: 50%;
+ left: 0;
+ }
+
+.fc-state-default .fc-button-effect span {
+ position: absolute;
+ top: -100px;
+ left: 0;
+ width: 500px;
+ height: 100px;
+ border-width: 100px 0 0 1px;
+ border-style: solid;
+ border-color: #fff;
+ background: #444;
+ opacity: .09;
+ filter: alpha(opacity=9);
+ }
+
+/* button states (determines colors) */
+
+.fc-state-default,
+.fc-state-default .fc-button-inner {
+ border-style: solid;
+ border-color: #ccc #bbb #aaa;
+ background: #F3F3F3;
+ color: #000;
+ }
+
+.fc-state-hover,
+.fc-state-hover .fc-button-inner {
+ border-color: #999;
+ }
+
+.fc-state-down,
+.fc-state-down .fc-button-inner {
+ border-color: #555;
+ background: #777;
+ }
+
+.fc-state-active,
+.fc-state-active .fc-button-inner {
+ border-color: #555;
+ background: #777;
+ color: #fff;
+ }
+
+.fc-state-disabled,
+.fc-state-disabled .fc-button-inner {
+ color: #999;
+ border-color: #ddd;
+ }
+
+.fc-state-disabled {
+ cursor: default;
+ }
+
+.fc-state-disabled .fc-button-effect {
+ display: none;
+ }
+
+
+
+/* Global Event Styles
+------------------------------------------------------------------------*/
+
+.fc-event {
+ border-style: solid;
+ border-width: 0;
+ font-size: .85em;
+ cursor: default;
+ }
+
+a.fc-event,
+.fc-event-draggable {
+ cursor: pointer;
+ }
+
+a.fc-event {
+ text-decoration: none;
+ }
+
+.fc-rtl .fc-event {
+ text-align: right;
+ }
+
+.fc-event-skin {
+ border-color: #36c; /* default BORDER color */
+ background-color: #36c; /* default BACKGROUND color */
+ color: #fff; /* default TEXT color */
+ }
+
+.fc-event-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ border-style: solid;
+ border-width: 0;
+ overflow: hidden;
+ }
+
+.fc-event-time,
+.fc-event-title {
+ padding: 0 1px;
+ }
+
+.fc .ui-resizable-handle { /*** TODO: don't use ui-resizable anymore, change class ***/
+ display: block;
+ position: absolute;
+ z-index: 99999;
+ overflow: hidden; /* hacky spaces (IE6/7) */
+ font-size: 300%; /* */
+ line-height: 50%; /* */
+ }
+
+
+
+/* Horizontal Events
+------------------------------------------------------------------------*/
+
+.fc-event-hori {
+ border-width: 1px 0;
+ margin-bottom: 1px;
+ }
+
+/* resizable */
+
+.fc-event-hori .ui-resizable-e {
+ top: 0 !important; /* importants override pre jquery ui 1.7 styles */
+ right: -3px !important;
+ width: 7px !important;
+ height: 100% !important;
+ cursor: e-resize;
+ }
+
+.fc-event-hori .ui-resizable-w {
+ top: 0 !important;
+ left: -3px !important;
+ width: 7px !important;
+ height: 100% !important;
+ cursor: w-resize;
+ }
+
+.fc-event-hori .ui-resizable-handle {
+ _padding-bottom: 14px; /* IE6 had 0 height */
+ }
+
+
+
+/* Fake Rounded Corners (for buttons and events)
+------------------------------------------------------------*/
+
+.fc-corner-left {
+ margin-left: 1px;
+ }
+
+.fc-corner-left .fc-button-inner,
+.fc-corner-left .fc-event-inner {
+ margin-left: -1px;
+ }
+
+.fc-corner-right {
+ margin-right: 1px;
+ }
+
+.fc-corner-right .fc-button-inner,
+.fc-corner-right .fc-event-inner {
+ margin-right: -1px;
+ }
+
+.fc-corner-top {
+ margin-top: 1px;
+ }
+
+.fc-corner-top .fc-event-inner {
+ margin-top: -1px;
+ }
+
+.fc-corner-bottom {
+ margin-bottom: 1px;
+ }
+
+.fc-corner-bottom .fc-event-inner {
+ margin-bottom: -1px;
+ }
+
+
+
+/* Fake Rounded Corners SPECIFICALLY FOR EVENTS
+-----------------------------------------------------------------*/
+
+.fc-corner-left .fc-event-inner {
+ border-left-width: 1px;
+ }
+
+.fc-corner-right .fc-event-inner {
+ border-right-width: 1px;
+ }
+
+.fc-corner-top .fc-event-inner {
+ border-top-width: 1px;
+ }
+
+.fc-corner-bottom .fc-event-inner {
+ border-bottom-width: 1px;
+ }
+
+
+
+/* Reusable Separate-border Table
+------------------------------------------------------------*/
+
+table.fc-border-separate {
+ border-collapse: separate;
+ }
+
+.fc-border-separate th,
+.fc-border-separate td {
+ border-width: 1px 0 0 1px;
+ }
+
+.fc-border-separate th.fc-last,
+.fc-border-separate td.fc-last {
+ border-right-width: 1px;
+ }
+
+.fc-border-separate tr.fc-last th,
+.fc-border-separate tr.fc-last td {
+ border-bottom-width: 1px;
+ }
+
+.fc-border-separate tbody tr.fc-first td,
+.fc-border-separate tbody tr.fc-first th {
+ border-top-width: 0;
+ }
+
+
+
+/* Month View, Basic Week View, Basic Day View
+------------------------------------------------------------------------*/
+
+.fc-grid th {
+ text-align: center;
+ }
+
+.fc-grid .fc-day-number {
+ float: right;
+ padding: 0 2px;
+ }
+
+.fc-grid .fc-other-month .fc-day-number {
+ opacity: 0.3;
+ filter: alpha(opacity=30); /* for IE */
+ /* opacity with small font can sometimes look too faded
+ might want to set the 'color' property instead
+ making day-numbers bold also fixes the problem */
+ }
+
+.fc-grid .fc-day-content {
+ clear: both;
+ padding: 2px 2px 1px; /* distance between events and day edges */
+ }
+
+/* event styles */
+
+.fc-grid .fc-event-time {
+ font-weight: bold;
+ }
+
+/* right-to-left */
+
+.fc-rtl .fc-grid .fc-day-number {
+ float: left;
+ }
+
+.fc-rtl .fc-grid .fc-event-time {
+ float: right;
+ }
+
+
+
+/* Agenda Week View, Agenda Day View
+------------------------------------------------------------------------*/
+
+.fc-agenda table {
+ border-collapse: separate;
+ }
+
+.fc-agenda-days th {
+ text-align: center;
+ }
+
+.fc-agenda .fc-agenda-axis {
+ width: 50px;
+ padding: 0 4px;
+ vertical-align: middle;
+ text-align: right;
+ white-space: nowrap;
+ font-weight: normal;
+ }
+
+.fc-agenda .fc-day-content {
+ padding: 2px 2px 1px;
+ }
+
+/* make axis border take precedence */
+
+.fc-agenda-days .fc-agenda-axis {
+ border-right-width: 1px;
+ }
+
+.fc-agenda-days .fc-col0 {
+ border-left-width: 0;
+ }
+
+/* all-day area */
+
+.fc-agenda-allday th {
+ border-width: 0 1px;
+ }
+
+.fc-agenda-allday .fc-day-content {
+ min-height: 34px; /* TODO: doesnt work well in quirksmode */
+ _height: 34px;
+ }
+
+/* divider (between all-day and slots) */
+
+.fc-agenda-divider-inner {
+ height: 2px;
+ overflow: hidden;
+ }
+
+.fc-widget-header .fc-agenda-divider-inner {
+ background: #eee;
+ }
+
+/* slot rows */
+
+.fc-agenda-slots th {
+ border-width: 1px 1px 0;
+ }
+
+.fc-agenda-slots td {
+ border-width: 1px 0 0;
+ background: none;
+ }
+
+.fc-agenda-slots td div {
+ height: 20px;
+ }
+
+.fc-agenda-slots tr.fc-slot0 th,
+.fc-agenda-slots tr.fc-slot0 td {
+ border-top-width: 0;
+ }
+
+.fc-agenda-slots tr.fc-minor th,
+.fc-agenda-slots tr.fc-minor td {
+ border-top-style: dotted;
+ }
+
+.fc-agenda-slots tr.fc-minor th.ui-widget-header {
+ *border-top-style: solid; /* doesn't work with background in IE6/7 */
+ }
+
+
+
+/* Vertical Events
+------------------------------------------------------------------------*/
+
+.fc-event-vert {
+ border-width: 0 1px;
+ }
+
+.fc-event-vert .fc-event-head,
+.fc-event-vert .fc-event-content {
+ position: relative;
+ z-index: 2;
+ width: 100%;
+ overflow: hidden;
+ }
+
+.fc-event-vert .fc-event-time {
+ white-space: nowrap;
+ font-size: 10px;
+ }
+
+.fc-event-vert .fc-event-bg { /* makes the event lighter w/ a semi-transparent overlay */
+ position: absolute;
+ z-index: 1;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: #fff;
+ opacity: .3;
+ filter: alpha(opacity=30);
+ }
+
+.fc .ui-draggable-dragging .fc-event-bg, /* TODO: something nicer like .fc-opacity */
+.fc-select-helper .fc-event-bg {
+ display: none\9; /* for IE6/7/8. nested opacity filters while dragging don't work */
+ }
+
+/* resizable */
+
+.fc-event-vert .ui-resizable-s {
+ bottom: 0 !important; /* importants override pre jquery ui 1.7 styles */
+ width: 100% !important;
+ height: 8px !important;
+ overflow: hidden !important;
+ line-height: 8px !important;
+ font-size: 11px !important;
+ font-family: monospace;
+ text-align: center;
+ cursor: s-resize;
+ }
+
+.fc-agenda .ui-resizable-resizing { /* TODO: better selector */
+ _overflow: hidden;
+ }
+
+
diff --git a/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.js b/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.js
new file mode 100644
index 00000000..5d74d530
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.js
@@ -0,0 +1,5218 @@
+/**
+ * @preserve
+ * FullCalendar v1.5.4
+ * http://arshaw.com/fullcalendar/
+ *
+ * Use fullcalendar.css for basic styling.
+ * For event drag & drop, requires jQuery UI draggable.
+ * For event resizing, requires jQuery UI resizable.
+ *
+ * Copyright (c) 2011 Adam Shaw
+ * Dual licensed under the MIT and GPL licenses, located in
+ * MIT-LICENSE.txt and GPL-LICENSE.txt respectively.
+ *
+ * Date: Tue Sep 4 23:38:33 2012 -0700
+ *
+ */
+
+(function($, undefined) {
+
+
+var defaults = {
+
+ // display
+ defaultView: 'month',
+ aspectRatio: 1.35,
+ header: {
+ left: 'title',
+ center: '',
+ right: 'today prev,next'
+ },
+ weekends: true,
+
+ // editing
+ //editable: false,
+ //disableDragging: false,
+ //disableResizing: false,
+
+ allDayDefault: true,
+ ignoreTimezone: true,
+
+ // event ajax
+ lazyFetching: true,
+ startParam: 'start',
+ endParam: 'end',
+
+ // time formats
+ titleFormat: {
+ month: 'MMMM yyyy',
+ week: "MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}",
+ day: 'dddd, MMM d, yyyy'
+ },
+ columnFormat: {
+ month: 'ddd',
+ week: 'ddd M/d',
+ day: 'dddd M/d'
+ },
+ timeFormat: { // for event elements
+ '': 'h(:mm)t' // default
+ },
+
+ // locale
+ isRTL: false,
+ firstDay: 0,
+ monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
+ monthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
+ dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
+ dayNamesShort: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
+ buttonText: {
+ prev: '&nbsp;&#9668;&nbsp;',
+ next: '&nbsp;&#9658;&nbsp;',
+ prevYear: '&nbsp;&lt;&lt;&nbsp;',
+ nextYear: '&nbsp;&gt;&gt;&nbsp;',
+ today: 'today',
+ month: 'month',
+ week: 'week',
+ day: 'day'
+ },
+
+ // jquery-ui theming
+ theme: false,
+ buttonIcons: {
+ prev: 'circle-triangle-w',
+ next: 'circle-triangle-e'
+ },
+
+ //selectable: false,
+ unselectAuto: true,
+
+ dropAccept: '*'
+
+};
+
+// right-to-left defaults
+var rtlDefaults = {
+ header: {
+ left: 'next,prev today',
+ center: '',
+ right: 'title'
+ },
+ buttonText: {
+ prev: '&nbsp;&#9658;&nbsp;',
+ next: '&nbsp;&#9668;&nbsp;',
+ prevYear: '&nbsp;&gt;&gt;&nbsp;',
+ nextYear: '&nbsp;&lt;&lt;&nbsp;'
+ },
+ buttonIcons: {
+ prev: 'circle-triangle-e',
+ next: 'circle-triangle-w'
+ }
+};
+
+
+
+var fc = $.fullCalendar = { version: "1.5.4" };
+var fcViews = fc.views = {};
+
+
+$.fn.fullCalendar = function(options) {
+
+
+ // method calling
+ if (typeof options == 'string') {
+ var args = Array.prototype.slice.call(arguments, 1);
+ var res;
+ this.each(function() {
+ var calendar = $.data(this, 'fullCalendar');
+ if (calendar && $.isFunction(calendar[options])) {
+ var r = calendar[options].apply(calendar, args);
+ if (res === undefined) {
+ res = r;
+ }
+ if (options == 'destroy') {
+ $.removeData(this, 'fullCalendar');
+ }
+ }
+ });
+ if (res !== undefined) {
+ return res;
+ }
+ return this;
+ }
+
+
+ // would like to have this logic in EventManager, but needs to happen before options are recursively extended
+ var eventSources = options.eventSources || [];
+ delete options.eventSources;
+ if (options.events) {
+ eventSources.push(options.events);
+ delete options.events;
+ }
+
+
+ options = $.extend(true, {},
+ defaults,
+ (options.isRTL || options.isRTL===undefined && defaults.isRTL) ? rtlDefaults : {},
+ options
+ );
+
+
+ this.each(function(i, _element) {
+ var element = $(_element);
+ var calendar = new Calendar(element, options, eventSources);
+ element.data('fullCalendar', calendar); // TODO: look into memory leak implications
+ calendar.render();
+ });
+
+
+ return this;
+
+};
+
+
+// function for adding/overriding defaults
+function setDefaults(d) {
+ $.extend(true, defaults, d);
+}
+
+
+
+
+function Calendar(element, options, eventSources) {
+ var t = this;
+
+
+ // exports
+ t.options = options;
+ t.render = render;
+ t.destroy = destroy;
+ t.refetchEvents = refetchEvents;
+ t.reportEvents = reportEvents;
+ t.reportEventChange = reportEventChange;
+ t.rerenderEvents = rerenderEvents;
+ t.changeView = changeView;
+ t.select = select;
+ t.unselect = unselect;
+ t.prev = prev;
+ t.next = next;
+ t.prevYear = prevYear;
+ t.nextYear = nextYear;
+ t.today = today;
+ t.gotoDate = gotoDate;
+ t.incrementDate = incrementDate;
+ t.formatDate = function(format, date) { return formatDate(format, date, options) };
+ t.formatDates = function(format, date1, date2) { return formatDates(format, date1, date2, options) };
+ t.getDate = getDate;
+ t.getView = getView;
+ t.option = option;
+ t.trigger = trigger;
+
+
+ // imports
+ EventManager.call(t, options, eventSources);
+ var isFetchNeeded = t.isFetchNeeded;
+ var fetchEvents = t.fetchEvents;
+
+
+ // locals
+ var _element = element[0];
+ var header;
+ var headerElement;
+ var content;
+ var tm; // for making theme classes
+ var currentView;
+ var viewInstances = {};
+ var elementOuterWidth;
+ var suggestedViewHeight;
+ var absoluteViewElement;
+ var resizeUID = 0;
+ var ignoreWindowResize = 0;
+ var date = new Date();
+ var events = [];
+ var _dragElement;
+
+
+
+ /* Main Rendering
+ -----------------------------------------------------------------------------*/
+
+
+ setYMD(date, options.year, options.month, options.date);
+
+
+ function render(inc) {
+ if (!content) {
+ initialRender();
+ }else{
+ calcSize();
+ markSizesDirty();
+ markEventsDirty();
+ renderView(inc);
+ }
+ }
+
+
+ function initialRender() {
+ tm = options.theme ? 'ui' : 'fc';
+ element.addClass('fc');
+ if (options.isRTL) {
+ element.addClass('fc-rtl');
+ }
+ if (options.theme) {
+ element.addClass('ui-widget');
+ }
+ content = $("<div class='fc-content' style='position:relative'/>")
+ .prependTo(element);
+ header = new Header(t, options);
+ headerElement = header.render();
+ if (headerElement) {
+ element.prepend(headerElement);
+ }
+ changeView(options.defaultView);
+ $(window).resize(windowResize);
+ // needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResize
+ if (!bodyVisible()) {
+ lateRender();
+ }
+ }
+
+
+ // called when we know the calendar couldn't be rendered when it was initialized,
+ // but we think it's ready now
+ function lateRender() {
+ setTimeout(function() { // IE7 needs this so dimensions are calculated correctly
+ if (!currentView.start && bodyVisible()) { // !currentView.start makes sure this never happens more than once
+ renderView();
+ }
+ },0);
+ }
+
+
+ function destroy() {
+ $(window).unbind('resize', windowResize);
+ header.destroy();
+ content.remove();
+ element.removeClass('fc fc-rtl ui-widget');
+ }
+
+
+
+ function elementVisible() {
+ return _element.offsetWidth !== 0;
+ }
+
+
+ function bodyVisible() {
+ return $('body')[0].offsetWidth !== 0;
+ }
+
+
+
+ /* View Rendering
+ -----------------------------------------------------------------------------*/
+
+ // TODO: improve view switching (still weird transition in IE, and FF has whiteout problem)
+
+ function changeView(newViewName) {
+ if (!currentView || newViewName != currentView.name) {
+ ignoreWindowResize++; // because setMinHeight might change the height before render (and subsequently setSize) is reached
+
+ unselect();
+
+ var oldView = currentView;
+ var newViewElement;
+
+ if (oldView) {
+ (oldView.beforeHide || noop)(); // called before changing min-height. if called after, scroll state is reset (in Opera)
+ setMinHeight(content, content.height());
+ oldView.element.hide();
+ }else{
+ setMinHeight(content, 1); // needs to be 1 (not 0) for IE7, or else view dimensions miscalculated
+ }
+ content.css('overflow', 'hidden');
+
+ currentView = viewInstances[newViewName];
+ if (currentView) {
+ currentView.element.show();
+ }else{
+ currentView = viewInstances[newViewName] = new fcViews[newViewName](
+ newViewElement = absoluteViewElement =
+ $("<div class='fc-view fc-view-" + newViewName + "' style='position:absolute'/>")
+ .appendTo(content),
+ t // the calendar object
+ );
+ }
+
+ if (oldView) {
+ header.deactivateButton(oldView.name);
+ }
+ header.activateButton(newViewName);
+
+ renderView(); // after height has been set, will make absoluteViewElement's position=relative, then set to null
+
+ content.css('overflow', '');
+ if (oldView) {
+ setMinHeight(content, 1);
+ }
+
+ if (!newViewElement) {
+ (currentView.afterShow || noop)(); // called after setting min-height/overflow, so in final scroll state (for Opera)
+ }
+
+ ignoreWindowResize--;
+ }
+ }
+
+
+
+ function renderView(inc) {
+ if (elementVisible()) {
+ ignoreWindowResize++; // because renderEvents might temporarily change the height before setSize is reached
+
+ unselect();
+
+ if (suggestedViewHeight === undefined) {
+ calcSize();
+ }
+
+ var forceEventRender = false;
+ if (!currentView.start || inc || date < currentView.start || date >= currentView.end) {
+ // view must render an entire new date range (and refetch/render events)
+ currentView.render(date, inc || 0); // responsible for clearing events
+ setSize(true);
+ forceEventRender = true;
+ }
+ else if (currentView.sizeDirty) {
+ // view must resize (and rerender events)
+ currentView.clearEvents();
+ setSize();
+ forceEventRender = true;
+ }
+ else if (currentView.eventsDirty) {
+ currentView.clearEvents();
+ forceEventRender = true;
+ }
+ currentView.sizeDirty = false;
+ currentView.eventsDirty = false;
+ updateEvents(forceEventRender);
+
+ elementOuterWidth = element.outerWidth();
+
+ header.updateTitle(currentView.title);
+ var today = new Date();
+ if (today >= currentView.start && today < currentView.end) {
+ header.disableButton('today');
+ }else{
+ header.enableButton('today');
+ }
+
+ ignoreWindowResize--;
+ currentView.trigger('viewDisplay', _element);
+ }
+ }
+
+
+
+ /* Resizing
+ -----------------------------------------------------------------------------*/
+
+
+ function updateSize() {
+ markSizesDirty();
+ if (elementVisible()) {
+ calcSize();
+ setSize();
+ unselect();
+ currentView.clearEvents();
+ currentView.renderEvents(events);
+ currentView.sizeDirty = false;
+ }
+ }
+
+
+ function markSizesDirty() {
+ $.each(viewInstances, function(i, inst) {
+ inst.sizeDirty = true;
+ });
+ }
+
+
+ function calcSize() {
+ if (options.contentHeight) {
+ suggestedViewHeight = options.contentHeight;
+ }
+ else if (options.height) {
+ suggestedViewHeight = options.height - (headerElement ? headerElement.height() : 0) - vsides(content);
+ }
+ else {
+ suggestedViewHeight = Math.round(content.width() / Math.max(options.aspectRatio, .5));
+ }
+ }
+
+
+ function setSize(dateChanged) { // todo: dateChanged?
+ ignoreWindowResize++;
+ currentView.setHeight(suggestedViewHeight, dateChanged);
+ if (absoluteViewElement) {
+ absoluteViewElement.css('position', 'relative');
+ absoluteViewElement = null;
+ }
+ currentView.setWidth(content.width(), dateChanged);
+ ignoreWindowResize--;
+ }
+
+
+ function windowResize() {
+ if (!ignoreWindowResize) {
+ if (currentView.start) { // view has already been rendered
+ var uid = ++resizeUID;
+ setTimeout(function() { // add a delay
+ if (uid == resizeUID && !ignoreWindowResize && elementVisible()) {
+ if (elementOuterWidth != (elementOuterWidth = element.outerWidth())) {
+ ignoreWindowResize++; // in case the windowResize callback changes the height
+ updateSize();
+ currentView.trigger('windowResize', _element);
+ ignoreWindowResize--;
+ }
+ }
+ }, 200);
+ }else{
+ // calendar must have been initialized in a 0x0 iframe that has just been resized
+ lateRender();
+ }
+ }
+ }
+
+
+
+ /* Event Fetching/Rendering
+ -----------------------------------------------------------------------------*/
+
+
+ // fetches events if necessary, rerenders events if necessary (or if forced)
+ function updateEvents(forceRender) {
+ if (!options.lazyFetching || isFetchNeeded(currentView.visStart, currentView.visEnd)) {
+ refetchEvents();
+ }
+ else if (forceRender) {
+ rerenderEvents();
+ }
+ }
+
+
+ function refetchEvents() {
+ fetchEvents(currentView.visStart, currentView.visEnd); // will call reportEvents
+ }
+
+
+ // called when event data arrives
+ function reportEvents(_events) {
+ events = _events;
+ rerenderEvents();
+ }
+
+
+ // called when a single event's data has been changed
+ function reportEventChange(eventID) {
+ rerenderEvents(eventID);
+ }
+
+
+ // attempts to rerenderEvents
+ function rerenderEvents(modifiedEventID) {
+ markEventsDirty();
+ if (elementVisible()) {
+ currentView.clearEvents();
+ currentView.renderEvents(events, modifiedEventID);
+ currentView.eventsDirty = false;
+ }
+ }
+
+
+ function markEventsDirty() {
+ $.each(viewInstances, function(i, inst) {
+ inst.eventsDirty = true;
+ });
+ }
+
+
+
+ /* Selection
+ -----------------------------------------------------------------------------*/
+
+
+ function select(start, end, allDay) {
+ currentView.select(start, end, allDay===undefined ? true : allDay);
+ }
+
+
+ function unselect() { // safe to be called before renderView
+ if (currentView) {
+ currentView.unselect();
+ }
+ }
+
+
+
+ /* Date
+ -----------------------------------------------------------------------------*/
+
+
+ function prev() {
+ renderView(-1);
+ }
+
+
+ function next() {
+ renderView(1);
+ }
+
+
+ function prevYear() {
+ addYears(date, -1);
+ renderView();
+ }
+
+
+ function nextYear() {
+ addYears(date, 1);
+ renderView();
+ }
+
+
+ function today() {
+ date = new Date();
+ renderView();
+ }
+
+
+ function gotoDate(year, month, dateOfMonth) {
+ if (year instanceof Date) {
+ date = cloneDate(year); // provided 1 argument, a Date
+ }else{
+ setYMD(date, year, month, dateOfMonth);
+ }
+ renderView();
+ }
+
+
+ function incrementDate(years, months, days) {
+ if (years !== undefined) {
+ addYears(date, years);
+ }
+ if (months !== undefined) {
+ addMonths(date, months);
+ }
+ if (days !== undefined) {
+ addDays(date, days);
+ }
+ renderView();
+ }
+
+
+ function getDate() {
+ return cloneDate(date);
+ }
+
+
+
+ /* Misc
+ -----------------------------------------------------------------------------*/
+
+
+ function getView() {
+ return currentView;
+ }
+
+
+ function option(name, value) {
+ if (value === undefined) {
+ return options[name];
+ }
+ if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') {
+ options[name] = value;
+ updateSize();
+ }
+ }
+
+
+ function trigger(name, thisObj) {
+ if (options[name]) {
+ return options[name].apply(
+ thisObj || _element,
+ Array.prototype.slice.call(arguments, 2)
+ );
+ }
+ }
+
+
+
+ /* External Dragging
+ ------------------------------------------------------------------------*/
+
+ if (options.droppable) {
+ $(document)
+ .bind('dragstart', function(ev, ui) {
+ var _e = ev.target;
+ var e = $(_e);
+ if (!e.parents('.fc').length) { // not already inside a calendar
+ var accept = options.dropAccept;
+ if ($.isFunction(accept) ? accept.call(_e, e) : e.is(accept)) {
+ _dragElement = _e;
+ currentView.dragStart(_dragElement, ev, ui);
+ }
+ }
+ })
+ .bind('dragstop', function(ev, ui) {
+ if (_dragElement) {
+ currentView.dragStop(_dragElement, ev, ui);
+ _dragElement = null;
+ }
+ });
+ }
+
+
+}
+
+function Header(calendar, options) {
+ var t = this;
+
+
+ // exports
+ t.render = render;
+ t.destroy = destroy;
+ t.updateTitle = updateTitle;
+ t.activateButton = activateButton;
+ t.deactivateButton = deactivateButton;
+ t.disableButton = disableButton;
+ t.enableButton = enableButton;
+
+
+ // locals
+ var element = $([]);
+ var tm;
+
+
+
+ function render() {
+ tm = options.theme ? 'ui' : 'fc';
+ var sections = options.header;
+ if (sections) {
+ element = $("<table class='fc-header' style='width:100%'/>")
+ .append(
+ $("<tr/>")
+ .append(renderSection('left'))
+ .append(renderSection('center'))
+ .append(renderSection('right'))
+ );
+ return element;
+ }
+ }
+
+
+ function destroy() {
+ element.remove();
+ }
+
+
+ function renderSection(position) {
+ var e = $("<td class='fc-header-" + position + "'/>");
+ var buttonStr = options.header[position];
+ if (buttonStr) {
+ $.each(buttonStr.split(' '), function(i) {
+ if (i > 0) {
+ e.append("<span class='fc-header-space'/>");
+ }
+ var prevButton;
+ $.each(this.split(','), function(j, buttonName) {
+ if (buttonName == 'title') {
+ e.append("<span class='fc-header-title'><h2>&nbsp;</h2></span>");
+ if (prevButton) {
+ prevButton.addClass(tm + '-corner-right');
+ }
+ prevButton = null;
+ }else{
+ var buttonClick;
+ if (calendar[buttonName]) {
+ buttonClick = calendar[buttonName]; // calendar method
+ }
+ else if (fcViews[buttonName]) {
+ buttonClick = function() {
+ button.removeClass(tm + '-state-hover'); // forget why
+ calendar.changeView(buttonName);
+ };
+ }
+ if (buttonClick) {
+ var icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null; // why are we using smartProperty here?
+ var text = smartProperty(options.buttonText, buttonName); // why are we using smartProperty here?
+ var button = $(
+ "<span class='fc-button fc-button-" + buttonName + " " + tm + "-state-default'>" +
+ "<span class='fc-button-inner'>" +
+ "<span class='fc-button-content'>" +
+ (icon ?
+ "<span class='fc-icon-wrap'>" +
+ "<span class='ui-icon ui-icon-" + icon + "'/>" +
+ "</span>" :
+ text
+ ) +
+ "</span>" +
+ "<span class='fc-button-effect'><span></span></span>" +
+ "</span>" +
+ "</span>"
+ );
+ if (button) {
+ button
+ .click(function() {
+ if (!button.hasClass(tm + '-state-disabled')) {
+ buttonClick();
+ }
+ })
+ .mousedown(function() {
+ button
+ .not('.' + tm + '-state-active')
+ .not('.' + tm + '-state-disabled')
+ .addClass(tm + '-state-down');
+ })
+ .mouseup(function() {
+ button.removeClass(tm + '-state-down');
+ })
+ .hover(
+ function() {
+ button
+ .not('.' + tm + '-state-active')
+ .not('.' + tm + '-state-disabled')
+ .addClass(tm + '-state-hover');
+ },
+ function() {
+ button
+ .removeClass(tm + '-state-hover')
+ .removeClass(tm + '-state-down');
+ }
+ )
+ .appendTo(e);
+ if (!prevButton) {
+ button.addClass(tm + '-corner-left');
+ }
+ prevButton = button;
+ }
+ }
+ }
+ });
+ if (prevButton) {
+ prevButton.addClass(tm + '-corner-right');
+ }
+ });
+ }
+ return e;
+ }
+
+
+ function updateTitle(html) {
+ element.find('h2')
+ .html(html);
+ }
+
+
+ function activateButton(buttonName) {
+ element.find('span.fc-button-' + buttonName)
+ .addClass(tm + '-state-active');
+ }
+
+
+ function deactivateButton(buttonName) {
+ element.find('span.fc-button-' + buttonName)
+ .removeClass(tm + '-state-active');
+ }
+
+
+ function disableButton(buttonName) {
+ element.find('span.fc-button-' + buttonName)
+ .addClass(tm + '-state-disabled');
+ }
+
+
+ function enableButton(buttonName) {
+ element.find('span.fc-button-' + buttonName)
+ .removeClass(tm + '-state-disabled');
+ }
+
+
+}
+
+fc.sourceNormalizers = [];
+fc.sourceFetchers = [];
+
+var ajaxDefaults = {
+ dataType: 'json',
+ cache: false
+};
+
+var eventGUID = 1;
+
+
+function EventManager(options, _sources) {
+ var t = this;
+
+
+ // exports
+ t.isFetchNeeded = isFetchNeeded;
+ t.fetchEvents = fetchEvents;
+ t.addEventSource = addEventSource;
+ t.removeEventSource = removeEventSource;
+ t.updateEvent = updateEvent;
+ t.renderEvent = renderEvent;
+ t.removeEvents = removeEvents;
+ t.clientEvents = clientEvents;
+ t.normalizeEvent = normalizeEvent;
+
+
+ // imports
+ var trigger = t.trigger;
+ var getView = t.getView;
+ var reportEvents = t.reportEvents;
+
+
+ // locals
+ var stickySource = { events: [] };
+ var sources = [ stickySource ];
+ var rangeStart, rangeEnd;
+ var currentFetchID = 0;
+ var pendingSourceCnt = 0;
+ var loadingLevel = 0;
+ var cache = [];
+
+
+ for (var i=0; i<_sources.length; i++) {
+ _addEventSource(_sources[i]);
+ }
+
+
+
+ /* Fetching
+ -----------------------------------------------------------------------------*/
+
+
+ function isFetchNeeded(start, end) {
+ return !rangeStart || start < rangeStart || end > rangeEnd;
+ }
+
+
+ function fetchEvents(start, end) {
+ rangeStart = start;
+ rangeEnd = end;
+ cache = [];
+ var fetchID = ++currentFetchID;
+ var len = sources.length;
+ pendingSourceCnt = len;
+ for (var i=0; i<len; i++) {
+ fetchEventSource(sources[i], fetchID);
+ }
+ }
+
+
+ function fetchEventSource(source, fetchID) {
+ _fetchEventSource(source, function(events) {
+ if (fetchID == currentFetchID) {
+ if (events) {
+ for (var i=0; i<events.length; i++) {
+ events[i].source = source;
+ normalizeEvent(events[i]);
+ }
+ cache = cache.concat(events);
+ }
+ pendingSourceCnt--;
+ if (!pendingSourceCnt) {
+ reportEvents(cache);
+ }
+ }
+ });
+ }
+
+
+ function _fetchEventSource(source, callback) {
+ var i;
+ var fetchers = fc.sourceFetchers;
+ var res;
+ for (i=0; i<fetchers.length; i++) {
+ res = fetchers[i](source, rangeStart, rangeEnd, callback);
+ if (res === true) {
+ // the fetcher is in charge. made its own async request
+ return;
+ }
+ else if (typeof res == 'object') {
+ // the fetcher returned a new source. process it
+ _fetchEventSource(res, callback);
+ return;
+ }
+ }
+ var events = source.events;
+ if (events) {
+ if ($.isFunction(events)) {
+ pushLoading();
+ events(cloneDate(rangeStart), cloneDate(rangeEnd), function(events) {
+ callback(events);
+ popLoading();
+ });
+ }
+ else if ($.isArray(events)) {
+ callback(events);
+ }
+ else {
+ callback();
+ }
+ }else{
+ var url = source.url;
+ if (url) {
+ var success = source.success;
+ var error = source.error;
+ var complete = source.complete;
+ var data = $.extend({}, source.data || {});
+ var startParam = firstDefined(source.startParam, options.startParam);
+ var endParam = firstDefined(source.endParam, options.endParam);
+ if (startParam) {
+ data[startParam] = Math.round(+rangeStart / 1000);
+ }
+ if (endParam) {
+ data[endParam] = Math.round(+rangeEnd / 1000);
+ }
+ pushLoading();
+ $.ajax($.extend({}, ajaxDefaults, source, {
+ data: data,
+ success: function(events) {
+ events = events || [];
+ var res = applyAll(success, this, arguments);
+ if ($.isArray(res)) {
+ events = res;
+ }
+ callback(events);
+ },
+ error: function() {
+ applyAll(error, this, arguments);
+ callback();
+ },
+ complete: function() {
+ applyAll(complete, this, arguments);
+ popLoading();
+ }
+ }));
+ }else{
+ callback();
+ }
+ }
+ }
+
+
+
+ /* Sources
+ -----------------------------------------------------------------------------*/
+
+
+ function addEventSource(source) {
+ source = _addEventSource(source);
+ if (source) {
+ pendingSourceCnt++;
+ fetchEventSource(source, currentFetchID); // will eventually call reportEvents
+ }
+ }
+
+
+ function _addEventSource(source) {
+ if ($.isFunction(source) || $.isArray(source)) {
+ source = { events: source };
+ }
+ else if (typeof source == 'string') {
+ source = { url: source };
+ }
+ if (typeof source == 'object') {
+ normalizeSource(source);
+ sources.push(source);
+ return source;
+ }
+ }
+
+
+ function removeEventSource(source) {
+ sources = $.grep(sources, function(src) {
+ return !isSourcesEqual(src, source);
+ });
+ // remove all client events from that source
+ cache = $.grep(cache, function(e) {
+ return !isSourcesEqual(e.source, source);
+ });
+ reportEvents(cache);
+ }
+
+
+
+ /* Manipulation
+ -----------------------------------------------------------------------------*/
+
+
+ function updateEvent(event) { // update an existing event
+ var i, len = cache.length, e,
+ defaultEventEnd = getView().defaultEventEnd, // getView???
+ startDelta = event.start - event._start,
+ endDelta = event.end ?
+ (event.end - (event._end || defaultEventEnd(event))) // event._end would be null if event.end
+ : 0; // was null and event was just resized
+ for (i=0; i<len; i++) {
+ e = cache[i];
+ if (e._id == event._id && e != event) {
+ e.start = new Date(+e.start + startDelta);
+ if (event.end) {
+ if (e.end) {
+ e.end = new Date(+e.end + endDelta);
+ }else{
+ e.end = new Date(+defaultEventEnd(e) + endDelta);
+ }
+ }else{
+ e.end = null;
+ }
+ e.title = event.title;
+ e.url = event.url;
+ e.allDay = event.allDay;
+ e.className = event.className;
+ e.editable = event.editable;
+ e.color = event.color;
+ e.backgroudColor = event.backgroudColor;
+ e.borderColor = event.borderColor;
+ e.textColor = event.textColor;
+ normalizeEvent(e);
+ }
+ }
+ normalizeEvent(event);
+ reportEvents(cache);
+ }
+
+
+ function renderEvent(event, stick) {
+ normalizeEvent(event);
+ if (!event.source) {
+ if (stick) {
+ stickySource.events.push(event);
+ event.source = stickySource;
+ }
+ cache.push(event);
+ }
+ reportEvents(cache);
+ }
+
+
+ function removeEvents(filter) {
+ if (!filter) { // remove all
+ cache = [];
+ // clear all array sources
+ for (var i=0; i<sources.length; i++) {
+ if ($.isArray(sources[i].events)) {
+ sources[i].events = [];
+ }
+ }
+ }else{
+ if (!$.isFunction(filter)) { // an event ID
+ var id = filter + '';
+ filter = function(e) {
+ return e._id == id;
+ };
+ }
+ cache = $.grep(cache, filter, true);
+ // remove events from array sources
+ for (var i=0; i<sources.length; i++) {
+ if ($.isArray(sources[i].events)) {
+ sources[i].events = $.grep(sources[i].events, filter, true);
+ }
+ }
+ }
+ reportEvents(cache);
+ }
+
+
+ function clientEvents(filter) {
+ if ($.isFunction(filter)) {
+ return $.grep(cache, filter);
+ }
+ else if (filter) { // an event ID
+ filter += '';
+ return $.grep(cache, function(e) {
+ return e._id == filter;
+ });
+ }
+ return cache; // else, return all
+ }
+
+
+
+ /* Loading State
+ -----------------------------------------------------------------------------*/
+
+
+ function pushLoading() {
+ if (!loadingLevel++) {
+ trigger('loading', null, true);
+ }
+ }
+
+
+ function popLoading() {
+ if (!--loadingLevel) {
+ trigger('loading', null, false);
+ }
+ }
+
+
+
+ /* Event Normalization
+ -----------------------------------------------------------------------------*/
+
+
+ function normalizeEvent(event) {
+ var source = event.source || {};
+ var ignoreTimezone = firstDefined(source.ignoreTimezone, options.ignoreTimezone);
+ event._id = event._id || (event.id === undefined ? '_fc' + eventGUID++ : event.id + '');
+ if (event.date) {
+ if (!event.start) {
+ event.start = event.date;
+ }
+ delete event.date;
+ }
+ event._start = cloneDate(event.start = parseDate(event.start, ignoreTimezone));
+ event.end = parseDate(event.end, ignoreTimezone);
+ if (event.end && event.end <= event.start) {
+ event.end = null;
+ }
+ event._end = event.end ? cloneDate(event.end) : null;
+ if (event.allDay === undefined) {
+ event.allDay = firstDefined(source.allDayDefault, options.allDayDefault);
+ }
+ if (event.className) {
+ if (typeof event.className == 'string') {
+ event.className = event.className.split(/\s+/);
+ }
+ }else{
+ event.className = [];
+ }
+ // TODO: if there is no start date, return false to indicate an invalid event
+ }
+
+
+
+ /* Utils
+ ------------------------------------------------------------------------------*/
+
+
+ function normalizeSource(source) {
+ if (source.className) {
+ // TODO: repeat code, same code for event classNames
+ if (typeof source.className == 'string') {
+ source.className = source.className.split(/\s+/);
+ }
+ }else{
+ source.className = [];
+ }
+ var normalizers = fc.sourceNormalizers;
+ for (var i=0; i<normalizers.length; i++) {
+ normalizers[i](source);
+ }
+ }
+
+
+ function isSourcesEqual(source1, source2) {
+ return source1 && source2 && getSourcePrimitive(source1) == getSourcePrimitive(source2);
+ }
+
+
+ function getSourcePrimitive(source) {
+ return ((typeof source == 'object') ? (source.events || source.url) : '') || source;
+ }
+
+
+}
+
+
+fc.addDays = addDays;
+fc.cloneDate = cloneDate;
+fc.parseDate = parseDate;
+fc.parseISO8601 = parseISO8601;
+fc.parseTime = parseTime;
+fc.formatDate = formatDate;
+fc.formatDates = formatDates;
+
+
+
+/* Date Math
+-----------------------------------------------------------------------------*/
+
+var dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],
+ DAY_MS = 86400000,
+ HOUR_MS = 3600000,
+ MINUTE_MS = 60000;
+
+
+function addYears(d, n, keepTime) {
+ d.setFullYear(d.getFullYear() + n);
+ if (!keepTime) {
+ clearTime(d);
+ }
+ return d;
+}
+
+
+function addMonths(d, n, keepTime) { // prevents day overflow/underflow
+ if (+d) { // prevent infinite looping on invalid dates
+ var m = d.getMonth() + n,
+ check = cloneDate(d);
+ check.setDate(1);
+ check.setMonth(m);
+ d.setMonth(m);
+ if (!keepTime) {
+ clearTime(d);
+ }
+ while (d.getMonth() != check.getMonth()) {
+ d.setDate(d.getDate() + (d < check ? 1 : -1));
+ }
+ }
+ return d;
+}
+
+
+function addDays(d, n, keepTime) { // deals with daylight savings
+ if (+d) {
+ var dd = d.getDate() + n,
+ check = cloneDate(d);
+ check.setHours(9); // set to middle of day
+ check.setDate(dd);
+ d.setDate(dd);
+ if (!keepTime) {
+ clearTime(d);
+ }
+ fixDate(d, check);
+ }
+ return d;
+}
+
+
+function fixDate(d, check) { // force d to be on check's YMD, for daylight savings purposes
+ if (+d) { // prevent infinite looping on invalid dates
+ while (d.getDate() != check.getDate()) {
+ d.setTime(+d + (d < check ? 1 : -1) * HOUR_MS);
+ }
+ }
+}
+
+
+function addMinutes(d, n) {
+ d.setMinutes(d.getMinutes() + n);
+ return d;
+}
+
+
+function clearTime(d) {
+ d.setHours(0);
+ d.setMinutes(0);
+ d.setSeconds(0);
+ d.setMilliseconds(0);
+ return d;
+}
+
+
+function cloneDate(d, dontKeepTime) {
+ if (dontKeepTime) {
+ return clearTime(new Date(+d));
+ }
+ return new Date(+d);
+}
+
+
+function zeroDate() { // returns a Date with time 00:00:00 and dateOfMonth=1
+ var i=0, d;
+ do {
+ d = new Date(1970, i++, 1);
+ } while (d.getHours()); // != 0
+ return d;
+}
+
+
+function skipWeekend(date, inc, excl) {
+ inc = inc || 1;
+ while (!date.getDay() || (excl && date.getDay()==1 || !excl && date.getDay()==6)) {
+ addDays(date, inc);
+ }
+ return date;
+}
+
+
+function dayDiff(d1, d2) { // d1 - d2
+ return Math.round((cloneDate(d1, true) - cloneDate(d2, true)) / DAY_MS);
+}
+
+
+function setYMD(date, y, m, d) {
+ if (y !== undefined && y != date.getFullYear()) {
+ date.setDate(1);
+ date.setMonth(0);
+ date.setFullYear(y);
+ }
+ if (m !== undefined && m != date.getMonth()) {
+ date.setDate(1);
+ date.setMonth(m);
+ }
+ if (d !== undefined) {
+ date.setDate(d);
+ }
+}
+
+
+
+/* Date Parsing
+-----------------------------------------------------------------------------*/
+
+
+function parseDate(s, ignoreTimezone) { // ignoreTimezone defaults to true
+ if (typeof s == 'object') { // already a Date object
+ return s;
+ }
+ if (typeof s == 'number') { // a UNIX timestamp
+ return new Date(s * 1000);
+ }
+ if (typeof s == 'string') {
+ if (s.match(/^\d+(\.\d+)?$/)) { // a UNIX timestamp
+ return new Date(parseFloat(s) * 1000);
+ }
+ if (ignoreTimezone === undefined) {
+ ignoreTimezone = true;
+ }
+ return parseISO8601(s, ignoreTimezone) || (s ? new Date(s) : null);
+ }
+ // TODO: never return invalid dates (like from new Date(<string>)), return null instead
+ return null;
+}
+
+
+function parseISO8601(s, ignoreTimezone) { // ignoreTimezone defaults to false
+ // derived from http://delete.me.uk/2005/03/iso8601.html
+ // TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html
+ var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/);
+ if (!m) {
+ return null;
+ }
+ var date = new Date(m[1], 0, 1);
+ if (ignoreTimezone || !m[13]) {
+ var check = new Date(m[1], 0, 1, 9, 0);
+ if (m[3]) {
+ date.setMonth(m[3] - 1);
+ check.setMonth(m[3] - 1);
+ }
+ if (m[5]) {
+ date.setDate(m[5]);
+ check.setDate(m[5]);
+ }
+ fixDate(date, check);
+ if (m[7]) {
+ date.setHours(m[7]);
+ }
+ if (m[8]) {
+ date.setMinutes(m[8]);
+ }
+ if (m[10]) {
+ date.setSeconds(m[10]);
+ }
+ if (m[12]) {
+ date.setMilliseconds(Number("0." + m[12]) * 1000);
+ }
+ fixDate(date, check);
+ }else{
+ date.setUTCFullYear(
+ m[1],
+ m[3] ? m[3] - 1 : 0,
+ m[5] || 1
+ );
+ date.setUTCHours(
+ m[7] || 0,
+ m[8] || 0,
+ m[10] || 0,
+ m[12] ? Number("0." + m[12]) * 1000 : 0
+ );
+ if (m[14]) {
+ var offset = Number(m[16]) * 60 + (m[18] ? Number(m[18]) : 0);
+ offset *= m[15] == '-' ? 1 : -1;
+ date = new Date(+date + (offset * 60 * 1000));
+ }
+ }
+ return date;
+}
+
+
+function parseTime(s) { // returns minutes since start of day
+ if (typeof s == 'number') { // an hour
+ return s * 60;
+ }
+ if (typeof s == 'object') { // a Date object
+ return s.getHours() * 60 + s.getMinutes();
+ }
+ var m = s.match(/(\d+)(?::(\d+))?\s*(\w+)?/);
+ if (m) {
+ var h = parseInt(m[1], 10);
+ if (m[3]) {
+ h %= 12;
+ if (m[3].toLowerCase().charAt(0) == 'p') {
+ h += 12;
+ }
+ }
+ return h * 60 + (m[2] ? parseInt(m[2], 10) : 0);
+ }
+}
+
+
+
+/* Date Formatting
+-----------------------------------------------------------------------------*/
+// TODO: use same function formatDate(date, [date2], format, [options])
+
+
+function formatDate(date, format, options) {
+ return formatDates(date, null, format, options);
+}
+
+
+function formatDates(date1, date2, format, options) {
+ options = options || defaults;
+ var date = date1,
+ otherDate = date2,
+ i, len = format.length, c,
+ i2, formatter,
+ res = '';
+ for (i=0; i<len; i++) {
+ c = format.charAt(i);
+ if (c == "'") {
+ for (i2=i+1; i2<len; i2++) {
+ if (format.charAt(i2) == "'") {
+ if (date) {
+ if (i2 == i+1) {
+ res += "'";
+ }else{
+ res += format.substring(i+1, i2);
+ }
+ i = i2;
+ }
+ break;
+ }
+ }
+ }
+ else if (c == '(') {
+ for (i2=i+1; i2<len; i2++) {
+ if (format.charAt(i2) == ')') {
+ var subres = formatDate(date, format.substring(i+1, i2), options);
+ if (parseInt(subres.replace(/\D/, ''), 10)) {
+ res += subres;
+ }
+ i = i2;
+ break;
+ }
+ }
+ }
+ else if (c == '[') {
+ for (i2=i+1; i2<len; i2++) {
+ if (format.charAt(i2) == ']') {
+ var subformat = format.substring(i+1, i2);
+ var subres = formatDate(date, subformat, options);
+ if (subres != formatDate(otherDate, subformat, options)) {
+ res += subres;
+ }
+ i = i2;
+ break;
+ }
+ }
+ }
+ else if (c == '{') {
+ date = date2;
+ otherDate = date1;
+ }
+ else if (c == '}') {
+ date = date1;
+ otherDate = date2;
+ }
+ else {
+ for (i2=len; i2>i; i2--) {
+ if (formatter = dateFormatters[format.substring(i, i2)]) {
+ if (date) {
+ res += formatter(date, options);
+ }
+ i = i2 - 1;
+ break;
+ }
+ }
+ if (i2 == i) {
+ if (date) {
+ res += c;
+ }
+ }
+ }
+ }
+ return res;
+}
+ var dateFormatters = {
+ s : function(d) { return d.getSeconds() },
+ ss : function(d) { return zeroPad(d.getSeconds()) },
+ m : function(d) { return d.getMinutes() },
+ mm : function(d) { return zeroPad(d.getMinutes()) },
+ h : function(d) { return d.getHours() % 12 || 12 },
+ hh : function(d) { return zeroPad(d.getHours() % 12 || 12) },
+ H : function(d) { return d.getHours() },
+ HH : function(d) { return zeroPad(d.getHours()) },
+ d : function(d) { return d.getDate() },
+ dd : function(d) { return zeroPad(d.getDate()) },
+ ddd : function(d,o) { return o.dayNamesShort[d.getDay()] },
+ dddd: function(d,o) { return o.dayNames[d.getDay()] },
+ M : function(d) { return d.getMonth() + 1 },
+ MM : function(d) { return zeroPad(d.getMonth() + 1) },
+ MMM : function(d,o) { return o.monthNamesShort[d.getMonth()] },
+ MMMM: function(d,o) { return o.monthNames[d.getMonth()] },
+ yy : function(d) { return (d.getFullYear()+'').substring(2) },
+ yyyy: function(d) { return d.getFullYear() },
+ t : function(d) { return d.getHours() < 12 ? 'a' : 'p' },
+ tt : function(d) { return d.getHours() < 12 ? 'am' : 'pm' },
+ T : function(d) { return d.getHours() < 12 ? 'A' : 'P' },
+ TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' },
+ u : function(d) { return formatDate(d, "yyyy-MM-dd'T'HH:mm:ss'Z'") },
+ S : function(d) {
+ var date = d.getDate();
+ if (date > 10 && date < 20) {
+ return 'th';
+ }
+ return ['st', 'nd', 'rd'][date%10-1] || 'th';
+ }
+};
+
+
+
+fc.applyAll = applyAll;
+
+
+/* Event Date Math
+-----------------------------------------------------------------------------*/
+
+
+function exclEndDay(event) {
+ if (event.end) {
+ return _exclEndDay(event.end, event.allDay);
+ }else{
+ return addDays(cloneDate(event.start), 1);
+ }
+}
+
+
+function _exclEndDay(end, allDay) {
+ end = cloneDate(end);
+ return allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : clearTime(end);
+}
+
+
+function segCmp(a, b) {
+ return (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);
+}
+
+
+function segsCollide(seg1, seg2) {
+ return seg1.end > seg2.start && seg1.start < seg2.end;
+}
+
+
+
+/* Event Sorting
+-----------------------------------------------------------------------------*/
+
+
+// event rendering utilities
+function sliceSegs(events, visEventEnds, start, end) {
+ var segs = [],
+ i, len=events.length, event,
+ eventStart, eventEnd,
+ segStart, segEnd,
+ isStart, isEnd;
+ for (i=0; i<len; i++) {
+ event = events[i];
+ eventStart = event.start;
+ eventEnd = visEventEnds[i];
+ if (eventEnd > start && eventStart < end) {
+ if (eventStart < start) {
+ segStart = cloneDate(start);
+ isStart = false;
+ }else{
+ segStart = eventStart;
+ isStart = true;
+ }
+ if (eventEnd > end) {
+ segEnd = cloneDate(end);
+ isEnd = false;
+ }else{
+ segEnd = eventEnd;
+ isEnd = true;
+ }
+ segs.push({
+ event: event,
+ start: segStart,
+ end: segEnd,
+ isStart: isStart,
+ isEnd: isEnd,
+ msLength: segEnd - segStart
+ });
+ }
+ }
+ return segs.sort(segCmp);
+}
+
+
+// event rendering calculation utilities
+function stackSegs(segs) {
+ var levels = [],
+ i, len = segs.length, seg,
+ j, collide, k;
+ for (i=0; i<len; i++) {
+ seg = segs[i];
+ j = 0; // the level index where seg should belong
+ while (true) {
+ collide = false;
+ if (levels[j]) {
+ for (k=0; k<levels[j].length; k++) {
+ if (segsCollide(levels[j][k], seg)) {
+ collide = true;
+ break;
+ }
+ }
+ }
+ if (collide) {
+ j++;
+ }else{
+ break;
+ }
+ }
+ if (levels[j]) {
+ levels[j].push(seg);
+ }else{
+ levels[j] = [seg];
+ }
+ }
+ return levels;
+}
+
+
+
+/* Event Element Binding
+-----------------------------------------------------------------------------*/
+
+
+function lazySegBind(container, segs, bindHandlers) {
+ container.unbind('mouseover').mouseover(function(ev) {
+ var parent=ev.target, e,
+ i, seg;
+ while (parent != this) {
+ e = parent;
+ parent = parent.parentNode;
+ }
+ if ((i = e._fci) !== undefined) {
+ e._fci = undefined;
+ seg = segs[i];
+ bindHandlers(seg.event, seg.element, seg);
+ $(ev.target).trigger(ev);
+ }
+ ev.stopPropagation();
+ });
+}
+
+
+
+/* Element Dimensions
+-----------------------------------------------------------------------------*/
+
+
+function setOuterWidth(element, width, includeMargins) {
+ for (var i=0, e; i<element.length; i++) {
+ e = $(element[i]);
+ e.width(Math.max(0, width - hsides(e, includeMargins)));
+ }
+}
+
+
+function setOuterHeight(element, height, includeMargins) {
+ for (var i=0, e; i<element.length; i++) {
+ e = $(element[i]);
+ e.height(Math.max(0, height - vsides(e, includeMargins)));
+ }
+}
+
+
+function hsides(element, includeMargins) {
+ return hpadding(element) + hborders(element) + (includeMargins ? hmargins(element) : 0);
+}
+
+
+function hpadding(element) {
+ return (parseFloat($.css(element[0], 'paddingLeft', true)) || 0) +
+ (parseFloat($.css(element[0], 'paddingRight', true)) || 0);
+}
+
+
+function hmargins(element) {
+ return (parseFloat($.css(element[0], 'marginLeft', true)) || 0) +
+ (parseFloat($.css(element[0], 'marginRight', true)) || 0);
+}
+
+
+function hborders(element) {
+ return (parseFloat($.css(element[0], 'borderLeftWidth', true)) || 0) +
+ (parseFloat($.css(element[0], 'borderRightWidth', true)) || 0);
+}
+
+
+function vsides(element, includeMargins) {
+ return vpadding(element) + vborders(element) + (includeMargins ? vmargins(element) : 0);
+}
+
+
+function vpadding(element) {
+ return (parseFloat($.css(element[0], 'paddingTop', true)) || 0) +
+ (parseFloat($.css(element[0], 'paddingBottom', true)) || 0);
+}
+
+
+function vmargins(element) {
+ return (parseFloat($.css(element[0], 'marginTop', true)) || 0) +
+ (parseFloat($.css(element[0], 'marginBottom', true)) || 0);
+}
+
+
+function vborders(element) {
+ return (parseFloat($.css(element[0], 'borderTopWidth', true)) || 0) +
+ (parseFloat($.css(element[0], 'borderBottomWidth', true)) || 0);
+}
+
+
+function setMinHeight(element, height) {
+ height = (typeof height == 'number' ? height + 'px' : height);
+ element.each(function(i, _element) {
+ _element.style.cssText += ';min-height:' + height + ';_height:' + height;
+ // why can't we just use .css() ? i forget
+ });
+}
+
+
+
+/* Misc Utils
+-----------------------------------------------------------------------------*/
+
+
+//TODO: arraySlice
+//TODO: isFunction, grep ?
+
+
+function noop() { }
+
+
+function cmp(a, b) {
+ return a - b;
+}
+
+
+function arrayMax(a) {
+ return Math.max.apply(Math, a);
+}
+
+
+function zeroPad(n) {
+ return (n < 10 ? '0' : '') + n;
+}
+
+
+function smartProperty(obj, name) { // get a camel-cased/namespaced property of an object
+ if (obj[name] !== undefined) {
+ return obj[name];
+ }
+ var parts = name.split(/(?=[A-Z])/),
+ i=parts.length-1, res;
+ for (; i>=0; i--) {
+ res = obj[parts[i].toLowerCase()];
+ if (res !== undefined) {
+ return res;
+ }
+ }
+ return obj[''];
+}
+
+
+function htmlEscape(s) {
+ return s.replace(/&/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/'/g, '&#039;')
+ .replace(/"/g, '&quot;')
+ .replace(/\n/g, '<br />');
+}
+
+
+function cssKey(_element) {
+ return _element.id + '/' + _element.className + '/' + _element.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig, '');
+}
+
+
+function disableTextSelection(element) {
+ element
+ .attr('unselectable', 'on')
+ .css('MozUserSelect', 'none')
+ .bind('selectstart.ui', function() { return false; });
+}
+
+
+/*
+function enableTextSelection(element) {
+ element
+ .attr('unselectable', 'off')
+ .css('MozUserSelect', '')
+ .unbind('selectstart.ui');
+}
+*/
+
+
+function markFirstLast(e) {
+ e.children()
+ .removeClass('fc-first fc-last')
+ .filter(':first-child')
+ .addClass('fc-first')
+ .end()
+ .filter(':last-child')
+ .addClass('fc-last');
+}
+
+
+function setDayID(cell, date) {
+ cell.each(function(i, _cell) {
+ _cell.className = _cell.className.replace(/^fc-\w*/, 'fc-' + dayIDs[date.getDay()]);
+ // TODO: make a way that doesn't rely on order of classes
+ });
+}
+
+
+function getSkinCss(event, opt) {
+ var source = event.source || {};
+ var eventColor = event.color;
+ var sourceColor = source.color;
+ var optionColor = opt('eventColor');
+ var backgroundColor =
+ event.backgroundColor ||
+ eventColor ||
+ source.backgroundColor ||
+ sourceColor ||
+ opt('eventBackgroundColor') ||
+ optionColor;
+ var borderColor =
+ event.borderColor ||
+ eventColor ||
+ source.borderColor ||
+ sourceColor ||
+ opt('eventBorderColor') ||
+ optionColor;
+ var textColor =
+ event.textColor ||
+ source.textColor ||
+ opt('eventTextColor');
+ var statements = [];
+ if (backgroundColor) {
+ statements.push('background-color:' + backgroundColor);
+ }
+ if (borderColor) {
+ statements.push('border-color:' + borderColor);
+ }
+ if (textColor) {
+ statements.push('color:' + textColor);
+ }
+ return statements.join(';');
+}
+
+
+function applyAll(functions, thisObj, args) {
+ if ($.isFunction(functions)) {
+ functions = [ functions ];
+ }
+ if (functions) {
+ var i;
+ var ret;
+ for (i=0; i<functions.length; i++) {
+ ret = functions[i].apply(thisObj, args) || ret;
+ }
+ return ret;
+ }
+}
+
+
+function firstDefined() {
+ for (var i=0; i<arguments.length; i++) {
+ if (arguments[i] !== undefined) {
+ return arguments[i];
+ }
+ }
+}
+
+
+fcViews.month = MonthView;
+
+function MonthView(element, calendar) {
+ var t = this;
+
+
+ // exports
+ t.render = render;
+
+
+ // imports
+ BasicView.call(t, element, calendar, 'month');
+ var opt = t.opt;
+ var renderBasic = t.renderBasic;
+ var formatDate = calendar.formatDate;
+
+
+
+ function render(date, delta) {
+ if (delta) {
+ addMonths(date, delta);
+ date.setDate(1);
+ }
+ var start = cloneDate(date, true);
+ start.setDate(1);
+ var end = addMonths(cloneDate(start), 1);
+ var visStart = cloneDate(start);
+ var visEnd = cloneDate(end);
+ var firstDay = opt('firstDay');
+ var nwe = opt('weekends') ? 0 : 1;
+ if (nwe) {
+ skipWeekend(visStart);
+ skipWeekend(visEnd, -1, true);
+ }
+ addDays(visStart, -((visStart.getDay() - Math.max(firstDay, nwe) + 7) % 7));
+ addDays(visEnd, (7 - visEnd.getDay() + Math.max(firstDay, nwe)) % 7);
+ var rowCnt = Math.round((visEnd - visStart) / (DAY_MS * 7));
+ if (opt('weekMode') == 'fixed') {
+ addDays(visEnd, (6 - rowCnt) * 7);
+ rowCnt = 6;
+ }
+ t.title = formatDate(start, opt('titleFormat'));
+ t.start = start;
+ t.end = end;
+ t.visStart = visStart;
+ t.visEnd = visEnd;
+ renderBasic(6, rowCnt, nwe ? 5 : 7, true);
+ }
+
+
+}
+
+fcViews.basicWeek = BasicWeekView;
+
+function BasicWeekView(element, calendar) {
+ var t = this;
+
+
+ // exports
+ t.render = render;
+
+
+ // imports
+ BasicView.call(t, element, calendar, 'basicWeek');
+ var opt = t.opt;
+ var renderBasic = t.renderBasic;
+ var formatDates = calendar.formatDates;
+
+
+
+ function render(date, delta) {
+ if (delta) {
+ addDays(date, delta * 7);
+ }
+ var start = addDays(cloneDate(date), -((date.getDay() - opt('firstDay') + 7) % 7));
+ var end = addDays(cloneDate(start), 7);
+ var visStart = cloneDate(start);
+ var visEnd = cloneDate(end);
+ var weekends = opt('weekends');
+ if (!weekends) {
+ skipWeekend(visStart);
+ skipWeekend(visEnd, -1, true);
+ }
+ t.title = formatDates(
+ visStart,
+ addDays(cloneDate(visEnd), -1),
+ opt('titleFormat')
+ );
+ t.start = start;
+ t.end = end;
+ t.visStart = visStart;
+ t.visEnd = visEnd;
+ renderBasic(1, 1, weekends ? 7 : 5, false);
+ }
+
+
+}
+
+fcViews.basicDay = BasicDayView;
+
+//TODO: when calendar's date starts out on a weekend, shouldn't happen
+
+
+function BasicDayView(element, calendar) {
+ var t = this;
+
+
+ // exports
+ t.render = render;
+
+
+ // imports
+ BasicView.call(t, element, calendar, 'basicDay');
+ var opt = t.opt;
+ var renderBasic = t.renderBasic;
+ var formatDate = calendar.formatDate;
+
+
+
+ function render(date, delta) {
+ if (delta) {
+ addDays(date, delta);
+ if (!opt('weekends')) {
+ skipWeekend(date, delta < 0 ? -1 : 1);
+ }
+ }
+ t.title = formatDate(date, opt('titleFormat'));
+ t.start = t.visStart = cloneDate(date, true);
+ t.end = t.visEnd = addDays(cloneDate(t.start), 1);
+ renderBasic(1, 1, 1, false);
+ }
+
+
+}
+
+setDefaults({
+ weekMode: 'fixed'
+});
+
+
+function BasicView(element, calendar, viewName) {
+ var t = this;
+
+
+ // exports
+ t.renderBasic = renderBasic;
+ t.setHeight = setHeight;
+ t.setWidth = setWidth;
+ t.renderDayOverlay = renderDayOverlay;
+ t.defaultSelectionEnd = defaultSelectionEnd;
+ t.renderSelection = renderSelection;
+ t.clearSelection = clearSelection;
+ t.reportDayClick = reportDayClick; // for selection (kinda hacky)
+ t.dragStart = dragStart;
+ t.dragStop = dragStop;
+ t.defaultEventEnd = defaultEventEnd;
+ t.getHoverListener = function() { return hoverListener };
+ t.colContentLeft = colContentLeft;
+ t.colContentRight = colContentRight;
+ t.dayOfWeekCol = dayOfWeekCol;
+ t.dateCell = dateCell;
+ t.cellDate = cellDate;
+ t.cellIsAllDay = function() { return true };
+ t.allDayRow = allDayRow;
+ t.allDayBounds = allDayBounds;
+ t.getRowCnt = function() { return rowCnt };
+ t.getColCnt = function() { return colCnt };
+ t.getColWidth = function() { return colWidth };
+ t.getDaySegmentContainer = function() { return daySegmentContainer };
+
+
+ // imports
+ View.call(t, element, calendar, viewName);
+ OverlayManager.call(t);
+ SelectionManager.call(t);
+ BasicEventRenderer.call(t);
+ var opt = t.opt;
+ var trigger = t.trigger;
+ var clearEvents = t.clearEvents;
+ var renderOverlay = t.renderOverlay;
+ var clearOverlays = t.clearOverlays;
+ var daySelectionMousedown = t.daySelectionMousedown;
+ var formatDate = calendar.formatDate;
+
+
+ // locals
+
+ var head;
+ var headCells;
+ var body;
+ var bodyRows;
+ var bodyCells;
+ var bodyFirstCells;
+ var bodyCellTopInners;
+ var daySegmentContainer;
+
+ var viewWidth;
+ var viewHeight;
+ var colWidth;
+
+ var rowCnt, colCnt;
+ var coordinateGrid;
+ var hoverListener;
+ var colContentPositions;
+
+ var rtl, dis, dit;
+ var firstDay;
+ var nwe;
+ var tm;
+ var colFormat;
+
+
+
+ /* Rendering
+ ------------------------------------------------------------*/
+
+
+ disableTextSelection(element.addClass('fc-grid'));
+
+
+ function renderBasic(maxr, r, c, showNumbers) {
+ rowCnt = r;
+ colCnt = c;
+ updateOptions();
+ var firstTime = !body;
+ if (firstTime) {
+ buildSkeleton(maxr, showNumbers);
+ }else{
+ clearEvents();
+ }
+ updateCells(firstTime);
+ }
+
+
+
+ function updateOptions() {
+ rtl = opt('isRTL');
+ if (rtl) {
+ dis = -1;
+ dit = colCnt - 1;
+ }else{
+ dis = 1;
+ dit = 0;
+ }
+ firstDay = opt('firstDay');
+ nwe = opt('weekends') ? 0 : 1;
+ tm = opt('theme') ? 'ui' : 'fc';
+ colFormat = opt('columnFormat');
+ }
+
+
+
+ function buildSkeleton(maxRowCnt, showNumbers) {
+ var s;
+ var headerClass = tm + "-widget-header";
+ var contentClass = tm + "-widget-content";
+ var i, j;
+ var table;
+
+ s =
+ "<table class='fc-border-separate' style='width:100%' cellspacing='0'>" +
+ "<thead>" +
+ "<tr>";
+ for (i=0; i<colCnt; i++) {
+ s +=
+ "<th class='fc- " + headerClass + "'/>"; // need fc- for setDayID
+ }
+ s +=
+ "</tr>" +
+ "</thead>" +
+ "<tbody>";
+ for (i=0; i<maxRowCnt; i++) {
+ s +=
+ "<tr class='fc-week" + i + "'>";
+ for (j=0; j<colCnt; j++) {
+ s +=
+ "<td class='fc- " + contentClass + " fc-day" + (i*colCnt+j) + "'>" + // need fc- for setDayID
+ "<div>" +
+ (showNumbers ?
+ "<div class='fc-day-number'/>" :
+ ''
+ ) +
+ "<div class='fc-day-content'>" +
+ "<div style='position:relative'>&nbsp;</div>" +
+ "</div>" +
+ "</div>" +
+ "</td>";
+ }
+ s +=
+ "</tr>";
+ }
+ s +=
+ "</tbody>" +
+ "</table>";
+ table = $(s).appendTo(element);
+
+ head = table.find('thead');
+ headCells = head.find('th');
+ body = table.find('tbody');
+ bodyRows = body.find('tr');
+ bodyCells = body.find('td');
+ bodyFirstCells = bodyCells.filter(':first-child');
+ bodyCellTopInners = bodyRows.eq(0).find('div.fc-day-content div');
+
+ markFirstLast(head.add(head.find('tr'))); // marks first+last tr/th's
+ markFirstLast(bodyRows); // marks first+last td's
+ bodyRows.eq(0).addClass('fc-first'); // fc-last is done in updateCells
+
+ dayBind(bodyCells);
+
+ daySegmentContainer =
+ $("<div style='position:absolute;z-index:8;top:0;left:0'/>")
+ .appendTo(element);
+ }
+
+
+
+ function updateCells(firstTime) {
+ var dowDirty = firstTime || rowCnt == 1; // could the cells' day-of-weeks need updating?
+ var month = t.start.getMonth();
+ var today = clearTime(new Date());
+ var cell;
+ var date;
+ var row;
+
+ if (dowDirty) {
+ headCells.each(function(i, _cell) {
+ cell = $(_cell);
+ date = indexDate(i);
+ cell.html(formatDate(date, colFormat));
+ setDayID(cell, date);
+ });
+ }
+
+ bodyCells.each(function(i, _cell) {
+ cell = $(_cell);
+ date = indexDate(i);
+ if (date.getMonth() == month) {
+ cell.removeClass('fc-other-month');
+ }else{
+ cell.addClass('fc-other-month');
+ }
+ if (+date == +today) {
+ cell.addClass(tm + '-state-highlight fc-today');
+ }else{
+ cell.removeClass(tm + '-state-highlight fc-today');
+ }
+ cell.find('div.fc-day-number').text(date.getDate());
+ if (dowDirty) {
+ setDayID(cell, date);
+ }
+ });
+
+ bodyRows.each(function(i, _row) {
+ row = $(_row);
+ if (i < rowCnt) {
+ row.show();
+ if (i == rowCnt-1) {
+ row.addClass('fc-last');
+ }else{
+ row.removeClass('fc-last');
+ }
+ }else{
+ row.hide();
+ }
+ });
+ }
+
+
+
+ function setHeight(height) {
+ viewHeight = height;
+
+ var bodyHeight = viewHeight - head.height();
+ var rowHeight;
+ var rowHeightLast;
+ var cell;
+
+ if (opt('weekMode') == 'variable') {
+ rowHeight = rowHeightLast = Math.floor(bodyHeight / (rowCnt==1 ? 2 : 6));
+ }else{
+ rowHeight = Math.floor(bodyHeight / rowCnt);
+ rowHeightLast = bodyHeight - rowHeight * (rowCnt-1);
+ }
+
+ bodyFirstCells.each(function(i, _cell) {
+ if (i < rowCnt) {
+ cell = $(_cell);
+ setMinHeight(
+ cell.find('> div'),
+ (i==rowCnt-1 ? rowHeightLast : rowHeight) - vsides(cell)
+ );
+ }
+ });
+
+ }
+
+
+ function setWidth(width) {
+ viewWidth = width;
+ colContentPositions.clear();
+ colWidth = Math.floor(viewWidth / colCnt);
+ setOuterWidth(headCells.slice(0, -1), colWidth);
+ }
+
+
+
+ /* Day clicking and binding
+ -----------------------------------------------------------*/
+
+
+ function dayBind(days) {
+ days.click(dayClick)
+ .mousedown(daySelectionMousedown);
+ }
+
+
+ function dayClick(ev) {
+ if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick
+ var index = parseInt(this.className.match(/fc\-day(\d+)/)[1]); // TODO: maybe use .data
+ var date = indexDate(index);
+ trigger('dayClick', this, date, true, ev);
+ }
+ }
+
+
+
+ /* Semi-transparent Overlay Helpers
+ ------------------------------------------------------*/
+
+
+ function renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive
+ if (refreshCoordinateGrid) {
+ coordinateGrid.build();
+ }
+ var rowStart = cloneDate(t.visStart);
+ var rowEnd = addDays(cloneDate(rowStart), colCnt);
+ for (var i=0; i<rowCnt; i++) {
+ var stretchStart = new Date(Math.max(rowStart, overlayStart));
+ var stretchEnd = new Date(Math.min(rowEnd, overlayEnd));
+ if (stretchStart < stretchEnd) {
+ var colStart, colEnd;
+ if (rtl) {
+ colStart = dayDiff(stretchEnd, rowStart)*dis+dit+1;
+ colEnd = dayDiff(stretchStart, rowStart)*dis+dit+1;
+ }else{
+ colStart = dayDiff(stretchStart, rowStart);
+ colEnd = dayDiff(stretchEnd, rowStart);
+ }
+ dayBind(
+ renderCellOverlay(i, colStart, i, colEnd-1)
+ );
+ }
+ addDays(rowStart, 7);
+ addDays(rowEnd, 7);
+ }
+ }
+
+
+ function renderCellOverlay(row0, col0, row1, col1) { // row1,col1 is inclusive
+ var rect = coordinateGrid.rect(row0, col0, row1, col1, element);
+ return renderOverlay(rect, element);
+ }
+
+
+
+ /* Selection
+ -----------------------------------------------------------------------*/
+
+
+ function defaultSelectionEnd(startDate, allDay) {
+ return cloneDate(startDate);
+ }
+
+
+ function renderSelection(startDate, endDate, allDay) {
+ renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true); // rebuild every time???
+ }
+
+
+ function clearSelection() {
+ clearOverlays();
+ }
+
+
+ function reportDayClick(date, allDay, ev) {
+ var cell = dateCell(date);
+ var _element = bodyCells[cell.row*colCnt + cell.col];
+ trigger('dayClick', _element, date, allDay, ev);
+ }
+
+
+
+ /* External Dragging
+ -----------------------------------------------------------------------*/
+
+
+ function dragStart(_dragElement, ev, ui) {
+ hoverListener.start(function(cell) {
+ clearOverlays();
+ if (cell) {
+ renderCellOverlay(cell.row, cell.col, cell.row, cell.col);
+ }
+ }, ev);
+ }
+
+
+ function dragStop(_dragElement, ev, ui) {
+ var cell = hoverListener.stop();
+ clearOverlays();
+ if (cell) {
+ var d = cellDate(cell);
+ trigger('drop', _dragElement, d, true, ev, ui);
+ }
+ }
+
+
+
+ /* Utilities
+ --------------------------------------------------------*/
+
+
+ function defaultEventEnd(event) {
+ return cloneDate(event.start);
+ }
+
+
+ coordinateGrid = new CoordinateGrid(function(rows, cols) {
+ var e, n, p;
+ headCells.each(function(i, _e) {
+ e = $(_e);
+ n = e.offset().left;
+ if (i) {
+ p[1] = n;
+ }
+ p = [n];
+ cols[i] = p;
+ });
+ p[1] = n + e.outerWidth();
+ bodyRows.each(function(i, _e) {
+ if (i < rowCnt) {
+ e = $(_e);
+ n = e.offset().top;
+ if (i) {
+ p[1] = n;
+ }
+ p = [n];
+ rows[i] = p;
+ }
+ });
+ p[1] = n + e.outerHeight();
+ });
+
+
+ hoverListener = new HoverListener(coordinateGrid);
+
+
+ colContentPositions = new HorizontalPositionCache(function(col) {
+ return bodyCellTopInners.eq(col);
+ });
+
+
+ function colContentLeft(col) {
+ return colContentPositions.left(col);
+ }
+
+
+ function colContentRight(col) {
+ return colContentPositions.right(col);
+ }
+
+
+
+
+ function dateCell(date) {
+ return {
+ row: Math.floor(dayDiff(date, t.visStart) / 7),
+ col: dayOfWeekCol(date.getDay())
+ };
+ }
+
+
+ function cellDate(cell) {
+ return _cellDate(cell.row, cell.col);
+ }
+
+
+ function _cellDate(row, col) {
+ return addDays(cloneDate(t.visStart), row*7 + col*dis+dit);
+ // what about weekends in middle of week?
+ }
+
+
+ function indexDate(index) {
+ return _cellDate(Math.floor(index/colCnt), index%colCnt);
+ }
+
+
+ function dayOfWeekCol(dayOfWeek) {
+ return ((dayOfWeek - Math.max(firstDay, nwe) + colCnt) % colCnt) * dis + dit;
+ }
+
+
+
+
+ function allDayRow(i) {
+ return bodyRows.eq(i);
+ }
+
+
+ function allDayBounds(i) {
+ return {
+ left: 0,
+ right: viewWidth
+ };
+ }
+
+
+}
+
+function BasicEventRenderer() {
+ var t = this;
+
+
+ // exports
+ t.renderEvents = renderEvents;
+ t.compileDaySegs = compileSegs; // for DayEventRenderer
+ t.clearEvents = clearEvents;
+ t.bindDaySeg = bindDaySeg;
+
+
+ // imports
+ DayEventRenderer.call(t);
+ var opt = t.opt;
+ var trigger = t.trigger;
+ //var setOverflowHidden = t.setOverflowHidden;
+ var isEventDraggable = t.isEventDraggable;
+ var isEventResizable = t.isEventResizable;
+ var reportEvents = t.reportEvents;
+ var reportEventClear = t.reportEventClear;
+ var eventElementHandlers = t.eventElementHandlers;
+ var showEvents = t.showEvents;
+ var hideEvents = t.hideEvents;
+ var eventDrop = t.eventDrop;
+ var getDaySegmentContainer = t.getDaySegmentContainer;
+ var getHoverListener = t.getHoverListener;
+ var renderDayOverlay = t.renderDayOverlay;
+ var clearOverlays = t.clearOverlays;
+ var getRowCnt = t.getRowCnt;
+ var getColCnt = t.getColCnt;
+ var renderDaySegs = t.renderDaySegs;
+ var resizableDayEvent = t.resizableDayEvent;
+
+
+
+ /* Rendering
+ --------------------------------------------------------------------*/
+
+
+ function renderEvents(events, modifiedEventId) {
+ reportEvents(events);
+ renderDaySegs(compileSegs(events), modifiedEventId);
+ }
+
+
+ function clearEvents() {
+ reportEventClear();
+ getDaySegmentContainer().empty();
+ }
+
+
+ function compileSegs(events) {
+ var rowCnt = getRowCnt(),
+ colCnt = getColCnt(),
+ d1 = cloneDate(t.visStart),
+ d2 = addDays(cloneDate(d1), colCnt),
+ visEventsEnds = $.map(events, exclEndDay),
+ i, row,
+ j, level,
+ k, seg,
+ segs=[];
+ for (i=0; i<rowCnt; i++) {
+ row = stackSegs(sliceSegs(events, visEventsEnds, d1, d2));
+ for (j=0; j<row.length; j++) {
+ level = row[j];
+ for (k=0; k<level.length; k++) {
+ seg = level[k];
+ seg.row = i;
+ seg.level = j; // not needed anymore
+ segs.push(seg);
+ }
+ }
+ addDays(d1, 7);
+ addDays(d2, 7);
+ }
+ return segs;
+ }
+
+
+ function bindDaySeg(event, eventElement, seg) {
+ if (isEventDraggable(event)) {
+ draggableDayEvent(event, eventElement);
+ }
+ if (seg.isEnd && isEventResizable(event)) {
+ resizableDayEvent(event, eventElement, seg);
+ }
+ eventElementHandlers(event, eventElement);
+ // needs to be after, because resizableDayEvent might stopImmediatePropagation on click
+ }
+
+
+
+ /* Dragging
+ ----------------------------------------------------------------------------*/
+
+
+ function draggableDayEvent(event, eventElement) {
+ var hoverListener = getHoverListener();
+ var dayDelta;
+ eventElement.draggable({
+ zIndex: 9,
+ delay: 50,
+ opacity: opt('dragOpacity'),
+ revertDuration: opt('dragRevertDuration'),
+ start: function(ev, ui) {
+ trigger('eventDragStart', eventElement, event, ev, ui);
+ hideEvents(event, eventElement);
+ hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
+ eventElement.draggable('option', 'revert', !cell || !rowDelta && !colDelta);
+ clearOverlays();
+ if (cell) {
+ //setOverflowHidden(true);
+ dayDelta = rowDelta*7 + colDelta * (opt('isRTL') ? -1 : 1);
+ renderDayOverlay(
+ addDays(cloneDate(event.start), dayDelta),
+ addDays(exclEndDay(event), dayDelta)
+ );
+ }else{
+ //setOverflowHidden(false);
+ dayDelta = 0;
+ }
+ }, ev, 'drag');
+ },
+ stop: function(ev, ui) {
+ hoverListener.stop();
+ clearOverlays();
+ trigger('eventDragStop', eventElement, event, ev, ui);
+ if (dayDelta) {
+ eventDrop(this, event, dayDelta, 0, event.allDay, ev, ui);
+ }else{
+ eventElement.css('filter', ''); // clear IE opacity side-effects
+ showEvents(event, eventElement);
+ }
+ //setOverflowHidden(false);
+ }
+ });
+ }
+
+
+}
+
+fcViews.agendaWeek = AgendaWeekView;
+
+function AgendaWeekView(element, calendar) {
+ var t = this;
+
+
+ // exports
+ t.render = render;
+
+
+ // imports
+ AgendaView.call(t, element, calendar, 'agendaWeek');
+ var opt = t.opt;
+ var renderAgenda = t.renderAgenda;
+ var formatDates = calendar.formatDates;
+
+
+
+ function render(date, delta) {
+ if (delta) {
+ addDays(date, delta * 7);
+ }
+ var start = addDays(cloneDate(date), -((date.getDay() - opt('firstDay') + 7) % 7));
+ var end = addDays(cloneDate(start), 7);
+ var visStart = cloneDate(start);
+ var visEnd = cloneDate(end);
+ var weekends = opt('weekends');
+ if (!weekends) {
+ skipWeekend(visStart);
+ skipWeekend(visEnd, -1, true);
+ }
+ t.title = formatDates(
+ visStart,
+ addDays(cloneDate(visEnd), -1),
+ opt('titleFormat')
+ );
+ t.start = start;
+ t.end = end;
+ t.visStart = visStart;
+ t.visEnd = visEnd;
+ renderAgenda(weekends ? 7 : 5);
+ }
+
+
+}
+
+fcViews.agendaDay = AgendaDayView;
+
+function AgendaDayView(element, calendar) {
+ var t = this;
+
+
+ // exports
+ t.render = render;
+
+
+ // imports
+ AgendaView.call(t, element, calendar, 'agendaDay');
+ var opt = t.opt;
+ var renderAgenda = t.renderAgenda;
+ var formatDate = calendar.formatDate;
+
+
+
+ function render(date, delta) {
+ if (delta) {
+ addDays(date, delta);
+ if (!opt('weekends')) {
+ skipWeekend(date, delta < 0 ? -1 : 1);
+ }
+ }
+ var start = cloneDate(date, true);
+ var end = addDays(cloneDate(start), 1);
+ t.title = formatDate(date, opt('titleFormat'));
+ t.start = t.visStart = start;
+ t.end = t.visEnd = end;
+ renderAgenda(1);
+ }
+
+
+}
+
+setDefaults({
+ allDaySlot: true,
+ allDayText: 'all-day',
+ firstHour: 6,
+ slotMinutes: 30,
+ defaultEventMinutes: 120,
+ axisFormat: 'h(:mm)tt',
+ timeFormat: {
+ agenda: 'h:mm{ - h:mm}'
+ },
+ dragOpacity: {
+ agenda: .5
+ },
+ minTime: 0,
+ maxTime: 24
+});
+
+
+// TODO: make it work in quirks mode (event corners, all-day height)
+// TODO: test liquid width, especially in IE6
+
+
+function AgendaView(element, calendar, viewName) {
+ var t = this;
+
+
+ // exports
+ t.renderAgenda = renderAgenda;
+ t.setWidth = setWidth;
+ t.setHeight = setHeight;
+ t.beforeHide = beforeHide;
+ t.afterShow = afterShow;
+ t.defaultEventEnd = defaultEventEnd;
+ t.timePosition = timePosition;
+ t.dayOfWeekCol = dayOfWeekCol;
+ t.dateCell = dateCell;
+ t.cellDate = cellDate;
+ t.cellIsAllDay = cellIsAllDay;
+ t.allDayRow = getAllDayRow;
+ t.allDayBounds = allDayBounds;
+ t.getHoverListener = function() { return hoverListener };
+ t.colContentLeft = colContentLeft;
+ t.colContentRight = colContentRight;
+ t.getDaySegmentContainer = function() { return daySegmentContainer };
+ t.getSlotSegmentContainer = function() { return slotSegmentContainer };
+ t.getMinMinute = function() { return minMinute };
+ t.getMaxMinute = function() { return maxMinute };
+ t.getBodyContent = function() { return slotContent }; // !!??
+ t.getRowCnt = function() { return 1 };
+ t.getColCnt = function() { return colCnt };
+ t.getColWidth = function() { return colWidth };
+ t.getSlotHeight = function() { return slotHeight };
+ t.defaultSelectionEnd = defaultSelectionEnd;
+ t.renderDayOverlay = renderDayOverlay;
+ t.renderSelection = renderSelection;
+ t.clearSelection = clearSelection;
+ t.reportDayClick = reportDayClick; // selection mousedown hack
+ t.dragStart = dragStart;
+ t.dragStop = dragStop;
+
+
+ // imports
+ View.call(t, element, calendar, viewName);
+ OverlayManager.call(t);
+ SelectionManager.call(t);
+ AgendaEventRenderer.call(t);
+ var opt = t.opt;
+ var trigger = t.trigger;
+ var clearEvents = t.clearEvents;
+ var renderOverlay = t.renderOverlay;
+ var clearOverlays = t.clearOverlays;
+ var reportSelection = t.reportSelection;
+ var unselect = t.unselect;
+ var daySelectionMousedown = t.daySelectionMousedown;
+ var slotSegHtml = t.slotSegHtml;
+ var formatDate = calendar.formatDate;
+
+
+ // locals
+
+ var dayTable;
+ var dayHead;
+ var dayHeadCells;
+ var dayBody;
+ var dayBodyCells;
+ var dayBodyCellInners;
+ var dayBodyFirstCell;
+ var dayBodyFirstCellStretcher;
+ var slotLayer;
+ var daySegmentContainer;
+ var allDayTable;
+ var allDayRow;
+ var slotScroller;
+ var slotContent;
+ var slotSegmentContainer;
+ var slotTable;
+ var slotTableFirstInner;
+ var axisFirstCells;
+ var gutterCells;
+ var selectionHelper;
+
+ var viewWidth;
+ var viewHeight;
+ var axisWidth;
+ var colWidth;
+ var gutterWidth;
+ var slotHeight; // TODO: what if slotHeight changes? (see issue 650)
+ var savedScrollTop;
+
+ var colCnt;
+ var slotCnt;
+ var coordinateGrid;
+ var hoverListener;
+ var colContentPositions;
+ var slotTopCache = {};
+
+ var tm;
+ var firstDay;
+ var nwe; // no weekends (int)
+ var rtl, dis, dit; // day index sign / translate
+ var minMinute, maxMinute;
+ var colFormat;
+
+
+
+ /* Rendering
+ -----------------------------------------------------------------------------*/
+
+
+ disableTextSelection(element.addClass('fc-agenda'));
+
+
+ function renderAgenda(c) {
+ colCnt = c;
+ updateOptions();
+ if (!dayTable) {
+ buildSkeleton();
+ }else{
+ clearEvents();
+ }
+ updateCells();
+ }
+
+
+
+ function updateOptions() {
+ tm = opt('theme') ? 'ui' : 'fc';
+ nwe = opt('weekends') ? 0 : 1;
+ firstDay = opt('firstDay');
+ if (rtl = opt('isRTL')) {
+ dis = -1;
+ dit = colCnt - 1;
+ }else{
+ dis = 1;
+ dit = 0;
+ }
+ minMinute = parseTime(opt('minTime'));
+ maxMinute = parseTime(opt('maxTime'));
+ colFormat = opt('columnFormat');
+ }
+
+
+
+ function buildSkeleton() {
+ var headerClass = tm + "-widget-header";
+ var contentClass = tm + "-widget-content";
+ var s;
+ var i;
+ var d;
+ var maxd;
+ var minutes;
+ var slotNormal = opt('slotMinutes') % 15 == 0;
+
+ s =
+ "<table style='width:100%' class='fc-agenda-days fc-border-separate' cellspacing='0'>" +
+ "<thead>" +
+ "<tr>" +
+ "<th class='fc-agenda-axis " + headerClass + "'>&nbsp;</th>";
+ for (i=0; i<colCnt; i++) {
+ s +=
+ "<th class='fc- fc-col" + i + ' ' + headerClass + "'/>"; // fc- needed for setDayID
+ }
+ s +=
+ "<th class='fc-agenda-gutter " + headerClass + "'>&nbsp;</th>" +
+ "</tr>" +
+ "</thead>" +
+ "<tbody>" +
+ "<tr>" +
+ "<th class='fc-agenda-axis " + headerClass + "'>&nbsp;</th>";
+ for (i=0; i<colCnt; i++) {
+ s +=
+ "<td class='fc- fc-col" + i + ' ' + contentClass + "'>" + // fc- needed for setDayID
+ "<div>" +
+ "<div class='fc-day-content'>" +
+ "<div style='position:relative'>&nbsp;</div>" +
+ "</div>" +
+ "</div>" +
+ "</td>";
+ }
+ s +=
+ "<td class='fc-agenda-gutter " + contentClass + "'>&nbsp;</td>" +
+ "</tr>" +
+ "</tbody>" +
+ "</table>";
+ dayTable = $(s).appendTo(element);
+ dayHead = dayTable.find('thead');
+ dayHeadCells = dayHead.find('th').slice(1, -1);
+ dayBody = dayTable.find('tbody');
+ dayBodyCells = dayBody.find('td').slice(0, -1);
+ dayBodyCellInners = dayBodyCells.find('div.fc-day-content div');
+ dayBodyFirstCell = dayBodyCells.eq(0);
+ dayBodyFirstCellStretcher = dayBodyFirstCell.find('> div');
+
+ markFirstLast(dayHead.add(dayHead.find('tr')));
+ markFirstLast(dayBody.add(dayBody.find('tr')));
+
+ axisFirstCells = dayHead.find('th:first');
+ gutterCells = dayTable.find('.fc-agenda-gutter');
+
+ slotLayer =
+ $("<div style='position:absolute;z-index:2;left:0;width:100%'/>")
+ .appendTo(element);
+
+ if (opt('allDaySlot')) {
+
+ daySegmentContainer =
+ $("<div style='position:absolute;z-index:8;top:0;left:0'/>")
+ .appendTo(slotLayer);
+
+ s =
+ "<table style='width:100%' class='fc-agenda-allday' cellspacing='0'>" +
+ "<tr>" +
+ "<th class='" + headerClass + " fc-agenda-axis'>" + opt('allDayText') + "</th>" +
+ "<td>" +
+ "<div class='fc-day-content'><div style='position:relative'/></div>" +
+ "</td>" +
+ "<th class='" + headerClass + " fc-agenda-gutter'>&nbsp;</th>" +
+ "</tr>" +
+ "</table>";
+ allDayTable = $(s).appendTo(slotLayer);
+ allDayRow = allDayTable.find('tr');
+
+ dayBind(allDayRow.find('td'));
+
+ axisFirstCells = axisFirstCells.add(allDayTable.find('th:first'));
+ gutterCells = gutterCells.add(allDayTable.find('th.fc-agenda-gutter'));
+
+ slotLayer.append(
+ "<div class='fc-agenda-divider " + headerClass + "'>" +
+ "<div class='fc-agenda-divider-inner'/>" +
+ "</div>"
+ );
+
+ }else{
+
+ daySegmentContainer = $([]); // in jQuery 1.4, we can just do $()
+
+ }
+
+ slotScroller =
+ $("<div style='position:absolute;width:100%;overflow-x:hidden;overflow-y:auto'/>")
+ .appendTo(slotLayer);
+
+ slotContent =
+ $("<div style='position:relative;width:100%;overflow:hidden'/>")
+ .appendTo(slotScroller);
+
+ slotSegmentContainer =
+ $("<div style='position:absolute;z-index:8;top:0;left:0'/>")
+ .appendTo(slotContent);
+
+ s =
+ "<table class='fc-agenda-slots' style='width:100%' cellspacing='0'>" +
+ "<tbody>";
+ d = zeroDate();
+ maxd = addMinutes(cloneDate(d), maxMinute);
+ addMinutes(d, minMinute);
+ slotCnt = 0;
+ for (i=0; d < maxd; i++) {
+ minutes = d.getMinutes();
+ s +=
+ "<tr class='fc-slot" + i + ' ' + (!minutes ? '' : 'fc-minor') + "'>" +
+ "<th class='fc-agenda-axis " + headerClass + "'>" +
+ ((!slotNormal || !minutes) ? formatDate(d, opt('axisFormat')) : '&nbsp;') +
+ "</th>" +
+ "<td class='" + contentClass + "'>" +
+ "<div style='position:relative'>&nbsp;</div>" +
+ "</td>" +
+ "</tr>";
+ addMinutes(d, opt('slotMinutes'));
+ slotCnt++;
+ }
+ s +=
+ "</tbody>" +
+ "</table>";
+ slotTable = $(s).appendTo(slotContent);
+ slotTableFirstInner = slotTable.find('div:first');
+
+ slotBind(slotTable.find('td'));
+
+ axisFirstCells = axisFirstCells.add(slotTable.find('th:first'));
+ }
+
+
+
+ function updateCells() {
+ var i;
+ var headCell;
+ var bodyCell;
+ var date;
+ var today = clearTime(new Date());
+ for (i=0; i<colCnt; i++) {
+ date = colDate(i);
+ headCell = dayHeadCells.eq(i);
+ headCell.html(formatDate(date, colFormat));
+ bodyCell = dayBodyCells.eq(i);
+ if (+date == +today) {
+ bodyCell.addClass(tm + '-state-highlight fc-today');
+ }else{
+ bodyCell.removeClass(tm + '-state-highlight fc-today');
+ }
+ setDayID(headCell.add(bodyCell), date);
+ }
+ }
+
+
+
+ function setHeight(height, dateChanged) {
+ if (height === undefined) {
+ height = viewHeight;
+ }
+ viewHeight = height;
+ slotTopCache = {};
+
+ var headHeight = dayBody.position().top;
+ var allDayHeight = slotScroller.position().top; // including divider
+ var bodyHeight = Math.min( // total body height, including borders
+ height - headHeight, // when scrollbars
+ slotTable.height() + allDayHeight + 1 // when no scrollbars. +1 for bottom border
+ );
+
+ dayBodyFirstCellStretcher
+ .height(bodyHeight - vsides(dayBodyFirstCell));
+
+ slotLayer.css('top', headHeight);
+
+ slotScroller.height(bodyHeight - allDayHeight - 1);
+
+ slotHeight = slotTableFirstInner.height() + 1; // +1 for border
+
+ if (dateChanged) {
+ resetScroll();
+ }
+ }
+
+
+
+ function setWidth(width) {
+ viewWidth = width;
+ colContentPositions.clear();
+
+ axisWidth = 0;
+ setOuterWidth(
+ axisFirstCells
+ .width('')
+ .each(function(i, _cell) {
+ axisWidth = Math.max(axisWidth, $(_cell).outerWidth());
+ }),
+ axisWidth
+ );
+
+ var slotTableWidth = slotScroller[0].clientWidth; // needs to be done after axisWidth (for IE7)
+ //slotTable.width(slotTableWidth);
+
+ gutterWidth = slotScroller.width() - slotTableWidth;
+ if (gutterWidth) {
+ setOuterWidth(gutterCells, gutterWidth);
+ gutterCells
+ .show()
+ .prev()
+ .removeClass('fc-last');
+ }else{
+ gutterCells
+ .hide()
+ .prev()
+ .addClass('fc-last');
+ }
+
+ colWidth = Math.floor((slotTableWidth - axisWidth) / colCnt);
+ setOuterWidth(dayHeadCells.slice(0, -1), colWidth);
+ }
+
+
+
+ function resetScroll() {
+ var d0 = zeroDate();
+ var scrollDate = cloneDate(d0);
+ scrollDate.setHours(opt('firstHour'));
+ var top = timePosition(d0, scrollDate) + 1; // +1 for the border
+ function scroll() {
+ slotScroller.scrollTop(top);
+ }
+ scroll();
+ setTimeout(scroll, 0); // overrides any previous scroll state made by the browser
+ }
+
+
+ function beforeHide() {
+ savedScrollTop = slotScroller.scrollTop();
+ }
+
+
+ function afterShow() {
+ slotScroller.scrollTop(savedScrollTop);
+ }
+
+
+
+ /* Slot/Day clicking and binding
+ -----------------------------------------------------------------------*/
+
+
+ function dayBind(cells) {
+ cells.click(slotClick)
+ .mousedown(daySelectionMousedown);
+ }
+
+
+ function slotBind(cells) {
+ cells.click(slotClick)
+ .mousedown(slotSelectionMousedown);
+ }
+
+
+ function slotClick(ev) {
+ if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick
+ var col = Math.min(colCnt-1, Math.floor((ev.pageX - dayTable.offset().left - axisWidth) / colWidth));
+ var date = colDate(col);
+ var rowMatch = this.parentNode.className.match(/fc-slot(\d+)/); // TODO: maybe use data
+ if (rowMatch) {
+ var mins = parseInt(rowMatch[1]) * opt('slotMinutes');
+ var hours = Math.floor(mins/60);
+ date.setHours(hours);
+ date.setMinutes(mins%60 + minMinute);
+ trigger('dayClick', dayBodyCells[col], date, false, ev);
+ }else{
+ trigger('dayClick', dayBodyCells[col], date, true, ev);
+ }
+ }
+ }
+
+
+
+ /* Semi-transparent Overlay Helpers
+ -----------------------------------------------------*/
+
+
+ function renderDayOverlay(startDate, endDate, refreshCoordinateGrid) { // endDate is exclusive
+ if (refreshCoordinateGrid) {
+ coordinateGrid.build();
+ }
+ var visStart = cloneDate(t.visStart);
+ var startCol, endCol;
+ if (rtl) {
+ startCol = dayDiff(endDate, visStart)*dis+dit+1;
+ endCol = dayDiff(startDate, visStart)*dis+dit+1;
+ }else{
+ startCol = dayDiff(startDate, visStart);
+ endCol = dayDiff(endDate, visStart);
+ }
+ startCol = Math.max(0, startCol);
+ endCol = Math.min(colCnt, endCol);
+ if (startCol < endCol) {
+ dayBind(
+ renderCellOverlay(0, startCol, 0, endCol-1)
+ );
+ }
+ }
+
+
+ function renderCellOverlay(row0, col0, row1, col1) { // only for all-day?
+ var rect = coordinateGrid.rect(row0, col0, row1, col1, slotLayer);
+ return renderOverlay(rect, slotLayer);
+ }
+
+
+ function renderSlotOverlay(overlayStart, overlayEnd) {
+ var dayStart = cloneDate(t.visStart);
+ var dayEnd = addDays(cloneDate(dayStart), 1);
+ for (var i=0; i<colCnt; i++) {
+ var stretchStart = new Date(Math.max(dayStart, overlayStart));
+ var stretchEnd = new Date(Math.min(dayEnd, overlayEnd));
+ if (stretchStart < stretchEnd) {
+ var col = i*dis+dit;
+ var rect = coordinateGrid.rect(0, col, 0, col, slotContent); // only use it for horizontal coords
+ var top = timePosition(dayStart, stretchStart);
+ var bottom = timePosition(dayStart, stretchEnd);
+ rect.top = top;
+ rect.height = bottom - top;
+ slotBind(
+ renderOverlay(rect, slotContent)
+ );
+ }
+ addDays(dayStart, 1);
+ addDays(dayEnd, 1);
+ }
+ }
+
+
+
+ /* Coordinate Utilities
+ -----------------------------------------------------------------------------*/
+
+
+ coordinateGrid = new CoordinateGrid(function(rows, cols) {
+ var e, n, p;
+ dayHeadCells.each(function(i, _e) {
+ e = $(_e);
+ n = e.offset().left;
+ if (i) {
+ p[1] = n;
+ }
+ p = [n];
+ cols[i] = p;
+ });
+ p[1] = n + e.outerWidth();
+ if (opt('allDaySlot')) {
+ e = allDayRow;
+ n = e.offset().top;
+ rows[0] = [n, n+e.outerHeight()];
+ }
+ var slotTableTop = slotContent.offset().top;
+ var slotScrollerTop = slotScroller.offset().top;
+ var slotScrollerBottom = slotScrollerTop + slotScroller.outerHeight();
+ function constrain(n) {
+ return Math.max(slotScrollerTop, Math.min(slotScrollerBottom, n));
+ }
+ for (var i=0; i<slotCnt; i++) {
+ rows.push([
+ constrain(slotTableTop + slotHeight*i),
+ constrain(slotTableTop + slotHeight*(i+1))
+ ]);
+ }
+ });
+
+
+ hoverListener = new HoverListener(coordinateGrid);
+
+
+ colContentPositions = new HorizontalPositionCache(function(col) {
+ return dayBodyCellInners.eq(col);
+ });
+
+
+ function colContentLeft(col) {
+ return colContentPositions.left(col);
+ }
+
+
+ function colContentRight(col) {
+ return colContentPositions.right(col);
+ }
+
+
+
+
+ function dateCell(date) { // "cell" terminology is now confusing
+ return {
+ row: Math.floor(dayDiff(date, t.visStart) / 7),
+ col: dayOfWeekCol(date.getDay())
+ };
+ }
+
+
+ function cellDate(cell) {
+ var d = colDate(cell.col);
+ var slotIndex = cell.row;
+ if (opt('allDaySlot')) {
+ slotIndex--;
+ }
+ if (slotIndex >= 0) {
+ addMinutes(d, minMinute + slotIndex * opt('slotMinutes'));
+ }
+ return d;
+ }
+
+
+ function colDate(col) { // returns dates with 00:00:00
+ return addDays(cloneDate(t.visStart), col*dis+dit);
+ }
+
+
+ function cellIsAllDay(cell) {
+ return opt('allDaySlot') && !cell.row;
+ }
+
+
+ function dayOfWeekCol(dayOfWeek) {
+ return ((dayOfWeek - Math.max(firstDay, nwe) + colCnt) % colCnt)*dis+dit;
+ }
+
+
+
+
+ // get the Y coordinate of the given time on the given day (both Date objects)
+ function timePosition(day, time) { // both date objects. day holds 00:00 of current day
+ day = cloneDate(day, true);
+ if (time < addMinutes(cloneDate(day), minMinute)) {
+ return 0;
+ }
+ if (time >= addMinutes(cloneDate(day), maxMinute)) {
+ return slotTable.height();
+ }
+ var slotMinutes = opt('slotMinutes'),
+ minutes = time.getHours()*60 + time.getMinutes() - minMinute,
+ slotI = Math.floor(minutes / slotMinutes),
+ slotTop = slotTopCache[slotI];
+ if (slotTop === undefined) {
+ slotTop = slotTopCache[slotI] = slotTable.find('tr:eq(' + slotI + ') td div')[0].offsetTop; //.position().top; // need this optimization???
+ }
+ return Math.max(0, Math.round(
+ slotTop - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes)
+ ));
+ }
+
+
+ function allDayBounds() {
+ return {
+ left: axisWidth,
+ right: viewWidth - gutterWidth
+ }
+ }
+
+
+ function getAllDayRow(index) {
+ return allDayRow;
+ }
+
+
+ function defaultEventEnd(event) {
+ var start = cloneDate(event.start);
+ if (event.allDay) {
+ return start;
+ }
+ return addMinutes(start, opt('defaultEventMinutes'));
+ }
+
+
+
+ /* Selection
+ ---------------------------------------------------------------------------------*/
+
+
+ function defaultSelectionEnd(startDate, allDay) {
+ if (allDay) {
+ return cloneDate(startDate);
+ }
+ return addMinutes(cloneDate(startDate), opt('slotMinutes'));
+ }
+
+
+ function renderSelection(startDate, endDate, allDay) { // only for all-day
+ if (allDay) {
+ if (opt('allDaySlot')) {
+ renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true);
+ }
+ }else{
+ renderSlotSelection(startDate, endDate);
+ }
+ }
+
+
+ function renderSlotSelection(startDate, endDate) {
+ var helperOption = opt('selectHelper');
+ coordinateGrid.build();
+ if (helperOption) {
+ var col = dayDiff(startDate, t.visStart) * dis + dit;
+ if (col >= 0 && col < colCnt) { // only works when times are on same day
+ var rect = coordinateGrid.rect(0, col, 0, col, slotContent); // only for horizontal coords
+ var top = timePosition(startDate, startDate);
+ var bottom = timePosition(startDate, endDate);
+ if (bottom > top) { // protect against selections that are entirely before or after visible range
+ rect.top = top;
+ rect.height = bottom - top;
+ rect.left += 2;
+ rect.width -= 5;
+ if ($.isFunction(helperOption)) {
+ var helperRes = helperOption(startDate, endDate);
+ if (helperRes) {
+ rect.position = 'absolute';
+ rect.zIndex = 8;
+ selectionHelper = $(helperRes)
+ .css(rect)
+ .appendTo(slotContent);
+ }
+ }else{
+ rect.isStart = true; // conside rect a "seg" now
+ rect.isEnd = true; //
+ selectionHelper = $(slotSegHtml(
+ {
+ title: '',
+ start: startDate,
+ end: endDate,
+ className: ['fc-select-helper'],
+ editable: false
+ },
+ rect
+ ));
+ selectionHelper.css('opacity', opt('dragOpacity'));
+ }
+ if (selectionHelper) {
+ slotBind(selectionHelper);
+ slotContent.append(selectionHelper);
+ setOuterWidth(selectionHelper, rect.width, true); // needs to be after appended
+ setOuterHeight(selectionHelper, rect.height, true);
+ }
+ }
+ }
+ }else{
+ renderSlotOverlay(startDate, endDate);
+ }
+ }
+
+
+ function clearSelection() {
+ clearOverlays();
+ if (selectionHelper) {
+ selectionHelper.remove();
+ selectionHelper = null;
+ }
+ }
+
+
+ function slotSelectionMousedown(ev) {
+ if (ev.which == 1 && opt('selectable')) { // ev.which==1 means left mouse button
+ unselect(ev);
+ var dates;
+ hoverListener.start(function(cell, origCell) {
+ clearSelection();
+ if (cell && cell.col == origCell.col && !cellIsAllDay(cell)) {
+ var d1 = cellDate(origCell);
+ var d2 = cellDate(cell);
+ dates = [
+ d1,
+ addMinutes(cloneDate(d1), opt('slotMinutes')),
+ d2,
+ addMinutes(cloneDate(d2), opt('slotMinutes'))
+ ].sort(cmp);
+ renderSlotSelection(dates[0], dates[3]);
+ }else{
+ dates = null;
+ }
+ }, ev);
+ $(document).one('mouseup', function(ev) {
+ hoverListener.stop();
+ if (dates) {
+ if (+dates[0] == +dates[1]) {
+ reportDayClick(dates[0], false, ev);
+ }
+ reportSelection(dates[0], dates[3], false, ev);
+ }
+ });
+ }
+ }
+
+
+ function reportDayClick(date, allDay, ev) {
+ trigger('dayClick', dayBodyCells[dayOfWeekCol(date.getDay())], date, allDay, ev);
+ }
+
+
+
+ /* External Dragging
+ --------------------------------------------------------------------------------*/
+
+
+ function dragStart(_dragElement, ev, ui) {
+ hoverListener.start(function(cell) {
+ clearOverlays();
+ if (cell) {
+ if (cellIsAllDay(cell)) {
+ renderCellOverlay(cell.row, cell.col, cell.row, cell.col);
+ }else{
+ var d1 = cellDate(cell);
+ var d2 = addMinutes(cloneDate(d1), opt('defaultEventMinutes'));
+ renderSlotOverlay(d1, d2);
+ }
+ }
+ }, ev);
+ }
+
+
+ function dragStop(_dragElement, ev, ui) {
+ var cell = hoverListener.stop();
+ clearOverlays();
+ if (cell) {
+ trigger('drop', _dragElement, cellDate(cell), cellIsAllDay(cell), ev, ui);
+ }
+ }
+
+
+}
+
+function AgendaEventRenderer() {
+ var t = this;
+
+
+ // exports
+ t.renderEvents = renderEvents;
+ t.compileDaySegs = compileDaySegs; // for DayEventRenderer
+ t.clearEvents = clearEvents;
+ t.slotSegHtml = slotSegHtml;
+ t.bindDaySeg = bindDaySeg;
+
+
+ // imports
+ DayEventRenderer.call(t);
+ var opt = t.opt;
+ var trigger = t.trigger;
+ //var setOverflowHidden = t.setOverflowHidden;
+ var isEventDraggable = t.isEventDraggable;
+ var isEventResizable = t.isEventResizable;
+ var eventEnd = t.eventEnd;
+ var reportEvents = t.reportEvents;
+ var reportEventClear = t.reportEventClear;
+ var eventElementHandlers = t.eventElementHandlers;
+ var setHeight = t.setHeight;
+ var getDaySegmentContainer = t.getDaySegmentContainer;
+ var getSlotSegmentContainer = t.getSlotSegmentContainer;
+ var getHoverListener = t.getHoverListener;
+ var getMaxMinute = t.getMaxMinute;
+ var getMinMinute = t.getMinMinute;
+ var timePosition = t.timePosition;
+ var colContentLeft = t.colContentLeft;
+ var colContentRight = t.colContentRight;
+ var renderDaySegs = t.renderDaySegs;
+ var resizableDayEvent = t.resizableDayEvent; // TODO: streamline binding architecture
+ var getColCnt = t.getColCnt;
+ var getColWidth = t.getColWidth;
+ var getSlotHeight = t.getSlotHeight;
+ var getBodyContent = t.getBodyContent;
+ var reportEventElement = t.reportEventElement;
+ var showEvents = t.showEvents;
+ var hideEvents = t.hideEvents;
+ var eventDrop = t.eventDrop;
+ var eventResize = t.eventResize;
+ var renderDayOverlay = t.renderDayOverlay;
+ var clearOverlays = t.clearOverlays;
+ var calendar = t.calendar;
+ var formatDate = calendar.formatDate;
+ var formatDates = calendar.formatDates;
+
+
+
+ /* Rendering
+ ----------------------------------------------------------------------------*/
+
+
+ function renderEvents(events, modifiedEventId) {
+ reportEvents(events);
+ var i, len=events.length,
+ dayEvents=[],
+ slotEvents=[];
+ for (i=0; i<len; i++) {
+ if (events[i].allDay) {
+ dayEvents.push(events[i]);
+ }else{
+ slotEvents.push(events[i]);
+ }
+ }
+ if (opt('allDaySlot')) {
+ renderDaySegs(compileDaySegs(dayEvents), modifiedEventId);
+ setHeight(); // no params means set to viewHeight
+ }
+ renderSlotSegs(compileSlotSegs(slotEvents), modifiedEventId);
+ }
+
+
+ function clearEvents() {
+ reportEventClear();
+ getDaySegmentContainer().empty();
+ getSlotSegmentContainer().empty();
+ }
+
+
+ function compileDaySegs(events) {
+ var levels = stackSegs(sliceSegs(events, $.map(events, exclEndDay), t.visStart, t.visEnd)),
+ i, levelCnt=levels.length, level,
+ j, seg,
+ segs=[];
+ for (i=0; i<levelCnt; i++) {
+ level = levels[i];
+ for (j=0; j<level.length; j++) {
+ seg = level[j];
+ seg.row = 0;
+ seg.level = i; // not needed anymore
+ segs.push(seg);
+ }
+ }
+ return segs;
+ }
+
+
+ function compileSlotSegs(events) {
+ var colCnt = getColCnt(),
+ minMinute = getMinMinute(),
+ maxMinute = getMaxMinute(),
+ d = addMinutes(cloneDate(t.visStart), minMinute),
+ visEventEnds = $.map(events, slotEventEnd),
+ i, col,
+ j, level,
+ k, seg,
+ segs=[];
+ for (i=0; i<colCnt; i++) {
+ col = stackSegs(sliceSegs(events, visEventEnds, d, addMinutes(cloneDate(d), maxMinute-minMinute)));
+ countForwardSegs(col);
+ for (j=0; j<col.length; j++) {
+ level = col[j];
+ for (k=0; k<level.length; k++) {
+ seg = level[k];
+ seg.col = i;
+ seg.level = j;
+ segs.push(seg);
+ }
+ }
+ addDays(d, 1, true);
+ }
+ return segs;
+ }
+
+
+ function slotEventEnd(event) {
+ if (event.end) {
+ return cloneDate(event.end);
+ }else{
+ return addMinutes(cloneDate(event.start), opt('defaultEventMinutes'));
+ }
+ }
+
+
+ // renders events in the 'time slots' at the bottom
+
+ function renderSlotSegs(segs, modifiedEventId) {
+
+ var i, segCnt=segs.length, seg,
+ event,
+ classes,
+ top, bottom,
+ colI, levelI, forward,
+ leftmost,
+ availWidth,
+ outerWidth,
+ left,
+ html='',
+ eventElements,
+ eventElement,
+ triggerRes,
+ vsideCache={},
+ hsideCache={},
+ key, val,
+ contentElement,
+ height,
+ slotSegmentContainer = getSlotSegmentContainer(),
+ rtl, dis, dit,
+ colCnt = getColCnt();
+
+ if (rtl = opt('isRTL')) {
+ dis = -1;
+ dit = colCnt - 1;
+ }else{
+ dis = 1;
+ dit = 0;
+ }
+
+ // calculate position/dimensions, create html
+ for (i=0; i<segCnt; i++) {
+ seg = segs[i];
+ event = seg.event;
+ top = timePosition(seg.start, seg.start);
+ bottom = timePosition(seg.start, seg.end);
+ colI = seg.col;
+ levelI = seg.level;
+ forward = seg.forward || 0;
+ leftmost = colContentLeft(colI*dis + dit);
+ availWidth = colContentRight(colI*dis + dit) - leftmost;
+ availWidth = Math.min(availWidth-6, availWidth*.95); // TODO: move this to CSS
+ if (levelI) {
+ // indented and thin
+ outerWidth = availWidth / (levelI + forward + 1);
+ }else{
+ if (forward) {
+ // moderately wide, aligned left still
+ outerWidth = ((availWidth / (forward + 1)) - (12/2)) * 2; // 12 is the predicted width of resizer =
+ }else{
+ // can be entire width, aligned left
+ outerWidth = availWidth;
+ }
+ }
+ left = leftmost + // leftmost possible
+ (availWidth / (levelI + forward + 1) * levelI) // indentation
+ * dis + (rtl ? availWidth - outerWidth : 0); // rtl
+ seg.top = top;
+ seg.left = left;
+ seg.outerWidth = outerWidth;
+ seg.outerHeight = bottom - top;
+ html += slotSegHtml(event, seg);
+ }
+ slotSegmentContainer[0].innerHTML = html; // faster than html()
+ eventElements = slotSegmentContainer.children();
+
+ // retrieve elements, run through eventRender callback, bind event handlers
+ for (i=0; i<segCnt; i++) {
+ seg = segs[i];
+ event = seg.event;
+ eventElement = $(eventElements[i]); // faster than eq()
+ triggerRes = trigger('eventRender', event, event, eventElement);
+ if (triggerRes === false) {
+ eventElement.remove();
+ }else{
+ if (triggerRes && triggerRes !== true) {
+ eventElement.remove();
+ eventElement = $(triggerRes)
+ .css({
+ position: 'absolute',
+ top: seg.top,
+ left: seg.left
+ })
+ .appendTo(slotSegmentContainer);
+ }
+ seg.element = eventElement;
+ if (event._id === modifiedEventId) {
+ bindSlotSeg(event, eventElement, seg);
+ }else{
+ eventElement[0]._fci = i; // for lazySegBind
+ }
+ reportEventElement(event, eventElement);
+ }
+ }
+
+ lazySegBind(slotSegmentContainer, segs, bindSlotSeg);
+
+ // record event sides and title positions
+ for (i=0; i<segCnt; i++) {
+ seg = segs[i];
+ if (eventElement = seg.element) {
+ val = vsideCache[key = seg.key = cssKey(eventElement[0])];
+ seg.vsides = val === undefined ? (vsideCache[key] = vsides(eventElement, true)) : val;
+ val = hsideCache[key];
+ seg.hsides = val === undefined ? (hsideCache[key] = hsides(eventElement, true)) : val;
+ contentElement = eventElement.find('div.fc-event-content');
+ if (contentElement.length) {
+ seg.contentTop = contentElement[0].offsetTop;
+ }
+ }
+ }
+
+ // set all positions/dimensions at once
+ for (i=0; i<segCnt; i++) {
+ seg = segs[i];
+ if (eventElement = seg.element) {
+ eventElement[0].style.width = Math.max(0, seg.outerWidth - seg.hsides) + 'px';
+ height = Math.max(0, seg.outerHeight - seg.vsides);
+ eventElement[0].style.height = height + 'px';
+ event = seg.event;
+ if (seg.contentTop !== undefined && height - seg.contentTop < 10) {
+ // not enough room for title, put it in the time header
+ eventElement.find('div.fc-event-time')
+ .text(formatDate(event.start, opt('timeFormat')) + ' - ' + event.title);
+ eventElement.find('div.fc-event-title')
+ .remove();
+ }
+ trigger('eventAfterRender', event, event, eventElement);
+ }
+ }
+
+ }
+
+
+ function slotSegHtml(event, seg) {
+ var html = "<";
+ var url = event.url;
+ var skinCss = getSkinCss(event, opt);
+ var skinCssAttr = (skinCss ? " style='" + skinCss + "'" : '');
+ var classes = ['fc-event', 'fc-event-skin', 'fc-event-vert'];
+ if (isEventDraggable(event)) {
+ classes.push('fc-event-draggable');
+ }
+ if (seg.isStart) {
+ classes.push('fc-corner-top');
+ }
+ if (seg.isEnd) {
+ classes.push('fc-corner-bottom');
+ }
+ classes = classes.concat(event.className);
+ if (event.source) {
+ classes = classes.concat(event.source.className || []);
+ }
+ if (url) {
+ html += "a href='" + htmlEscape(event.url) + "'";
+ }else{
+ html += "div";
+ }
+ html +=
+ " class='" + classes.join(' ') + "'" +
+ " style='position:absolute;z-index:8;top:" + seg.top + "px;left:" + seg.left + "px;" + skinCss + "'" +
+ ">" +
+ "<div class='fc-event-inner fc-event-skin'" + skinCssAttr + ">" +
+ "<div class='fc-event-head fc-event-skin'" + skinCssAttr + ">" +
+ "<div class='fc-event-time'>" +
+ htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +
+ "</div>" +
+ "</div>" +
+ "<div class='fc-event-content'>" +
+ "<div class='fc-event-title'>" +
+ htmlEscape(event.title) +
+ "</div>" +
+ "</div>" +
+ "<div class='fc-event-bg'></div>" +
+ "</div>"; // close inner
+ if (seg.isEnd && isEventResizable(event)) {
+ html +=
+ "<div class='ui-resizable-handle ui-resizable-s'>=</div>";
+ }
+ html +=
+ "</" + (url ? "a" : "div") + ">";
+ return html;
+ }
+
+
+ function bindDaySeg(event, eventElement, seg) {
+ if (isEventDraggable(event)) {
+ draggableDayEvent(event, eventElement, seg.isStart);
+ }
+ if (seg.isEnd && isEventResizable(event)) {
+ resizableDayEvent(event, eventElement, seg);
+ }
+ eventElementHandlers(event, eventElement);
+ // needs to be after, because resizableDayEvent might stopImmediatePropagation on click
+ }
+
+
+ function bindSlotSeg(event, eventElement, seg) {
+ var timeElement = eventElement.find('div.fc-event-time');
+ if (isEventDraggable(event)) {
+ draggableSlotEvent(event, eventElement, timeElement);
+ }
+ if (seg.isEnd && isEventResizable(event)) {
+ resizableSlotEvent(event, eventElement, timeElement);
+ }
+ eventElementHandlers(event, eventElement);
+ }
+
+
+
+ /* Dragging
+ -----------------------------------------------------------------------------------*/
+
+
+ // when event starts out FULL-DAY
+
+ function draggableDayEvent(event, eventElement, isStart) {
+ var origWidth;
+ var revert;
+ var allDay=true;
+ var dayDelta;
+ var dis = opt('isRTL') ? -1 : 1;
+ var hoverListener = getHoverListener();
+ var colWidth = getColWidth();
+ var slotHeight = getSlotHeight();
+ var minMinute = getMinMinute();
+ eventElement.draggable({
+ zIndex: 9,
+ opacity: opt('dragOpacity', 'month'), // use whatever the month view was using
+ revertDuration: opt('dragRevertDuration'),
+ start: function(ev, ui) {
+ trigger('eventDragStart', eventElement, event, ev, ui);
+ hideEvents(event, eventElement);
+ origWidth = eventElement.width();
+ hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
+ clearOverlays();
+ if (cell) {
+ //setOverflowHidden(true);
+ revert = false;
+ dayDelta = colDelta * dis;
+ if (!cell.row) {
+ // on full-days
+ renderDayOverlay(
+ addDays(cloneDate(event.start), dayDelta),
+ addDays(exclEndDay(event), dayDelta)
+ );
+ resetElement();
+ }else{
+ // mouse is over bottom slots
+ if (isStart) {
+ if (allDay) {
+ // convert event to temporary slot-event
+ eventElement.width(colWidth - 10); // don't use entire width
+ setOuterHeight(
+ eventElement,
+ slotHeight * Math.round(
+ (event.end ? ((event.end - event.start) / MINUTE_MS) : opt('defaultEventMinutes'))
+ / opt('slotMinutes')
+ )
+ );
+ eventElement.draggable('option', 'grid', [colWidth, 1]);
+ allDay = false;
+ }
+ }else{
+ revert = true;
+ }
+ }
+ revert = revert || (allDay && !dayDelta);
+ }else{
+ resetElement();
+ //setOverflowHidden(false);
+ revert = true;
+ }
+ eventElement.draggable('option', 'revert', revert);
+ }, ev, 'drag');
+ },
+ stop: function(ev, ui) {
+ hoverListener.stop();
+ clearOverlays();
+ trigger('eventDragStop', eventElement, event, ev, ui);
+ if (revert) {
+ // hasn't moved or is out of bounds (draggable has already reverted)
+ resetElement();
+ eventElement.css('filter', ''); // clear IE opacity side-effects
+ showEvents(event, eventElement);
+ }else{
+ // changed!
+ var minuteDelta = 0;
+ if (!allDay) {
+ minuteDelta = Math.round((eventElement.offset().top - getBodyContent().offset().top) / slotHeight)
+ * opt('slotMinutes')
+ + minMinute
+ - (event.start.getHours() * 60 + event.start.getMinutes());
+ }
+ eventDrop(this, event, dayDelta, minuteDelta, allDay, ev, ui);
+ }
+ //setOverflowHidden(false);
+ }
+ });
+ function resetElement() {
+ if (!allDay) {
+ eventElement
+ .width(origWidth)
+ .height('')
+ .draggable('option', 'grid', null);
+ allDay = true;
+ }
+ }
+ }
+
+
+ // when event starts out IN TIMESLOTS
+
+ function draggableSlotEvent(event, eventElement, timeElement) {
+ var origPosition;
+ var allDay=false;
+ var dayDelta;
+ var minuteDelta;
+ var prevMinuteDelta;
+ var dis = opt('isRTL') ? -1 : 1;
+ var hoverListener = getHoverListener();
+ var colCnt = getColCnt();
+ var colWidth = getColWidth();
+ var slotHeight = getSlotHeight();
+ eventElement.draggable({
+ zIndex: 9,
+ scroll: false,
+ grid: [colWidth, slotHeight],
+ axis: colCnt==1 ? 'y' : false,
+ opacity: opt('dragOpacity'),
+ revertDuration: opt('dragRevertDuration'),
+ start: function(ev, ui) {
+ trigger('eventDragStart', eventElement, event, ev, ui);
+ hideEvents(event, eventElement);
+ origPosition = eventElement.position();
+ minuteDelta = prevMinuteDelta = 0;
+ hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
+ eventElement.draggable('option', 'revert', !cell);
+ clearOverlays();
+ if (cell) {
+ dayDelta = colDelta * dis;
+ if (opt('allDaySlot') && !cell.row) {
+ // over full days
+ if (!allDay) {
+ // convert to temporary all-day event
+ allDay = true;
+ timeElement.hide();
+ eventElement.draggable('option', 'grid', null);
+ }
+ renderDayOverlay(
+ addDays(cloneDate(event.start), dayDelta),
+ addDays(exclEndDay(event), dayDelta)
+ );
+ }else{
+ // on slots
+ resetElement();
+ }
+ }
+ }, ev, 'drag');
+ },
+ drag: function(ev, ui) {
+ minuteDelta = Math.round((ui.position.top - origPosition.top) / slotHeight) * opt('slotMinutes');
+ if (minuteDelta != prevMinuteDelta) {
+ if (!allDay) {
+ updateTimeText(minuteDelta);
+ }
+ prevMinuteDelta = minuteDelta;
+ }
+ },
+ stop: function(ev, ui) {
+ var cell = hoverListener.stop();
+ clearOverlays();
+ trigger('eventDragStop', eventElement, event, ev, ui);
+ if (cell && (dayDelta || minuteDelta || allDay)) {
+ // changed!
+ eventDrop(this, event, dayDelta, allDay ? 0 : minuteDelta, allDay, ev, ui);
+ }else{
+ // either no change or out-of-bounds (draggable has already reverted)
+ resetElement();
+ eventElement.css('filter', ''); // clear IE opacity side-effects
+ eventElement.css(origPosition); // sometimes fast drags make event revert to wrong position
+ updateTimeText(0);
+ showEvents(event, eventElement);
+ }
+ }
+ });
+ function updateTimeText(minuteDelta) {
+ var newStart = addMinutes(cloneDate(event.start), minuteDelta);
+ var newEnd;
+ if (event.end) {
+ newEnd = addMinutes(cloneDate(event.end), minuteDelta);
+ }
+ timeElement.text(formatDates(newStart, newEnd, opt('timeFormat')));
+ }
+ function resetElement() {
+ // convert back to original slot-event
+ if (allDay) {
+ timeElement.css('display', ''); // show() was causing display=inline
+ eventElement.draggable('option', 'grid', [colWidth, slotHeight]);
+ allDay = false;
+ }
+ }
+ }
+
+
+
+ /* Resizing
+ --------------------------------------------------------------------------------------*/
+
+
+ function resizableSlotEvent(event, eventElement, timeElement) {
+ var slotDelta, prevSlotDelta;
+ var slotHeight = getSlotHeight();
+ eventElement.resizable({
+ handles: {
+ s: 'div.ui-resizable-s'
+ },
+ grid: slotHeight,
+ start: function(ev, ui) {
+ slotDelta = prevSlotDelta = 0;
+ hideEvents(event, eventElement);
+ eventElement.css('z-index', 9);
+ trigger('eventResizeStart', this, event, ev, ui);
+ },
+ resize: function(ev, ui) {
+ // don't rely on ui.size.height, doesn't take grid into account
+ slotDelta = Math.round((Math.max(slotHeight, eventElement.height()) - ui.originalSize.height) / slotHeight);
+ if (slotDelta != prevSlotDelta) {
+ timeElement.text(
+ formatDates(
+ event.start,
+ (!slotDelta && !event.end) ? null : // no change, so don't display time range
+ addMinutes(eventEnd(event), opt('slotMinutes')*slotDelta),
+ opt('timeFormat')
+ )
+ );
+ prevSlotDelta = slotDelta;
+ }
+ },
+ stop: function(ev, ui) {
+ trigger('eventResizeStop', this, event, ev, ui);
+ if (slotDelta) {
+ eventResize(this, event, 0, opt('slotMinutes')*slotDelta, ev, ui);
+ }else{
+ eventElement.css('z-index', 8);
+ showEvents(event, eventElement);
+ // BUG: if event was really short, need to put title back in span
+ }
+ }
+ });
+ }
+
+
+}
+
+
+function countForwardSegs(levels) {
+ var i, j, k, level, segForward, segBack;
+ for (i=levels.length-1; i>0; i--) {
+ level = levels[i];
+ for (j=0; j<level.length; j++) {
+ segForward = level[j];
+ for (k=0; k<levels[i-1].length; k++) {
+ segBack = levels[i-1][k];
+ if (segsCollide(segForward, segBack)) {
+ segBack.forward = Math.max(segBack.forward||0, (segForward.forward||0)+1);
+ }
+ }
+ }
+ }
+}
+
+
+
+
+function View(element, calendar, viewName) {
+ var t = this;
+
+
+ // exports
+ t.element = element;
+ t.calendar = calendar;
+ t.name = viewName;
+ t.opt = opt;
+ t.trigger = trigger;
+ //t.setOverflowHidden = setOverflowHidden;
+ t.isEventDraggable = isEventDraggable;
+ t.isEventResizable = isEventResizable;
+ t.reportEvents = reportEvents;
+ t.eventEnd = eventEnd;
+ t.reportEventElement = reportEventElement;
+ t.reportEventClear = reportEventClear;
+ t.eventElementHandlers = eventElementHandlers;
+ t.showEvents = showEvents;
+ t.hideEvents = hideEvents;
+ t.eventDrop = eventDrop;
+ t.eventResize = eventResize;
+ // t.title
+ // t.start, t.end
+ // t.visStart, t.visEnd
+
+
+ // imports
+ var defaultEventEnd = t.defaultEventEnd;
+ var normalizeEvent = calendar.normalizeEvent; // in EventManager
+ var reportEventChange = calendar.reportEventChange;
+
+
+ // locals
+ var eventsByID = {};
+ var eventElements = [];
+ var eventElementsByID = {};
+ var options = calendar.options;
+
+
+
+ function opt(name, viewNameOverride) {
+ var v = options[name];
+ if (typeof v == 'object') {
+ return smartProperty(v, viewNameOverride || viewName);
+ }
+ return v;
+ }
+
+
+ function trigger(name, thisObj) {
+ return calendar.trigger.apply(
+ calendar,
+ [name, thisObj || t].concat(Array.prototype.slice.call(arguments, 2), [t])
+ );
+ }
+
+
+ /*
+ function setOverflowHidden(bool) {
+ element.css('overflow', bool ? 'hidden' : '');
+ }
+ */
+
+
+ function isEventDraggable(event) {
+ return isEventEditable(event) && !opt('disableDragging');
+ }
+
+
+ function isEventResizable(event) { // but also need to make sure the seg.isEnd == true
+ return isEventEditable(event) && !opt('disableResizing');
+ }
+
+
+ function isEventEditable(event) {
+ return firstDefined(event.editable, (event.source || {}).editable, opt('editable'));
+ }
+
+
+
+ /* Event Data
+ ------------------------------------------------------------------------------*/
+
+
+ // report when view receives new events
+ function reportEvents(events) { // events are already normalized at this point
+ eventsByID = {};
+ var i, len=events.length, event;
+ for (i=0; i<len; i++) {
+ event = events[i];
+ if (eventsByID[event._id]) {
+ eventsByID[event._id].push(event);
+ }else{
+ eventsByID[event._id] = [event];
+ }
+ }
+ }
+
+
+ // returns a Date object for an event's end
+ function eventEnd(event) {
+ return event.end ? cloneDate(event.end) : defaultEventEnd(event);
+ }
+
+
+
+ /* Event Elements
+ ------------------------------------------------------------------------------*/
+
+
+ // report when view creates an element for an event
+ function reportEventElement(event, element) {
+ eventElements.push(element);
+ if (eventElementsByID[event._id]) {
+ eventElementsByID[event._id].push(element);
+ }else{
+ eventElementsByID[event._id] = [element];
+ }
+ }
+
+
+ function reportEventClear() {
+ eventElements = [];
+ eventElementsByID = {};
+ }
+
+
+ // attaches eventClick, eventMouseover, eventMouseout
+ function eventElementHandlers(event, eventElement) {
+ eventElement
+ .click(function(ev) {
+ if (!eventElement.hasClass('ui-draggable-dragging') &&
+ !eventElement.hasClass('ui-resizable-resizing')) {
+ return trigger('eventClick', this, event, ev);
+ }
+ })
+ .hover(
+ function(ev) {
+ trigger('eventMouseover', this, event, ev);
+ },
+ function(ev) {
+ trigger('eventMouseout', this, event, ev);
+ }
+ );
+ // TODO: don't fire eventMouseover/eventMouseout *while* dragging is occuring (on subject element)
+ // TODO: same for resizing
+ }
+
+
+ function showEvents(event, exceptElement) {
+ eachEventElement(event, exceptElement, 'show');
+ }
+
+
+ function hideEvents(event, exceptElement) {
+ eachEventElement(event, exceptElement, 'hide');
+ }
+
+
+ function eachEventElement(event, exceptElement, funcName) {
+ var elements = eventElementsByID[event._id],
+ i, len = elements.length;
+ for (i=0; i<len; i++) {
+ if (!exceptElement || elements[i][0] != exceptElement[0]) {
+ elements[i][funcName]();
+ }
+ }
+ }
+
+
+
+ /* Event Modification Reporting
+ ---------------------------------------------------------------------------------*/
+
+
+ function eventDrop(e, event, dayDelta, minuteDelta, allDay, ev, ui) {
+ var oldAllDay = event.allDay;
+ var eventId = event._id;
+ moveEvents(eventsByID[eventId], dayDelta, minuteDelta, allDay);
+ trigger(
+ 'eventDrop',
+ e,
+ event,
+ dayDelta,
+ minuteDelta,
+ allDay,
+ function() {
+ // TODO: investigate cases where this inverse technique might not work
+ moveEvents(eventsByID[eventId], -dayDelta, -minuteDelta, oldAllDay);
+ reportEventChange(eventId);
+ },
+ ev,
+ ui
+ );
+ reportEventChange(eventId);
+ }
+
+
+ function eventResize(e, event, dayDelta, minuteDelta, ev, ui) {
+ var eventId = event._id;
+ elongateEvents(eventsByID[eventId], dayDelta, minuteDelta);
+ trigger(
+ 'eventResize',
+ e,
+ event,
+ dayDelta,
+ minuteDelta,
+ function() {
+ // TODO: investigate cases where this inverse technique might not work
+ elongateEvents(eventsByID[eventId], -dayDelta, -minuteDelta);
+ reportEventChange(eventId);
+ },
+ ev,
+ ui
+ );
+ reportEventChange(eventId);
+ }
+
+
+
+ /* Event Modification Math
+ ---------------------------------------------------------------------------------*/
+
+
+ function moveEvents(events, dayDelta, minuteDelta, allDay) {
+ minuteDelta = minuteDelta || 0;
+ for (var e, len=events.length, i=0; i<len; i++) {
+ e = events[i];
+ if (allDay !== undefined) {
+ e.allDay = allDay;
+ }
+ addMinutes(addDays(e.start, dayDelta, true), minuteDelta);
+ if (e.end) {
+ e.end = addMinutes(addDays(e.end, dayDelta, true), minuteDelta);
+ }
+ normalizeEvent(e, options);
+ }
+ }
+
+
+ function elongateEvents(events, dayDelta, minuteDelta) {
+ minuteDelta = minuteDelta || 0;
+ for (var e, len=events.length, i=0; i<len; i++) {
+ e = events[i];
+ e.end = addMinutes(addDays(eventEnd(e), dayDelta, true), minuteDelta);
+ normalizeEvent(e, options);
+ }
+ }
+
+
+}
+
+function DayEventRenderer() {
+ var t = this;
+
+
+ // exports
+ t.renderDaySegs = renderDaySegs;
+ t.resizableDayEvent = resizableDayEvent;
+
+
+ // imports
+ var opt = t.opt;
+ var trigger = t.trigger;
+ var isEventDraggable = t.isEventDraggable;
+ var isEventResizable = t.isEventResizable;
+ var eventEnd = t.eventEnd;
+ var reportEventElement = t.reportEventElement;
+ var showEvents = t.showEvents;
+ var hideEvents = t.hideEvents;
+ var eventResize = t.eventResize;
+ var getRowCnt = t.getRowCnt;
+ var getColCnt = t.getColCnt;
+ var getColWidth = t.getColWidth;
+ var allDayRow = t.allDayRow;
+ var allDayBounds = t.allDayBounds;
+ var colContentLeft = t.colContentLeft;
+ var colContentRight = t.colContentRight;
+ var dayOfWeekCol = t.dayOfWeekCol;
+ var dateCell = t.dateCell;
+ var compileDaySegs = t.compileDaySegs;
+ var getDaySegmentContainer = t.getDaySegmentContainer;
+ var bindDaySeg = t.bindDaySeg; //TODO: streamline this
+ var formatDates = t.calendar.formatDates;
+ var renderDayOverlay = t.renderDayOverlay;
+ var clearOverlays = t.clearOverlays;
+ var clearSelection = t.clearSelection;
+
+
+
+ /* Rendering
+ -----------------------------------------------------------------------------*/
+
+
+ function renderDaySegs(segs, modifiedEventId) {
+ var segmentContainer = getDaySegmentContainer();
+ var rowDivs;
+ var rowCnt = getRowCnt();
+ var colCnt = getColCnt();
+ var i = 0;
+ var rowI;
+ var levelI;
+ var colHeights;
+ var j;
+ var segCnt = segs.length;
+ var seg;
+ var top;
+ var k;
+ segmentContainer[0].innerHTML = daySegHTML(segs); // faster than .html()
+ daySegElementResolve(segs, segmentContainer.children());
+ daySegElementReport(segs);
+ daySegHandlers(segs, segmentContainer, modifiedEventId);
+ daySegCalcHSides(segs);
+ daySegSetWidths(segs);
+ daySegCalcHeights(segs);
+ rowDivs = getRowDivs();
+ // set row heights, calculate event tops (in relation to row top)
+ for (rowI=0; rowI<rowCnt; rowI++) {
+ levelI = 0;
+ colHeights = [];
+ for (j=0; j<colCnt; j++) {
+ colHeights[j] = 0;
+ }
+ while (i<segCnt && (seg = segs[i]).row == rowI) {
+ // loop through segs in a row
+ top = arrayMax(colHeights.slice(seg.startCol, seg.endCol));
+ seg.top = top;
+ top += seg.outerHeight;
+ for (k=seg.startCol; k<seg.endCol; k++) {
+ colHeights[k] = top;
+ }
+ i++;
+ }
+ rowDivs[rowI].height(arrayMax(colHeights));
+ }
+ daySegSetTops(segs, getRowTops(rowDivs));
+ }
+
+
+ function renderTempDaySegs(segs, adjustRow, adjustTop) {
+ var tempContainer = $("<div/>");
+ var elements;
+ var segmentContainer = getDaySegmentContainer();
+ var i;
+ var segCnt = segs.length;
+ var element;
+ tempContainer[0].innerHTML = daySegHTML(segs); // faster than .html()
+ elements = tempContainer.children();
+ segmentContainer.append(elements);
+ daySegElementResolve(segs, elements);
+ daySegCalcHSides(segs);
+ daySegSetWidths(segs);
+ daySegCalcHeights(segs);
+ daySegSetTops(segs, getRowTops(getRowDivs()));
+ elements = [];
+ for (i=0; i<segCnt; i++) {
+ element = segs[i].element;
+ if (element) {
+ if (segs[i].row === adjustRow) {
+ element.css('top', adjustTop);
+ }
+ elements.push(element[0]);
+ }
+ }
+ return $(elements);
+ }
+
+
+ function daySegHTML(segs) { // also sets seg.left and seg.outerWidth
+ var rtl = opt('isRTL');
+ var i;
+ var segCnt=segs.length;
+ var seg;
+ var event;
+ var url;
+ var classes;
+ var bounds = allDayBounds();
+ var minLeft = bounds.left;
+ var maxLeft = bounds.right;
+ var leftCol;
+ var rightCol;
+ var left;
+ var right;
+ var skinCss;
+ var html = '';
+ // calculate desired position/dimensions, create html
+ for (i=0; i<segCnt; i++) {
+ seg = segs[i];
+ event = seg.event;
+ classes = ['fc-event', 'fc-event-skin', 'fc-event-hori'];
+ if (isEventDraggable(event)) {
+ classes.push('fc-event-draggable');
+ }
+ if (rtl) {
+ if (seg.isStart) {
+ classes.push('fc-corner-right');
+ }
+ if (seg.isEnd) {
+ classes.push('fc-corner-left');
+ }
+ leftCol = dayOfWeekCol(seg.end.getDay()-1);
+ rightCol = dayOfWeekCol(seg.start.getDay());
+ left = seg.isEnd ? colContentLeft(leftCol) : minLeft;
+ right = seg.isStart ? colContentRight(rightCol) : maxLeft;
+ }else{
+ if (seg.isStart) {
+ classes.push('fc-corner-left');
+ }
+ if (seg.isEnd) {
+ classes.push('fc-corner-right');
+ }
+ leftCol = dayOfWeekCol(seg.start.getDay());
+ rightCol = dayOfWeekCol(seg.end.getDay()-1);
+ left = seg.isStart ? colContentLeft(leftCol) : minLeft;
+ right = seg.isEnd ? colContentRight(rightCol) : maxLeft;
+ }
+ classes = classes.concat(event.className);
+ if (event.source) {
+ classes = classes.concat(event.source.className || []);
+ }
+ url = event.url;
+ skinCss = getSkinCss(event, opt);
+ if (url) {
+ html += "<a href='" + htmlEscape(url) + "'";
+ }else{
+ html += "<div";
+ }
+ html +=
+ " class='" + classes.join(' ') + "'" +
+ " style='position:absolute;z-index:8;left:"+left+"px;" + skinCss + "'" +
+ ">" +
+ "<div" +
+ " class='fc-event-inner fc-event-skin'" +
+ (skinCss ? " style='" + skinCss + "'" : '') +
+ ">";
+ if (!event.allDay && seg.isStart) {
+ html +=
+ "<span class='fc-event-time'>" +
+ htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +
+ "</span>";
+ }
+ html +=
+ "<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
+ "</div>";
+ if (seg.isEnd && isEventResizable(event)) {
+ html +=
+ "<div class='ui-resizable-handle ui-resizable-" + (rtl ? 'w' : 'e') + "'>" +
+ "&nbsp;&nbsp;&nbsp;" + // makes hit area a lot better for IE6/7
+ "</div>";
+ }
+ html +=
+ "</" + (url ? "a" : "div" ) + ">";
+ seg.left = left;
+ seg.outerWidth = right - left;
+ seg.startCol = leftCol;
+ seg.endCol = rightCol + 1; // needs to be exclusive
+ }
+ return html;
+ }
+
+
+ function daySegElementResolve(segs, elements) { // sets seg.element
+ var i;
+ var segCnt = segs.length;
+ var seg;
+ var event;
+ var element;
+ var triggerRes;
+ for (i=0; i<segCnt; i++) {
+ seg = segs[i];
+ event = seg.event;
+ element = $(elements[i]); // faster than .eq()
+ triggerRes = trigger('eventRender', event, event, element);
+ if (triggerRes === false) {
+ element.remove();
+ }else{
+ if (triggerRes && triggerRes !== true) {
+ triggerRes = $(triggerRes)
+ .css({
+ position: 'absolute',
+ left: seg.left
+ });
+ element.replaceWith(triggerRes);
+ element = triggerRes;
+ }
+ seg.element = element;
+ }
+ }
+ }
+
+
+ function daySegElementReport(segs) {
+ var i;
+ var segCnt = segs.length;
+ var seg;
+ var element;
+ for (i=0; i<segCnt; i++) {
+ seg = segs[i];
+ element = seg.element;
+ if (element) {
+ reportEventElement(seg.event, element);
+ }
+ }
+ }
+
+
+ function daySegHandlers(segs, segmentContainer, modifiedEventId) {
+ var i;
+ var segCnt = segs.length;
+ var seg;
+ var element;
+ var event;
+ // retrieve elements, run through eventRender callback, bind handlers
+ for (i=0; i<segCnt; i++) {
+ seg = segs[i];
+ element = seg.element;
+ if (element) {
+ event = seg.event;
+ if (event._id === modifiedEventId) {
+ bindDaySeg(event, element, seg);
+ }else{
+ element[0]._fci = i; // for lazySegBind
+ }
+ }
+ }
+ lazySegBind(segmentContainer, segs, bindDaySeg);
+ }
+
+
+ function daySegCalcHSides(segs) { // also sets seg.key
+ var i;
+ var segCnt = segs.length;
+ var seg;
+ var element;
+ var key, val;
+ var hsideCache = {};
+ // record event horizontal sides
+ for (i=0; i<segCnt; i++) {
+ seg = segs[i];
+ element = seg.element;
+ if (element) {
+ key = seg.key = cssKey(element[0]);
+ val = hsideCache[key];
+ if (val === undefined) {
+ val = hsideCache[key] = hsides(element, true);
+ }
+ seg.hsides = val;
+ }
+ }
+ }
+
+
+ function daySegSetWidths(segs) {
+ var i;
+ var segCnt = segs.length;
+ var seg;
+ var element;
+ for (i=0; i<segCnt; i++) {
+ seg = segs[i];
+ element = seg.element;
+ if (element) {
+ element[0].style.width = Math.max(0, seg.outerWidth - seg.hsides) + 'px';
+ }
+ }
+ }
+
+
+ function daySegCalcHeights(segs) {
+ var i;
+ var segCnt = segs.length;
+ var seg;
+ var element;
+ var key, val;
+ var vmarginCache = {};
+ // record event heights
+ for (i=0; i<segCnt; i++) {
+ seg = segs[i];
+ element = seg.element;
+ if (element) {
+ key = seg.key; // created in daySegCalcHSides
+ val = vmarginCache[key];
+ if (val === undefined) {
+ val = vmarginCache[key] = vmargins(element);
+ }
+ seg.outerHeight = element[0].offsetHeight + val;
+ }
+ }
+ }
+
+
+ function getRowDivs() {
+ var i;
+ var rowCnt = getRowCnt();
+ var rowDivs = [];
+ for (i=0; i<rowCnt; i++) {
+ rowDivs[i] = allDayRow(i)
+ .find('td:first div.fc-day-content > div'); // optimal selector?
+ }
+ return rowDivs;
+ }
+
+
+ function getRowTops(rowDivs) {
+ var i;
+ var rowCnt = rowDivs.length;
+ var tops = [];
+ for (i=0; i<rowCnt; i++) {
+ tops[i] = rowDivs[i][0].offsetTop; // !!?? but this means the element needs position:relative if in a table cell!!!!
+ }
+ return tops;
+ }
+
+
+ function daySegSetTops(segs, rowTops) { // also triggers eventAfterRender
+ var i;
+ var segCnt = segs.length;
+ var seg;
+ var element;
+ var event;
+ for (i=0; i<segCnt; i++) {
+ seg = segs[i];
+ element = seg.element;
+ if (element) {
+ element[0].style.top = rowTops[seg.row] + (seg.top||0) + 'px';
+ event = seg.event;
+ trigger('eventAfterRender', event, event, element);
+ }
+ }
+ }
+
+
+
+ /* Resizing
+ -----------------------------------------------------------------------------------*/
+
+
+ function resizableDayEvent(event, element, seg) {
+ var rtl = opt('isRTL');
+ var direction = rtl ? 'w' : 'e';
+ var handle = element.find('div.ui-resizable-' + direction);
+ var isResizing = false;
+
+ // TODO: look into using jquery-ui mouse widget for this stuff
+ disableTextSelection(element); // prevent native <a> selection for IE
+ element
+ .mousedown(function(ev) { // prevent native <a> selection for others
+ ev.preventDefault();
+ })
+ .click(function(ev) {
+ if (isResizing) {
+ ev.preventDefault(); // prevent link from being visited (only method that worked in IE6)
+ ev.stopImmediatePropagation(); // prevent fullcalendar eventClick handler from being called
+ // (eventElementHandlers needs to be bound after resizableDayEvent)
+ }
+ });
+
+ handle.mousedown(function(ev) {
+ if (ev.which != 1) {
+ return; // needs to be left mouse button
+ }
+ isResizing = true;
+ var hoverListener = t.getHoverListener();
+ var rowCnt = getRowCnt();
+ var colCnt = getColCnt();
+ var dis = rtl ? -1 : 1;
+ var dit = rtl ? colCnt-1 : 0;
+ var elementTop = element.css('top');
+ var dayDelta;
+ var helpers;
+ var eventCopy = $.extend({}, event);
+ var minCell = dateCell(event.start);
+ clearSelection();
+ $('body')
+ .css('cursor', direction + '-resize')
+ .one('mouseup', mouseup);
+ trigger('eventResizeStart', this, event, ev);
+ hoverListener.start(function(cell, origCell) {
+ if (cell) {
+ var r = Math.max(minCell.row, cell.row);
+ var c = cell.col;
+ if (rowCnt == 1) {
+ r = 0; // hack for all-day area in agenda views
+ }
+ if (r == minCell.row) {
+ if (rtl) {
+ c = Math.min(minCell.col, c);
+ }else{
+ c = Math.max(minCell.col, c);
+ }
+ }
+ dayDelta = (r*7 + c*dis+dit) - (origCell.row*7 + origCell.col*dis+dit);
+ var newEnd = addDays(eventEnd(event), dayDelta, true);
+ if (dayDelta) {
+ eventCopy.end = newEnd;
+ var oldHelpers = helpers;
+ helpers = renderTempDaySegs(compileDaySegs([eventCopy]), seg.row, elementTop);
+ helpers.find('*').css('cursor', direction + '-resize');
+ if (oldHelpers) {
+ oldHelpers.remove();
+ }
+ hideEvents(event);
+ }else{
+ if (helpers) {
+ showEvents(event);
+ helpers.remove();
+ helpers = null;
+ }
+ }
+ clearOverlays();
+ renderDayOverlay(event.start, addDays(cloneDate(newEnd), 1)); // coordinate grid already rebuild at hoverListener.start
+ }
+ }, ev);
+
+ function mouseup(ev) {
+ trigger('eventResizeStop', this, event, ev);
+ $('body').css('cursor', '');
+ hoverListener.stop();
+ clearOverlays();
+ if (dayDelta) {
+ eventResize(this, event, dayDelta, 0, ev);
+ // event redraw will clear helpers
+ }
+ // otherwise, the drag handler already restored the old events
+
+ setTimeout(function() { // make this happen after the element's click event
+ isResizing = false;
+ },0);
+ }
+
+ });
+ }
+
+
+}
+
+//BUG: unselect needs to be triggered when events are dragged+dropped
+
+function SelectionManager() {
+ var t = this;
+
+
+ // exports
+ t.select = select;
+ t.unselect = unselect;
+ t.reportSelection = reportSelection;
+ t.daySelectionMousedown = daySelectionMousedown;
+
+
+ // imports
+ var opt = t.opt;
+ var trigger = t.trigger;
+ var defaultSelectionEnd = t.defaultSelectionEnd;
+ var renderSelection = t.renderSelection;
+ var clearSelection = t.clearSelection;
+
+
+ // locals
+ var selected = false;
+
+
+
+ // unselectAuto
+ if (opt('selectable') && opt('unselectAuto')) {
+ $(document).mousedown(function(ev) {
+ var ignore = opt('unselectCancel');
+ if (ignore) {
+ if ($(ev.target).parents(ignore).length) { // could be optimized to stop after first match
+ return;
+ }
+ }
+ unselect(ev);
+ });
+ }
+
+
+ function select(startDate, endDate, allDay) {
+ unselect();
+ if (!endDate) {
+ endDate = defaultSelectionEnd(startDate, allDay);
+ }
+ renderSelection(startDate, endDate, allDay);
+ reportSelection(startDate, endDate, allDay);
+ }
+
+
+ function unselect(ev) {
+ if (selected) {
+ selected = false;
+ clearSelection();
+ trigger('unselect', null, ev);
+ }
+ }
+
+
+ function reportSelection(startDate, endDate, allDay, ev) {
+ selected = true;
+ trigger('select', null, startDate, endDate, allDay, ev);
+ }
+
+
+ function daySelectionMousedown(ev) { // not really a generic manager method, oh well
+ var cellDate = t.cellDate;
+ var cellIsAllDay = t.cellIsAllDay;
+ var hoverListener = t.getHoverListener();
+ var reportDayClick = t.reportDayClick; // this is hacky and sort of weird
+ if (ev.which == 1 && opt('selectable')) { // which==1 means left mouse button
+ unselect(ev);
+ var _mousedownElement = this;
+ var dates;
+ hoverListener.start(function(cell, origCell) { // TODO: maybe put cellDate/cellIsAllDay info in cell
+ clearSelection();
+ if (cell && cellIsAllDay(cell)) {
+ dates = [ cellDate(origCell), cellDate(cell) ].sort(cmp);
+ renderSelection(dates[0], dates[1], true);
+ }else{
+ dates = null;
+ }
+ }, ev);
+ $(document).one('mouseup', function(ev) {
+ hoverListener.stop();
+ if (dates) {
+ if (+dates[0] == +dates[1]) {
+ reportDayClick(dates[0], true, ev);
+ }
+ reportSelection(dates[0], dates[1], true, ev);
+ }
+ });
+ }
+ }
+
+
+}
+
+function OverlayManager() {
+ var t = this;
+
+
+ // exports
+ t.renderOverlay = renderOverlay;
+ t.clearOverlays = clearOverlays;
+
+
+ // locals
+ var usedOverlays = [];
+ var unusedOverlays = [];
+
+
+ function renderOverlay(rect, parent) {
+ var e = unusedOverlays.shift();
+ if (!e) {
+ e = $("<div class='fc-cell-overlay' style='position:absolute;z-index:3'/>");
+ }
+ if (e[0].parentNode != parent[0]) {
+ e.appendTo(parent);
+ }
+ usedOverlays.push(e.css(rect).show());
+ return e;
+ }
+
+
+ function clearOverlays() {
+ var e;
+ while (e = usedOverlays.shift()) {
+ unusedOverlays.push(e.hide().unbind());
+ }
+ }
+
+
+}
+
+function CoordinateGrid(buildFunc) {
+
+ var t = this;
+ var rows;
+ var cols;
+
+
+ t.build = function() {
+ rows = [];
+ cols = [];
+ buildFunc(rows, cols);
+ };
+
+
+ t.cell = function(x, y) {
+ var rowCnt = rows.length;
+ var colCnt = cols.length;
+ var i, r=-1, c=-1;
+ for (i=0; i<rowCnt; i++) {
+ if (y >= rows[i][0] && y < rows[i][1]) {
+ r = i;
+ break;
+ }
+ }
+ for (i=0; i<colCnt; i++) {
+ if (x >= cols[i][0] && x < cols[i][1]) {
+ c = i;
+ break;
+ }
+ }
+ return (r>=0 && c>=0) ? { row:r, col:c } : null;
+ };
+
+
+ t.rect = function(row0, col0, row1, col1, originElement) { // row1,col1 is inclusive
+ var origin = originElement.offset();
+ return {
+ top: rows[row0][0] - origin.top,
+ left: cols[col0][0] - origin.left,
+ width: cols[col1][1] - cols[col0][0],
+ height: rows[row1][1] - rows[row0][0]
+ };
+ };
+
+}
+
+function HoverListener(coordinateGrid) {
+
+
+ var t = this;
+ var bindType;
+ var change;
+ var firstCell;
+ var cell;
+
+
+ t.start = function(_change, ev, _bindType) {
+ change = _change;
+ firstCell = cell = null;
+ coordinateGrid.build();
+ mouse(ev);
+ bindType = _bindType || 'mousemove';
+ $(document).bind(bindType, mouse);
+ };
+
+
+ function mouse(ev) {
+ _fixUIEvent(ev); // see below
+ var newCell = coordinateGrid.cell(ev.pageX, ev.pageY);
+ if (!newCell != !cell || newCell && (newCell.row != cell.row || newCell.col != cell.col)) {
+ if (newCell) {
+ if (!firstCell) {
+ firstCell = newCell;
+ }
+ change(newCell, firstCell, newCell.row-firstCell.row, newCell.col-firstCell.col);
+ }else{
+ change(newCell, firstCell);
+ }
+ cell = newCell;
+ }
+ }
+
+
+ t.stop = function() {
+ $(document).unbind(bindType, mouse);
+ return cell;
+ };
+
+
+}
+
+
+
+// this fix was only necessary for jQuery UI 1.8.16 (and jQuery 1.7 or 1.7.1)
+// upgrading to jQuery UI 1.8.17 (and using either jQuery 1.7 or 1.7.1) fixed the problem
+// but keep this in here for 1.8.16 users
+// and maybe remove it down the line
+
+function _fixUIEvent(event) { // for issue 1168
+ if (event.pageX === undefined) {
+ event.pageX = event.originalEvent.pageX;
+ event.pageY = event.originalEvent.pageY;
+ }
+}
+function HorizontalPositionCache(getElement) {
+
+ var t = this,
+ elements = {},
+ lefts = {},
+ rights = {};
+
+ function e(i) {
+ return elements[i] = elements[i] || getElement(i);
+ }
+
+ t.left = function(i) {
+ return lefts[i] = lefts[i] === undefined ? e(i).position().left : lefts[i];
+ };
+
+ t.right = function(i) {
+ return rights[i] = rights[i] === undefined ? t.left(i) + e(i).width() : rights[i];
+ };
+
+ t.clear = function() {
+ elements = {};
+ lefts = {};
+ rights = {};
+ };
+
+}
+
+})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.min.js b/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.min.js
new file mode 100644
index 00000000..da6c7c09
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.min.js
@@ -0,0 +1,114 @@
+/*
+
+ FullCalendar v1.5.4
+ http://arshaw.com/fullcalendar/
+
+ Use fullcalendar.css for basic styling.
+ For event drag & drop, requires jQuery UI draggable.
+ For event resizing, requires jQuery UI resizable.
+
+ Copyright (c) 2011 Adam Shaw
+ Dual licensed under the MIT and GPL licenses, located in
+ MIT-LICENSE.txt and GPL-LICENSE.txt respectively.
+
+ Date: Tue Sep 4 23:38:33 2012 -0700
+
+*/
+(function(m,ma){function wb(a){m.extend(true,Ya,a)}function Yb(a,b,e){function d(k){if(E){u();q();na();S(k)}else f()}function f(){B=b.theme?"ui":"fc";a.addClass("fc");b.isRTL&&a.addClass("fc-rtl");b.theme&&a.addClass("ui-widget");E=m("<div class='fc-content' style='position:relative'/>").prependTo(a);C=new Zb(X,b);(P=C.render())&&a.prepend(P);y(b.defaultView);m(window).resize(oa);t()||g()}function g(){setTimeout(function(){!n.start&&t()&&S()},0)}function l(){m(window).unbind("resize",oa);C.destroy();
+E.remove();a.removeClass("fc fc-rtl ui-widget")}function j(){return i.offsetWidth!==0}function t(){return m("body")[0].offsetWidth!==0}function y(k){if(!n||k!=n.name){F++;pa();var D=n,Z;if(D){(D.beforeHide||xb)();Za(E,E.height());D.element.hide()}else Za(E,1);E.css("overflow","hidden");if(n=Y[k])n.element.show();else n=Y[k]=new Ja[k](Z=s=m("<div class='fc-view fc-view-"+k+"' style='position:absolute'/>").appendTo(E),X);D&&C.deactivateButton(D.name);C.activateButton(k);S();E.css("overflow","");D&&
+Za(E,1);Z||(n.afterShow||xb)();F--}}function S(k){if(j()){F++;pa();o===ma&&u();var D=false;if(!n.start||k||r<n.start||r>=n.end){n.render(r,k||0);fa(true);D=true}else if(n.sizeDirty){n.clearEvents();fa();D=true}else if(n.eventsDirty){n.clearEvents();D=true}n.sizeDirty=false;n.eventsDirty=false;ga(D);W=a.outerWidth();C.updateTitle(n.title);k=new Date;k>=n.start&&k<n.end?C.disableButton("today"):C.enableButton("today");F--;n.trigger("viewDisplay",i)}}function Q(){q();if(j()){u();fa();pa();n.clearEvents();
+n.renderEvents(J);n.sizeDirty=false}}function q(){m.each(Y,function(k,D){D.sizeDirty=true})}function u(){o=b.contentHeight?b.contentHeight:b.height?b.height-(P?P.height():0)-Sa(E):Math.round(E.width()/Math.max(b.aspectRatio,0.5))}function fa(k){F++;n.setHeight(o,k);if(s){s.css("position","relative");s=null}n.setWidth(E.width(),k);F--}function oa(){if(!F)if(n.start){var k=++v;setTimeout(function(){if(k==v&&!F&&j())if(W!=(W=a.outerWidth())){F++;Q();n.trigger("windowResize",i);F--}},200)}else g()}function ga(k){if(!b.lazyFetching||
+ya(n.visStart,n.visEnd))ra();else k&&da()}function ra(){K(n.visStart,n.visEnd)}function sa(k){J=k;da()}function ha(k){da(k)}function da(k){na();if(j()){n.clearEvents();n.renderEvents(J,k);n.eventsDirty=false}}function na(){m.each(Y,function(k,D){D.eventsDirty=true})}function ua(k,D,Z){n.select(k,D,Z===ma?true:Z)}function pa(){n&&n.unselect()}function U(){S(-1)}function ca(){S(1)}function ka(){gb(r,-1);S()}function qa(){gb(r,1);S()}function G(){r=new Date;S()}function p(k,D,Z){if(k instanceof Date)r=
+N(k);else yb(r,k,D,Z);S()}function L(k,D,Z){k!==ma&&gb(r,k);D!==ma&&hb(r,D);Z!==ma&&ba(r,Z);S()}function c(){return N(r)}function z(){return n}function H(k,D){if(D===ma)return b[k];if(k=="height"||k=="contentHeight"||k=="aspectRatio"){b[k]=D;Q()}}function T(k,D){if(b[k])return b[k].apply(D||i,Array.prototype.slice.call(arguments,2))}var X=this;X.options=b;X.render=d;X.destroy=l;X.refetchEvents=ra;X.reportEvents=sa;X.reportEventChange=ha;X.rerenderEvents=da;X.changeView=y;X.select=ua;X.unselect=pa;
+X.prev=U;X.next=ca;X.prevYear=ka;X.nextYear=qa;X.today=G;X.gotoDate=p;X.incrementDate=L;X.formatDate=function(k,D){return Oa(k,D,b)};X.formatDates=function(k,D,Z){return ib(k,D,Z,b)};X.getDate=c;X.getView=z;X.option=H;X.trigger=T;$b.call(X,b,e);var ya=X.isFetchNeeded,K=X.fetchEvents,i=a[0],C,P,E,B,n,Y={},W,o,s,v=0,F=0,r=new Date,J=[],M;yb(r,b.year,b.month,b.date);b.droppable&&m(document).bind("dragstart",function(k,D){var Z=k.target,ja=m(Z);if(!ja.parents(".fc").length){var ia=b.dropAccept;if(m.isFunction(ia)?
+ia.call(Z,ja):ja.is(ia)){M=Z;n.dragStart(M,k,D)}}}).bind("dragstop",function(k,D){if(M){n.dragStop(M,k,D);M=null}})}function Zb(a,b){function e(){q=b.theme?"ui":"fc";if(b.header)return Q=m("<table class='fc-header' style='width:100%'/>").append(m("<tr/>").append(f("left")).append(f("center")).append(f("right")))}function d(){Q.remove()}function f(u){var fa=m("<td class='fc-header-"+u+"'/>");(u=b.header[u])&&m.each(u.split(" "),function(oa){oa>0&&fa.append("<span class='fc-header-space'/>");var ga;
+m.each(this.split(","),function(ra,sa){if(sa=="title"){fa.append("<span class='fc-header-title'><h2>&nbsp;</h2></span>");ga&&ga.addClass(q+"-corner-right");ga=null}else{var ha;if(a[sa])ha=a[sa];else if(Ja[sa])ha=function(){na.removeClass(q+"-state-hover");a.changeView(sa)};if(ha){ra=b.theme?jb(b.buttonIcons,sa):null;var da=jb(b.buttonText,sa),na=m("<span class='fc-button fc-button-"+sa+" "+q+"-state-default'><span class='fc-button-inner'><span class='fc-button-content'>"+(ra?"<span class='fc-icon-wrap'><span class='ui-icon ui-icon-"+
+ra+"'/></span>":da)+"</span><span class='fc-button-effect'><span></span></span></span></span>");if(na){na.click(function(){na.hasClass(q+"-state-disabled")||ha()}).mousedown(function(){na.not("."+q+"-state-active").not("."+q+"-state-disabled").addClass(q+"-state-down")}).mouseup(function(){na.removeClass(q+"-state-down")}).hover(function(){na.not("."+q+"-state-active").not("."+q+"-state-disabled").addClass(q+"-state-hover")},function(){na.removeClass(q+"-state-hover").removeClass(q+"-state-down")}).appendTo(fa);
+ga||na.addClass(q+"-corner-left");ga=na}}}});ga&&ga.addClass(q+"-corner-right")});return fa}function g(u){Q.find("h2").html(u)}function l(u){Q.find("span.fc-button-"+u).addClass(q+"-state-active")}function j(u){Q.find("span.fc-button-"+u).removeClass(q+"-state-active")}function t(u){Q.find("span.fc-button-"+u).addClass(q+"-state-disabled")}function y(u){Q.find("span.fc-button-"+u).removeClass(q+"-state-disabled")}var S=this;S.render=e;S.destroy=d;S.updateTitle=g;S.activateButton=l;S.deactivateButton=
+j;S.disableButton=t;S.enableButton=y;var Q=m([]),q}function $b(a,b){function e(c,z){return!ca||c<ca||z>ka}function d(c,z){ca=c;ka=z;L=[];c=++qa;G=z=U.length;for(var H=0;H<z;H++)f(U[H],c)}function f(c,z){g(c,function(H){if(z==qa){if(H){for(var T=0;T<H.length;T++){H[T].source=c;oa(H[T])}L=L.concat(H)}G--;G||ua(L)}})}function g(c,z){var H,T=Aa.sourceFetchers,X;for(H=0;H<T.length;H++){X=T[H](c,ca,ka,z);if(X===true)return;else if(typeof X=="object"){g(X,z);return}}if(H=c.events)if(m.isFunction(H)){u();
+H(N(ca),N(ka),function(C){z(C);fa()})}else m.isArray(H)?z(H):z();else if(c.url){var ya=c.success,K=c.error,i=c.complete;H=m.extend({},c.data||{});T=Ta(c.startParam,a.startParam);X=Ta(c.endParam,a.endParam);if(T)H[T]=Math.round(+ca/1E3);if(X)H[X]=Math.round(+ka/1E3);u();m.ajax(m.extend({},ac,c,{data:H,success:function(C){C=C||[];var P=$a(ya,this,arguments);if(m.isArray(P))C=P;z(C)},error:function(){$a(K,this,arguments);z()},complete:function(){$a(i,this,arguments);fa()}}))}else z()}function l(c){if(c=
+j(c)){G++;f(c,qa)}}function j(c){if(m.isFunction(c)||m.isArray(c))c={events:c};else if(typeof c=="string")c={url:c};if(typeof c=="object"){ga(c);U.push(c);return c}}function t(c){U=m.grep(U,function(z){return!ra(z,c)});L=m.grep(L,function(z){return!ra(z.source,c)});ua(L)}function y(c){var z,H=L.length,T,X=na().defaultEventEnd,ya=c.start-c._start,K=c.end?c.end-(c._end||X(c)):0;for(z=0;z<H;z++){T=L[z];if(T._id==c._id&&T!=c){T.start=new Date(+T.start+ya);T.end=c.end?T.end?new Date(+T.end+K):new Date(+X(T)+
+K):null;T.title=c.title;T.url=c.url;T.allDay=c.allDay;T.className=c.className;T.editable=c.editable;T.color=c.color;T.backgroudColor=c.backgroudColor;T.borderColor=c.borderColor;T.textColor=c.textColor;oa(T)}}oa(c);ua(L)}function S(c,z){oa(c);if(!c.source){if(z){pa.events.push(c);c.source=pa}L.push(c)}ua(L)}function Q(c){if(c){if(!m.isFunction(c)){var z=c+"";c=function(T){return T._id==z}}L=m.grep(L,c,true);for(H=0;H<U.length;H++)if(m.isArray(U[H].events))U[H].events=m.grep(U[H].events,c,true)}else{L=
+[];for(var H=0;H<U.length;H++)if(m.isArray(U[H].events))U[H].events=[]}ua(L)}function q(c){if(m.isFunction(c))return m.grep(L,c);else if(c){c+="";return m.grep(L,function(z){return z._id==c})}return L}function u(){p++||da("loading",null,true)}function fa(){--p||da("loading",null,false)}function oa(c){var z=c.source||{},H=Ta(z.ignoreTimezone,a.ignoreTimezone);c._id=c._id||(c.id===ma?"_fc"+bc++:c.id+"");if(c.date){if(!c.start)c.start=c.date;delete c.date}c._start=N(c.start=kb(c.start,H));c.end=kb(c.end,
+H);if(c.end&&c.end<=c.start)c.end=null;c._end=c.end?N(c.end):null;if(c.allDay===ma)c.allDay=Ta(z.allDayDefault,a.allDayDefault);if(c.className){if(typeof c.className=="string")c.className=c.className.split(/\s+/)}else c.className=[]}function ga(c){if(c.className){if(typeof c.className=="string")c.className=c.className.split(/\s+/)}else c.className=[];for(var z=Aa.sourceNormalizers,H=0;H<z.length;H++)z[H](c)}function ra(c,z){return c&&z&&sa(c)==sa(z)}function sa(c){return(typeof c=="object"?c.events||
+c.url:"")||c}var ha=this;ha.isFetchNeeded=e;ha.fetchEvents=d;ha.addEventSource=l;ha.removeEventSource=t;ha.updateEvent=y;ha.renderEvent=S;ha.removeEvents=Q;ha.clientEvents=q;ha.normalizeEvent=oa;var da=ha.trigger,na=ha.getView,ua=ha.reportEvents,pa={events:[]},U=[pa],ca,ka,qa=0,G=0,p=0,L=[];for(ha=0;ha<b.length;ha++)j(b[ha])}function gb(a,b,e){a.setFullYear(a.getFullYear()+b);e||Ka(a);return a}function hb(a,b,e){if(+a){b=a.getMonth()+b;var d=N(a);d.setDate(1);d.setMonth(b);a.setMonth(b);for(e||Ka(a);a.getMonth()!=
+d.getMonth();)a.setDate(a.getDate()+(a<d?1:-1))}return a}function ba(a,b,e){if(+a){b=a.getDate()+b;var d=N(a);d.setHours(9);d.setDate(b);a.setDate(b);e||Ka(a);lb(a,d)}return a}function lb(a,b){if(+a)for(;a.getDate()!=b.getDate();)a.setTime(+a+(a<b?1:-1)*cc)}function xa(a,b){a.setMinutes(a.getMinutes()+b);return a}function Ka(a){a.setHours(0);a.setMinutes(0);a.setSeconds(0);a.setMilliseconds(0);return a}function N(a,b){if(b)return Ka(new Date(+a));return new Date(+a)}function zb(){var a=0,b;do b=new Date(1970,
+a++,1);while(b.getHours());return b}function Fa(a,b,e){for(b=b||1;!a.getDay()||e&&a.getDay()==1||!e&&a.getDay()==6;)ba(a,b);return a}function Ca(a,b){return Math.round((N(a,true)-N(b,true))/Ab)}function yb(a,b,e,d){if(b!==ma&&b!=a.getFullYear()){a.setDate(1);a.setMonth(0);a.setFullYear(b)}if(e!==ma&&e!=a.getMonth()){a.setDate(1);a.setMonth(e)}d!==ma&&a.setDate(d)}function kb(a,b){if(typeof a=="object")return a;if(typeof a=="number")return new Date(a*1E3);if(typeof a=="string"){if(a.match(/^\d+(\.\d+)?$/))return new Date(parseFloat(a)*
+1E3);if(b===ma)b=true;return Bb(a,b)||(a?new Date(a):null)}return null}function Bb(a,b){a=a.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/);if(!a)return null;var e=new Date(a[1],0,1);if(b||!a[13]){b=new Date(a[1],0,1,9,0);if(a[3]){e.setMonth(a[3]-1);b.setMonth(a[3]-1)}if(a[5]){e.setDate(a[5]);b.setDate(a[5])}lb(e,b);a[7]&&e.setHours(a[7]);a[8]&&e.setMinutes(a[8]);a[10]&&e.setSeconds(a[10]);a[12]&&e.setMilliseconds(Number("0."+
+a[12])*1E3);lb(e,b)}else{e.setUTCFullYear(a[1],a[3]?a[3]-1:0,a[5]||1);e.setUTCHours(a[7]||0,a[8]||0,a[10]||0,a[12]?Number("0."+a[12])*1E3:0);if(a[14]){b=Number(a[16])*60+(a[18]?Number(a[18]):0);b*=a[15]=="-"?1:-1;e=new Date(+e+b*60*1E3)}}return e}function mb(a){if(typeof a=="number")return a*60;if(typeof a=="object")return a.getHours()*60+a.getMinutes();if(a=a.match(/(\d+)(?::(\d+))?\s*(\w+)?/)){var b=parseInt(a[1],10);if(a[3]){b%=12;if(a[3].toLowerCase().charAt(0)=="p")b+=12}return b*60+(a[2]?parseInt(a[2],
+10):0)}}function Oa(a,b,e){return ib(a,null,b,e)}function ib(a,b,e,d){d=d||Ya;var f=a,g=b,l,j=e.length,t,y,S,Q="";for(l=0;l<j;l++){t=e.charAt(l);if(t=="'")for(y=l+1;y<j;y++){if(e.charAt(y)=="'"){if(f){Q+=y==l+1?"'":e.substring(l+1,y);l=y}break}}else if(t=="(")for(y=l+1;y<j;y++){if(e.charAt(y)==")"){l=Oa(f,e.substring(l+1,y),d);if(parseInt(l.replace(/\D/,""),10))Q+=l;l=y;break}}else if(t=="[")for(y=l+1;y<j;y++){if(e.charAt(y)=="]"){t=e.substring(l+1,y);l=Oa(f,t,d);if(l!=Oa(g,t,d))Q+=l;l=y;break}}else if(t==
+"{"){f=b;g=a}else if(t=="}"){f=a;g=b}else{for(y=j;y>l;y--)if(S=dc[e.substring(l,y)]){if(f)Q+=S(f,d);l=y-1;break}if(y==l)if(f)Q+=t}}return Q}function Ua(a){return a.end?ec(a.end,a.allDay):ba(N(a.start),1)}function ec(a,b){a=N(a);return b||a.getHours()||a.getMinutes()?ba(a,1):Ka(a)}function fc(a,b){return(b.msLength-a.msLength)*100+(a.event.start-b.event.start)}function Cb(a,b){return a.end>b.start&&a.start<b.end}function nb(a,b,e,d){var f=[],g,l=a.length,j,t,y,S,Q;for(g=0;g<l;g++){j=a[g];t=j.start;
+y=b[g];if(y>e&&t<d){if(t<e){t=N(e);S=false}else{t=t;S=true}if(y>d){y=N(d);Q=false}else{y=y;Q=true}f.push({event:j,start:t,end:y,isStart:S,isEnd:Q,msLength:y-t})}}return f.sort(fc)}function ob(a){var b=[],e,d=a.length,f,g,l,j;for(e=0;e<d;e++){f=a[e];for(g=0;;){l=false;if(b[g])for(j=0;j<b[g].length;j++)if(Cb(b[g][j],f)){l=true;break}if(l)g++;else break}if(b[g])b[g].push(f);else b[g]=[f]}return b}function Db(a,b,e){a.unbind("mouseover").mouseover(function(d){for(var f=d.target,g;f!=this;){g=f;f=f.parentNode}if((f=
+g._fci)!==ma){g._fci=ma;g=b[f];e(g.event,g.element,g);m(d.target).trigger(d)}d.stopPropagation()})}function Va(a,b,e){for(var d=0,f;d<a.length;d++){f=m(a[d]);f.width(Math.max(0,b-pb(f,e)))}}function Eb(a,b,e){for(var d=0,f;d<a.length;d++){f=m(a[d]);f.height(Math.max(0,b-Sa(f,e)))}}function pb(a,b){return gc(a)+hc(a)+(b?ic(a):0)}function gc(a){return(parseFloat(m.css(a[0],"paddingLeft",true))||0)+(parseFloat(m.css(a[0],"paddingRight",true))||0)}function ic(a){return(parseFloat(m.css(a[0],"marginLeft",
+true))||0)+(parseFloat(m.css(a[0],"marginRight",true))||0)}function hc(a){return(parseFloat(m.css(a[0],"borderLeftWidth",true))||0)+(parseFloat(m.css(a[0],"borderRightWidth",true))||0)}function Sa(a,b){return jc(a)+kc(a)+(b?Fb(a):0)}function jc(a){return(parseFloat(m.css(a[0],"paddingTop",true))||0)+(parseFloat(m.css(a[0],"paddingBottom",true))||0)}function Fb(a){return(parseFloat(m.css(a[0],"marginTop",true))||0)+(parseFloat(m.css(a[0],"marginBottom",true))||0)}function kc(a){return(parseFloat(m.css(a[0],
+"borderTopWidth",true))||0)+(parseFloat(m.css(a[0],"borderBottomWidth",true))||0)}function Za(a,b){b=typeof b=="number"?b+"px":b;a.each(function(e,d){d.style.cssText+=";min-height:"+b+";_height:"+b})}function xb(){}function Gb(a,b){return a-b}function Hb(a){return Math.max.apply(Math,a)}function Pa(a){return(a<10?"0":"")+a}function jb(a,b){if(a[b]!==ma)return a[b];b=b.split(/(?=[A-Z])/);for(var e=b.length-1,d;e>=0;e--){d=a[b[e].toLowerCase()];if(d!==ma)return d}return a[""]}function Qa(a){return a.replace(/&/g,
+"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#039;").replace(/"/g,"&quot;").replace(/\n/g,"<br />")}function Ib(a){return a.id+"/"+a.className+"/"+a.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig,"")}function qb(a){a.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})}function ab(a){a.children().removeClass("fc-first fc-last").filter(":first-child").addClass("fc-first").end().filter(":last-child").addClass("fc-last")}
+function rb(a,b){a.each(function(e,d){d.className=d.className.replace(/^fc-\w*/,"fc-"+lc[b.getDay()])})}function Jb(a,b){var e=a.source||{},d=a.color,f=e.color,g=b("eventColor"),l=a.backgroundColor||d||e.backgroundColor||f||b("eventBackgroundColor")||g;d=a.borderColor||d||e.borderColor||f||b("eventBorderColor")||g;a=a.textColor||e.textColor||b("eventTextColor");b=[];l&&b.push("background-color:"+l);d&&b.push("border-color:"+d);a&&b.push("color:"+a);return b.join(";")}function $a(a,b,e){if(m.isFunction(a))a=
+[a];if(a){var d,f;for(d=0;d<a.length;d++)f=a[d].apply(b,e)||f;return f}}function Ta(){for(var a=0;a<arguments.length;a++)if(arguments[a]!==ma)return arguments[a]}function mc(a,b){function e(j,t){if(t){hb(j,t);j.setDate(1)}j=N(j,true);j.setDate(1);t=hb(N(j),1);var y=N(j),S=N(t),Q=f("firstDay"),q=f("weekends")?0:1;if(q){Fa(y);Fa(S,-1,true)}ba(y,-((y.getDay()-Math.max(Q,q)+7)%7));ba(S,(7-S.getDay()+Math.max(Q,q))%7);Q=Math.round((S-y)/(Ab*7));if(f("weekMode")=="fixed"){ba(S,(6-Q)*7);Q=6}d.title=l(j,
+f("titleFormat"));d.start=j;d.end=t;d.visStart=y;d.visEnd=S;g(6,Q,q?5:7,true)}var d=this;d.render=e;sb.call(d,a,b,"month");var f=d.opt,g=d.renderBasic,l=b.formatDate}function nc(a,b){function e(j,t){t&&ba(j,t*7);j=ba(N(j),-((j.getDay()-f("firstDay")+7)%7));t=ba(N(j),7);var y=N(j),S=N(t),Q=f("weekends");if(!Q){Fa(y);Fa(S,-1,true)}d.title=l(y,ba(N(S),-1),f("titleFormat"));d.start=j;d.end=t;d.visStart=y;d.visEnd=S;g(1,1,Q?7:5,false)}var d=this;d.render=e;sb.call(d,a,b,"basicWeek");var f=d.opt,g=d.renderBasic,
+l=b.formatDates}function oc(a,b){function e(j,t){if(t){ba(j,t);f("weekends")||Fa(j,t<0?-1:1)}d.title=l(j,f("titleFormat"));d.start=d.visStart=N(j,true);d.end=d.visEnd=ba(N(d.start),1);g(1,1,1,false)}var d=this;d.render=e;sb.call(d,a,b,"basicDay");var f=d.opt,g=d.renderBasic,l=b.formatDate}function sb(a,b,e){function d(w,I,R,V){v=I;F=R;f();(I=!C)?g(w,V):z();l(I)}function f(){if(k=L("isRTL")){D=-1;Z=F-1}else{D=1;Z=0}ja=L("firstDay");ia=L("weekends")?0:1;la=L("theme")?"ui":"fc";$=L("columnFormat")}function g(w,
+I){var R,V=la+"-widget-header",ea=la+"-widget-content",aa;R="<table class='fc-border-separate' style='width:100%' cellspacing='0'><thead><tr>";for(aa=0;aa<F;aa++)R+="<th class='fc- "+V+"'/>";R+="</tr></thead><tbody>";for(aa=0;aa<w;aa++){R+="<tr class='fc-week"+aa+"'>";for(V=0;V<F;V++)R+="<td class='fc- "+ea+" fc-day"+(aa*F+V)+"'><div>"+(I?"<div class='fc-day-number'/>":"")+"<div class='fc-day-content'><div style='position:relative'>&nbsp;</div></div></div></td>";R+="</tr>"}R+="</tbody></table>";w=
+m(R).appendTo(a);K=w.find("thead");i=K.find("th");C=w.find("tbody");P=C.find("tr");E=C.find("td");B=E.filter(":first-child");n=P.eq(0).find("div.fc-day-content div");ab(K.add(K.find("tr")));ab(P);P.eq(0).addClass("fc-first");y(E);Y=m("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(a)}function l(w){var I=w||v==1,R=p.start.getMonth(),V=Ka(new Date),ea,aa,va;I&&i.each(function(wa,Ga){ea=m(Ga);aa=ca(wa);ea.html(ya(aa,$));rb(ea,aa)});E.each(function(wa,Ga){ea=m(Ga);aa=ca(wa);aa.getMonth()==
+R?ea.removeClass("fc-other-month"):ea.addClass("fc-other-month");+aa==+V?ea.addClass(la+"-state-highlight fc-today"):ea.removeClass(la+"-state-highlight fc-today");ea.find("div.fc-day-number").text(aa.getDate());I&&rb(ea,aa)});P.each(function(wa,Ga){va=m(Ga);if(wa<v){va.show();wa==v-1?va.addClass("fc-last"):va.removeClass("fc-last")}else va.hide()})}function j(w){o=w;w=o-K.height();var I,R,V;if(L("weekMode")=="variable")I=R=Math.floor(w/(v==1?2:6));else{I=Math.floor(w/v);R=w-I*(v-1)}B.each(function(ea,
+aa){if(ea<v){V=m(aa);Za(V.find("> div"),(ea==v-1?R:I)-Sa(V))}})}function t(w){W=w;M.clear();s=Math.floor(W/F);Va(i.slice(0,-1),s)}function y(w){w.click(S).mousedown(X)}function S(w){if(!L("selectable")){var I=parseInt(this.className.match(/fc\-day(\d+)/)[1]);I=ca(I);c("dayClick",this,I,true,w)}}function Q(w,I,R){R&&r.build();R=N(p.visStart);for(var V=ba(N(R),F),ea=0;ea<v;ea++){var aa=new Date(Math.max(R,w)),va=new Date(Math.min(V,I));if(aa<va){var wa;if(k){wa=Ca(va,R)*D+Z+1;aa=Ca(aa,R)*D+Z+1}else{wa=
+Ca(aa,R);aa=Ca(va,R)}y(q(ea,wa,ea,aa-1))}ba(R,7);ba(V,7)}}function q(w,I,R,V){w=r.rect(w,I,R,V,a);return H(w,a)}function u(w){return N(w)}function fa(w,I){Q(w,ba(N(I),1),true)}function oa(){T()}function ga(w,I,R){var V=ua(w);c("dayClick",E[V.row*F+V.col],w,I,R)}function ra(w,I){J.start(function(R){T();R&&q(R.row,R.col,R.row,R.col)},I)}function sa(w,I,R){var V=J.stop();T();if(V){V=pa(V);c("drop",w,V,true,I,R)}}function ha(w){return N(w.start)}function da(w){return M.left(w)}function na(w){return M.right(w)}
+function ua(w){return{row:Math.floor(Ca(w,p.visStart)/7),col:ka(w.getDay())}}function pa(w){return U(w.row,w.col)}function U(w,I){return ba(N(p.visStart),w*7+I*D+Z)}function ca(w){return U(Math.floor(w/F),w%F)}function ka(w){return(w-Math.max(ja,ia)+F)%F*D+Z}function qa(w){return P.eq(w)}function G(){return{left:0,right:W}}var p=this;p.renderBasic=d;p.setHeight=j;p.setWidth=t;p.renderDayOverlay=Q;p.defaultSelectionEnd=u;p.renderSelection=fa;p.clearSelection=oa;p.reportDayClick=ga;p.dragStart=ra;p.dragStop=
+sa;p.defaultEventEnd=ha;p.getHoverListener=function(){return J};p.colContentLeft=da;p.colContentRight=na;p.dayOfWeekCol=ka;p.dateCell=ua;p.cellDate=pa;p.cellIsAllDay=function(){return true};p.allDayRow=qa;p.allDayBounds=G;p.getRowCnt=function(){return v};p.getColCnt=function(){return F};p.getColWidth=function(){return s};p.getDaySegmentContainer=function(){return Y};Kb.call(p,a,b,e);Lb.call(p);Mb.call(p);pc.call(p);var L=p.opt,c=p.trigger,z=p.clearEvents,H=p.renderOverlay,T=p.clearOverlays,X=p.daySelectionMousedown,
+ya=b.formatDate,K,i,C,P,E,B,n,Y,W,o,s,v,F,r,J,M,k,D,Z,ja,ia,la,$;qb(a.addClass("fc-grid"));r=new Nb(function(w,I){var R,V,ea;i.each(function(aa,va){R=m(va);V=R.offset().left;if(aa)ea[1]=V;ea=[V];I[aa]=ea});ea[1]=V+R.outerWidth();P.each(function(aa,va){if(aa<v){R=m(va);V=R.offset().top;if(aa)ea[1]=V;ea=[V];w[aa]=ea}});ea[1]=V+R.outerHeight()});J=new Ob(r);M=new Pb(function(w){return n.eq(w)})}function pc(){function a(U,ca){S(U);ua(e(U),ca)}function b(){Q();ga().empty()}function e(U){var ca=da(),ka=
+na(),qa=N(g.visStart);ka=ba(N(qa),ka);var G=m.map(U,Ua),p,L,c,z,H,T,X=[];for(p=0;p<ca;p++){L=ob(nb(U,G,qa,ka));for(c=0;c<L.length;c++){z=L[c];for(H=0;H<z.length;H++){T=z[H];T.row=p;T.level=c;X.push(T)}}ba(qa,7);ba(ka,7)}return X}function d(U,ca,ka){t(U)&&f(U,ca);ka.isEnd&&y(U)&&pa(U,ca,ka);q(U,ca)}function f(U,ca){var ka=ra(),qa;ca.draggable({zIndex:9,delay:50,opacity:l("dragOpacity"),revertDuration:l("dragRevertDuration"),start:function(G,p){j("eventDragStart",ca,U,G,p);fa(U,ca);ka.start(function(L,
+c,z,H){ca.draggable("option","revert",!L||!z&&!H);ha();if(L){qa=z*7+H*(l("isRTL")?-1:1);sa(ba(N(U.start),qa),ba(Ua(U),qa))}else qa=0},G,"drag")},stop:function(G,p){ka.stop();ha();j("eventDragStop",ca,U,G,p);if(qa)oa(this,U,qa,0,U.allDay,G,p);else{ca.css("filter","");u(U,ca)}}})}var g=this;g.renderEvents=a;g.compileDaySegs=e;g.clearEvents=b;g.bindDaySeg=d;Qb.call(g);var l=g.opt,j=g.trigger,t=g.isEventDraggable,y=g.isEventResizable,S=g.reportEvents,Q=g.reportEventClear,q=g.eventElementHandlers,u=g.showEvents,
+fa=g.hideEvents,oa=g.eventDrop,ga=g.getDaySegmentContainer,ra=g.getHoverListener,sa=g.renderDayOverlay,ha=g.clearOverlays,da=g.getRowCnt,na=g.getColCnt,ua=g.renderDaySegs,pa=g.resizableDayEvent}function qc(a,b){function e(j,t){t&&ba(j,t*7);j=ba(N(j),-((j.getDay()-f("firstDay")+7)%7));t=ba(N(j),7);var y=N(j),S=N(t),Q=f("weekends");if(!Q){Fa(y);Fa(S,-1,true)}d.title=l(y,ba(N(S),-1),f("titleFormat"));d.start=j;d.end=t;d.visStart=y;d.visEnd=S;g(Q?7:5)}var d=this;d.render=e;Rb.call(d,a,b,"agendaWeek");
+var f=d.opt,g=d.renderAgenda,l=b.formatDates}function rc(a,b){function e(j,t){if(t){ba(j,t);f("weekends")||Fa(j,t<0?-1:1)}t=N(j,true);var y=ba(N(t),1);d.title=l(j,f("titleFormat"));d.start=d.visStart=t;d.end=d.visEnd=y;g(1)}var d=this;d.render=e;Rb.call(d,a,b,"agendaDay");var f=d.opt,g=d.renderAgenda,l=b.formatDate}function Rb(a,b,e){function d(h){Ba=h;f();v?P():g();l()}function f(){Wa=i("theme")?"ui":"fc";Sb=i("weekends")?0:1;Tb=i("firstDay");if(Ub=i("isRTL")){Ha=-1;Ia=Ba-1}else{Ha=1;Ia=0}La=mb(i("minTime"));
+bb=mb(i("maxTime"));Vb=i("columnFormat")}function g(){var h=Wa+"-widget-header",O=Wa+"-widget-content",x,A,ta,za,Da,Ea=i("slotMinutes")%15==0;x="<table style='width:100%' class='fc-agenda-days fc-border-separate' cellspacing='0'><thead><tr><th class='fc-agenda-axis "+h+"'>&nbsp;</th>";for(A=0;A<Ba;A++)x+="<th class='fc- fc-col"+A+" "+h+"'/>";x+="<th class='fc-agenda-gutter "+h+"'>&nbsp;</th></tr></thead><tbody><tr><th class='fc-agenda-axis "+h+"'>&nbsp;</th>";for(A=0;A<Ba;A++)x+="<td class='fc- fc-col"+
+A+" "+O+"'><div><div class='fc-day-content'><div style='position:relative'>&nbsp;</div></div></div></td>";x+="<td class='fc-agenda-gutter "+O+"'>&nbsp;</td></tr></tbody></table>";v=m(x).appendTo(a);F=v.find("thead");r=F.find("th").slice(1,-1);J=v.find("tbody");M=J.find("td").slice(0,-1);k=M.find("div.fc-day-content div");D=M.eq(0);Z=D.find("> div");ab(F.add(F.find("tr")));ab(J.add(J.find("tr")));aa=F.find("th:first");va=v.find(".fc-agenda-gutter");ja=m("<div style='position:absolute;z-index:2;left:0;width:100%'/>").appendTo(a);
+if(i("allDaySlot")){ia=m("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(ja);x="<table style='width:100%' class='fc-agenda-allday' cellspacing='0'><tr><th class='"+h+" fc-agenda-axis'>"+i("allDayText")+"</th><td><div class='fc-day-content'><div style='position:relative'/></div></td><th class='"+h+" fc-agenda-gutter'>&nbsp;</th></tr></table>";la=m(x).appendTo(ja);$=la.find("tr");q($.find("td"));aa=aa.add(la.find("th:first"));va=va.add(la.find("th.fc-agenda-gutter"));ja.append("<div class='fc-agenda-divider "+
+h+"'><div class='fc-agenda-divider-inner'/></div>")}else ia=m([]);w=m("<div style='position:absolute;width:100%;overflow-x:hidden;overflow-y:auto'/>").appendTo(ja);I=m("<div style='position:relative;width:100%;overflow:hidden'/>").appendTo(w);R=m("<div style='position:absolute;z-index:8;top:0;left:0'/>").appendTo(I);x="<table class='fc-agenda-slots' style='width:100%' cellspacing='0'><tbody>";ta=zb();za=xa(N(ta),bb);xa(ta,La);for(A=tb=0;ta<za;A++){Da=ta.getMinutes();x+="<tr class='fc-slot"+A+" "+
+(!Da?"":"fc-minor")+"'><th class='fc-agenda-axis "+h+"'>"+(!Ea||!Da?s(ta,i("axisFormat")):"&nbsp;")+"</th><td class='"+O+"'><div style='position:relative'>&nbsp;</div></td></tr>";xa(ta,i("slotMinutes"));tb++}x+="</tbody></table>";V=m(x).appendTo(I);ea=V.find("div:first");u(V.find("td"));aa=aa.add(V.find("th:first"))}function l(){var h,O,x,A,ta=Ka(new Date);for(h=0;h<Ba;h++){A=ua(h);O=r.eq(h);O.html(s(A,Vb));x=M.eq(h);+A==+ta?x.addClass(Wa+"-state-highlight fc-today"):x.removeClass(Wa+"-state-highlight fc-today");
+rb(O.add(x),A)}}function j(h,O){if(h===ma)h=Wb;Wb=h;ub={};var x=J.position().top,A=w.position().top;h=Math.min(h-x,V.height()+A+1);Z.height(h-Sa(D));ja.css("top",x);w.height(h-A-1);Xa=ea.height()+1;O&&y()}function t(h){Ga=h;cb.clear();Ma=0;Va(aa.width("").each(function(O,x){Ma=Math.max(Ma,m(x).outerWidth())}),Ma);h=w[0].clientWidth;if(vb=w.width()-h){Va(va,vb);va.show().prev().removeClass("fc-last")}else va.hide().prev().addClass("fc-last");db=Math.floor((h-Ma)/Ba);Va(r.slice(0,-1),db)}function y(){function h(){w.scrollTop(A)}
+var O=zb(),x=N(O);x.setHours(i("firstHour"));var A=ca(O,x)+1;h();setTimeout(h,0)}function S(){Xb=w.scrollTop()}function Q(){w.scrollTop(Xb)}function q(h){h.click(fa).mousedown(W)}function u(h){h.click(fa).mousedown(H)}function fa(h){if(!i("selectable")){var O=Math.min(Ba-1,Math.floor((h.pageX-v.offset().left-Ma)/db)),x=ua(O),A=this.parentNode.className.match(/fc-slot(\d+)/);if(A){A=parseInt(A[1])*i("slotMinutes");var ta=Math.floor(A/60);x.setHours(ta);x.setMinutes(A%60+La);C("dayClick",M[O],x,false,
+h)}else C("dayClick",M[O],x,true,h)}}function oa(h,O,x){x&&Na.build();var A=N(K.visStart);if(Ub){x=Ca(O,A)*Ha+Ia+1;h=Ca(h,A)*Ha+Ia+1}else{x=Ca(h,A);h=Ca(O,A)}x=Math.max(0,x);h=Math.min(Ba,h);x<h&&q(ga(0,x,0,h-1))}function ga(h,O,x,A){h=Na.rect(h,O,x,A,ja);return E(h,ja)}function ra(h,O){for(var x=N(K.visStart),A=ba(N(x),1),ta=0;ta<Ba;ta++){var za=new Date(Math.max(x,h)),Da=new Date(Math.min(A,O));if(za<Da){var Ea=ta*Ha+Ia;Ea=Na.rect(0,Ea,0,Ea,I);za=ca(x,za);Da=ca(x,Da);Ea.top=za;Ea.height=Da-za;u(E(Ea,
+I))}ba(x,1);ba(A,1)}}function sa(h){return cb.left(h)}function ha(h){return cb.right(h)}function da(h){return{row:Math.floor(Ca(h,K.visStart)/7),col:U(h.getDay())}}function na(h){var O=ua(h.col);h=h.row;i("allDaySlot")&&h--;h>=0&&xa(O,La+h*i("slotMinutes"));return O}function ua(h){return ba(N(K.visStart),h*Ha+Ia)}function pa(h){return i("allDaySlot")&&!h.row}function U(h){return(h-Math.max(Tb,Sb)+Ba)%Ba*Ha+Ia}function ca(h,O){h=N(h,true);if(O<xa(N(h),La))return 0;if(O>=xa(N(h),bb))return V.height();
+h=i("slotMinutes");O=O.getHours()*60+O.getMinutes()-La;var x=Math.floor(O/h),A=ub[x];if(A===ma)A=ub[x]=V.find("tr:eq("+x+") td div")[0].offsetTop;return Math.max(0,Math.round(A-1+Xa*(O%h/h)))}function ka(){return{left:Ma,right:Ga-vb}}function qa(){return $}function G(h){var O=N(h.start);if(h.allDay)return O;return xa(O,i("defaultEventMinutes"))}function p(h,O){if(O)return N(h);return xa(N(h),i("slotMinutes"))}function L(h,O,x){if(x)i("allDaySlot")&&oa(h,ba(N(O),1),true);else c(h,O)}function c(h,O){var x=
+i("selectHelper");Na.build();if(x){var A=Ca(h,K.visStart)*Ha+Ia;if(A>=0&&A<Ba){A=Na.rect(0,A,0,A,I);var ta=ca(h,h),za=ca(h,O);if(za>ta){A.top=ta;A.height=za-ta;A.left+=2;A.width-=5;if(m.isFunction(x)){if(h=x(h,O)){A.position="absolute";A.zIndex=8;wa=m(h).css(A).appendTo(I)}}else{A.isStart=true;A.isEnd=true;wa=m(o({title:"",start:h,end:O,className:["fc-select-helper"],editable:false},A));wa.css("opacity",i("dragOpacity"))}if(wa){u(wa);I.append(wa);Va(wa,A.width,true);Eb(wa,A.height,true)}}}}else ra(h,
+O)}function z(){B();if(wa){wa.remove();wa=null}}function H(h){if(h.which==1&&i("selectable")){Y(h);var O;Ra.start(function(x,A){z();if(x&&x.col==A.col&&!pa(x)){A=na(A);x=na(x);O=[A,xa(N(A),i("slotMinutes")),x,xa(N(x),i("slotMinutes"))].sort(Gb);c(O[0],O[3])}else O=null},h);m(document).one("mouseup",function(x){Ra.stop();if(O){+O[0]==+O[1]&&T(O[0],false,x);n(O[0],O[3],false,x)}})}}function T(h,O,x){C("dayClick",M[U(h.getDay())],h,O,x)}function X(h,O){Ra.start(function(x){B();if(x)if(pa(x))ga(x.row,
+x.col,x.row,x.col);else{x=na(x);var A=xa(N(x),i("defaultEventMinutes"));ra(x,A)}},O)}function ya(h,O,x){var A=Ra.stop();B();A&&C("drop",h,na(A),pa(A),O,x)}var K=this;K.renderAgenda=d;K.setWidth=t;K.setHeight=j;K.beforeHide=S;K.afterShow=Q;K.defaultEventEnd=G;K.timePosition=ca;K.dayOfWeekCol=U;K.dateCell=da;K.cellDate=na;K.cellIsAllDay=pa;K.allDayRow=qa;K.allDayBounds=ka;K.getHoverListener=function(){return Ra};K.colContentLeft=sa;K.colContentRight=ha;K.getDaySegmentContainer=function(){return ia};
+K.getSlotSegmentContainer=function(){return R};K.getMinMinute=function(){return La};K.getMaxMinute=function(){return bb};K.getBodyContent=function(){return I};K.getRowCnt=function(){return 1};K.getColCnt=function(){return Ba};K.getColWidth=function(){return db};K.getSlotHeight=function(){return Xa};K.defaultSelectionEnd=p;K.renderDayOverlay=oa;K.renderSelection=L;K.clearSelection=z;K.reportDayClick=T;K.dragStart=X;K.dragStop=ya;Kb.call(K,a,b,e);Lb.call(K);Mb.call(K);sc.call(K);var i=K.opt,C=K.trigger,
+P=K.clearEvents,E=K.renderOverlay,B=K.clearOverlays,n=K.reportSelection,Y=K.unselect,W=K.daySelectionMousedown,o=K.slotSegHtml,s=b.formatDate,v,F,r,J,M,k,D,Z,ja,ia,la,$,w,I,R,V,ea,aa,va,wa,Ga,Wb,Ma,db,vb,Xa,Xb,Ba,tb,Na,Ra,cb,ub={},Wa,Tb,Sb,Ub,Ha,Ia,La,bb,Vb;qb(a.addClass("fc-agenda"));Na=new Nb(function(h,O){function x(eb){return Math.max(Ea,Math.min(tc,eb))}var A,ta,za;r.each(function(eb,uc){A=m(uc);ta=A.offset().left;if(eb)za[1]=ta;za=[ta];O[eb]=za});za[1]=ta+A.outerWidth();if(i("allDaySlot")){A=
+$;ta=A.offset().top;h[0]=[ta,ta+A.outerHeight()]}for(var Da=I.offset().top,Ea=w.offset().top,tc=Ea+w.outerHeight(),fb=0;fb<tb;fb++)h.push([x(Da+Xa*fb),x(Da+Xa*(fb+1))])});Ra=new Ob(Na);cb=new Pb(function(h){return k.eq(h)})}function sc(){function a(o,s){sa(o);var v,F=o.length,r=[],J=[];for(v=0;v<F;v++)o[v].allDay?r.push(o[v]):J.push(o[v]);if(u("allDaySlot")){L(e(r),s);na()}g(d(J),s)}function b(){ha();ua().empty();pa().empty()}function e(o){o=ob(nb(o,m.map(o,Ua),q.visStart,q.visEnd));var s,v=o.length,
+F,r,J,M=[];for(s=0;s<v;s++){F=o[s];for(r=0;r<F.length;r++){J=F[r];J.row=0;J.level=s;M.push(J)}}return M}function d(o){var s=z(),v=ka(),F=ca(),r=xa(N(q.visStart),v),J=m.map(o,f),M,k,D,Z,ja,ia,la=[];for(M=0;M<s;M++){k=ob(nb(o,J,r,xa(N(r),F-v)));vc(k);for(D=0;D<k.length;D++){Z=k[D];for(ja=0;ja<Z.length;ja++){ia=Z[ja];ia.col=M;ia.level=D;la.push(ia)}}ba(r,1,true)}return la}function f(o){return o.end?N(o.end):xa(N(o.start),u("defaultEventMinutes"))}function g(o,s){var v,F=o.length,r,J,M,k,D,Z,ja,ia,la,
+$="",w,I,R={},V={},ea=pa(),aa;v=z();if(w=u("isRTL")){I=-1;aa=v-1}else{I=1;aa=0}for(v=0;v<F;v++){r=o[v];J=r.event;M=qa(r.start,r.start);k=qa(r.start,r.end);D=r.col;Z=r.level;ja=r.forward||0;ia=G(D*I+aa);la=p(D*I+aa)-ia;la=Math.min(la-6,la*0.95);D=Z?la/(Z+ja+1):ja?(la/(ja+1)-6)*2:la;Z=ia+la/(Z+ja+1)*Z*I+(w?la-D:0);r.top=M;r.left=Z;r.outerWidth=D;r.outerHeight=k-M;$+=l(J,r)}ea[0].innerHTML=$;w=ea.children();for(v=0;v<F;v++){r=o[v];J=r.event;$=m(w[v]);I=fa("eventRender",J,J,$);if(I===false)$.remove();
+else{if(I&&I!==true){$.remove();$=m(I).css({position:"absolute",top:r.top,left:r.left}).appendTo(ea)}r.element=$;if(J._id===s)t(J,$,r);else $[0]._fci=v;ya(J,$)}}Db(ea,o,t);for(v=0;v<F;v++){r=o[v];if($=r.element){J=R[s=r.key=Ib($[0])];r.vsides=J===ma?(R[s]=Sa($,true)):J;J=V[s];r.hsides=J===ma?(V[s]=pb($,true)):J;s=$.find("div.fc-event-content");if(s.length)r.contentTop=s[0].offsetTop}}for(v=0;v<F;v++){r=o[v];if($=r.element){$[0].style.width=Math.max(0,r.outerWidth-r.hsides)+"px";R=Math.max(0,r.outerHeight-
+r.vsides);$[0].style.height=R+"px";J=r.event;if(r.contentTop!==ma&&R-r.contentTop<10){$.find("div.fc-event-time").text(Y(J.start,u("timeFormat"))+" - "+J.title);$.find("div.fc-event-title").remove()}fa("eventAfterRender",J,J,$)}}}function l(o,s){var v="<",F=o.url,r=Jb(o,u),J=r?" style='"+r+"'":"",M=["fc-event","fc-event-skin","fc-event-vert"];oa(o)&&M.push("fc-event-draggable");s.isStart&&M.push("fc-corner-top");s.isEnd&&M.push("fc-corner-bottom");M=M.concat(o.className);if(o.source)M=M.concat(o.source.className||
+[]);v+=F?"a href='"+Qa(o.url)+"'":"div";v+=" class='"+M.join(" ")+"' style='position:absolute;z-index:8;top:"+s.top+"px;left:"+s.left+"px;"+r+"'><div class='fc-event-inner fc-event-skin'"+J+"><div class='fc-event-head fc-event-skin'"+J+"><div class='fc-event-time'>"+Qa(W(o.start,o.end,u("timeFormat")))+"</div></div><div class='fc-event-content'><div class='fc-event-title'>"+Qa(o.title)+"</div></div><div class='fc-event-bg'></div></div>";if(s.isEnd&&ga(o))v+="<div class='ui-resizable-handle ui-resizable-s'>=</div>";
+v+="</"+(F?"a":"div")+">";return v}function j(o,s,v){oa(o)&&y(o,s,v.isStart);v.isEnd&&ga(o)&&c(o,s,v);da(o,s)}function t(o,s,v){var F=s.find("div.fc-event-time");oa(o)&&S(o,s,F);v.isEnd&&ga(o)&&Q(o,s,F);da(o,s)}function y(o,s,v){function F(){if(!M){s.width(r).height("").draggable("option","grid",null);M=true}}var r,J,M=true,k,D=u("isRTL")?-1:1,Z=U(),ja=H(),ia=T(),la=ka();s.draggable({zIndex:9,opacity:u("dragOpacity","month"),revertDuration:u("dragRevertDuration"),start:function($,w){fa("eventDragStart",
+s,o,$,w);i(o,s);r=s.width();Z.start(function(I,R,V,ea){B();if(I){J=false;k=ea*D;if(I.row)if(v){if(M){s.width(ja-10);Eb(s,ia*Math.round((o.end?(o.end-o.start)/wc:u("defaultEventMinutes"))/u("slotMinutes")));s.draggable("option","grid",[ja,1]);M=false}}else J=true;else{E(ba(N(o.start),k),ba(Ua(o),k));F()}J=J||M&&!k}else{F();J=true}s.draggable("option","revert",J)},$,"drag")},stop:function($,w){Z.stop();B();fa("eventDragStop",s,o,$,w);if(J){F();s.css("filter","");K(o,s)}else{var I=0;M||(I=Math.round((s.offset().top-
+X().offset().top)/ia)*u("slotMinutes")+la-(o.start.getHours()*60+o.start.getMinutes()));C(this,o,k,I,M,$,w)}}})}function S(o,s,v){function F(I){var R=xa(N(o.start),I),V;if(o.end)V=xa(N(o.end),I);v.text(W(R,V,u("timeFormat")))}function r(){if(M){v.css("display","");s.draggable("option","grid",[$,w]);M=false}}var J,M=false,k,D,Z,ja=u("isRTL")?-1:1,ia=U(),la=z(),$=H(),w=T();s.draggable({zIndex:9,scroll:false,grid:[$,w],axis:la==1?"y":false,opacity:u("dragOpacity"),revertDuration:u("dragRevertDuration"),
+start:function(I,R){fa("eventDragStart",s,o,I,R);i(o,s);J=s.position();D=Z=0;ia.start(function(V,ea,aa,va){s.draggable("option","revert",!V);B();if(V){k=va*ja;if(u("allDaySlot")&&!V.row){if(!M){M=true;v.hide();s.draggable("option","grid",null)}E(ba(N(o.start),k),ba(Ua(o),k))}else r()}},I,"drag")},drag:function(I,R){D=Math.round((R.position.top-J.top)/w)*u("slotMinutes");if(D!=Z){M||F(D);Z=D}},stop:function(I,R){var V=ia.stop();B();fa("eventDragStop",s,o,I,R);if(V&&(k||D||M))C(this,o,k,M?0:D,M,I,R);
+else{r();s.css("filter","");s.css(J);F(0);K(o,s)}}})}function Q(o,s,v){var F,r,J=T();s.resizable({handles:{s:"div.ui-resizable-s"},grid:J,start:function(M,k){F=r=0;i(o,s);s.css("z-index",9);fa("eventResizeStart",this,o,M,k)},resize:function(M,k){F=Math.round((Math.max(J,s.height())-k.originalSize.height)/J);if(F!=r){v.text(W(o.start,!F&&!o.end?null:xa(ra(o),u("slotMinutes")*F),u("timeFormat")));r=F}},stop:function(M,k){fa("eventResizeStop",this,o,M,k);if(F)P(this,o,0,u("slotMinutes")*F,M,k);else{s.css("z-index",
+8);K(o,s)}}})}var q=this;q.renderEvents=a;q.compileDaySegs=e;q.clearEvents=b;q.slotSegHtml=l;q.bindDaySeg=j;Qb.call(q);var u=q.opt,fa=q.trigger,oa=q.isEventDraggable,ga=q.isEventResizable,ra=q.eventEnd,sa=q.reportEvents,ha=q.reportEventClear,da=q.eventElementHandlers,na=q.setHeight,ua=q.getDaySegmentContainer,pa=q.getSlotSegmentContainer,U=q.getHoverListener,ca=q.getMaxMinute,ka=q.getMinMinute,qa=q.timePosition,G=q.colContentLeft,p=q.colContentRight,L=q.renderDaySegs,c=q.resizableDayEvent,z=q.getColCnt,
+H=q.getColWidth,T=q.getSlotHeight,X=q.getBodyContent,ya=q.reportEventElement,K=q.showEvents,i=q.hideEvents,C=q.eventDrop,P=q.eventResize,E=q.renderDayOverlay,B=q.clearOverlays,n=q.calendar,Y=n.formatDate,W=n.formatDates}function vc(a){var b,e,d,f,g,l;for(b=a.length-1;b>0;b--){f=a[b];for(e=0;e<f.length;e++){g=f[e];for(d=0;d<a[b-1].length;d++){l=a[b-1][d];if(Cb(g,l))l.forward=Math.max(l.forward||0,(g.forward||0)+1)}}}}function Kb(a,b,e){function d(G,p){G=qa[G];if(typeof G=="object")return jb(G,p||e);
+return G}function f(G,p){return b.trigger.apply(b,[G,p||da].concat(Array.prototype.slice.call(arguments,2),[da]))}function g(G){return j(G)&&!d("disableDragging")}function l(G){return j(G)&&!d("disableResizing")}function j(G){return Ta(G.editable,(G.source||{}).editable,d("editable"))}function t(G){U={};var p,L=G.length,c;for(p=0;p<L;p++){c=G[p];if(U[c._id])U[c._id].push(c);else U[c._id]=[c]}}function y(G){return G.end?N(G.end):na(G)}function S(G,p){ca.push(p);if(ka[G._id])ka[G._id].push(p);else ka[G._id]=
+[p]}function Q(){ca=[];ka={}}function q(G,p){p.click(function(L){if(!p.hasClass("ui-draggable-dragging")&&!p.hasClass("ui-resizable-resizing"))return f("eventClick",this,G,L)}).hover(function(L){f("eventMouseover",this,G,L)},function(L){f("eventMouseout",this,G,L)})}function u(G,p){oa(G,p,"show")}function fa(G,p){oa(G,p,"hide")}function oa(G,p,L){G=ka[G._id];var c,z=G.length;for(c=0;c<z;c++)if(!p||G[c][0]!=p[0])G[c][L]()}function ga(G,p,L,c,z,H,T){var X=p.allDay,ya=p._id;sa(U[ya],L,c,z);f("eventDrop",
+G,p,L,c,z,function(){sa(U[ya],-L,-c,X);pa(ya)},H,T);pa(ya)}function ra(G,p,L,c,z,H){var T=p._id;ha(U[T],L,c);f("eventResize",G,p,L,c,function(){ha(U[T],-L,-c);pa(T)},z,H);pa(T)}function sa(G,p,L,c){L=L||0;for(var z,H=G.length,T=0;T<H;T++){z=G[T];if(c!==ma)z.allDay=c;xa(ba(z.start,p,true),L);if(z.end)z.end=xa(ba(z.end,p,true),L);ua(z,qa)}}function ha(G,p,L){L=L||0;for(var c,z=G.length,H=0;H<z;H++){c=G[H];c.end=xa(ba(y(c),p,true),L);ua(c,qa)}}var da=this;da.element=a;da.calendar=b;da.name=e;da.opt=
+d;da.trigger=f;da.isEventDraggable=g;da.isEventResizable=l;da.reportEvents=t;da.eventEnd=y;da.reportEventElement=S;da.reportEventClear=Q;da.eventElementHandlers=q;da.showEvents=u;da.hideEvents=fa;da.eventDrop=ga;da.eventResize=ra;var na=da.defaultEventEnd,ua=b.normalizeEvent,pa=b.reportEventChange,U={},ca=[],ka={},qa=b.options}function Qb(){function a(i,C){var P=z(),E=pa(),B=U(),n=0,Y,W,o=i.length,s,v;P[0].innerHTML=e(i);d(i,P.children());f(i);g(i,P,C);l(i);j(i);t(i);C=y();for(P=0;P<E;P++){Y=[];for(W=
+0;W<B;W++)Y[W]=0;for(;n<o&&(s=i[n]).row==P;){W=Hb(Y.slice(s.startCol,s.endCol));s.top=W;W+=s.outerHeight;for(v=s.startCol;v<s.endCol;v++)Y[v]=W;n++}C[P].height(Hb(Y))}Q(i,S(C))}function b(i,C,P){var E=m("<div/>"),B=z(),n=i.length,Y;E[0].innerHTML=e(i);E=E.children();B.append(E);d(i,E);l(i);j(i);t(i);Q(i,S(y()));E=[];for(B=0;B<n;B++)if(Y=i[B].element){i[B].row===C&&Y.css("top",P);E.push(Y[0])}return m(E)}function e(i){var C=fa("isRTL"),P,E=i.length,B,n,Y,W;P=ka();var o=P.left,s=P.right,v,F,r,J,M,k=
+"";for(P=0;P<E;P++){B=i[P];n=B.event;W=["fc-event","fc-event-skin","fc-event-hori"];ga(n)&&W.push("fc-event-draggable");if(C){B.isStart&&W.push("fc-corner-right");B.isEnd&&W.push("fc-corner-left");v=p(B.end.getDay()-1);F=p(B.start.getDay());r=B.isEnd?qa(v):o;J=B.isStart?G(F):s}else{B.isStart&&W.push("fc-corner-left");B.isEnd&&W.push("fc-corner-right");v=p(B.start.getDay());F=p(B.end.getDay()-1);r=B.isStart?qa(v):o;J=B.isEnd?G(F):s}W=W.concat(n.className);if(n.source)W=W.concat(n.source.className||
+[]);Y=n.url;M=Jb(n,fa);k+=Y?"<a href='"+Qa(Y)+"'":"<div";k+=" class='"+W.join(" ")+"' style='position:absolute;z-index:8;left:"+r+"px;"+M+"'><div class='fc-event-inner fc-event-skin'"+(M?" style='"+M+"'":"")+">";if(!n.allDay&&B.isStart)k+="<span class='fc-event-time'>"+Qa(T(n.start,n.end,fa("timeFormat")))+"</span>";k+="<span class='fc-event-title'>"+Qa(n.title)+"</span></div>";if(B.isEnd&&ra(n))k+="<div class='ui-resizable-handle ui-resizable-"+(C?"w":"e")+"'>&nbsp;&nbsp;&nbsp;</div>";k+="</"+(Y?
+"a":"div")+">";B.left=r;B.outerWidth=J-r;B.startCol=v;B.endCol=F+1}return k}function d(i,C){var P,E=i.length,B,n,Y;for(P=0;P<E;P++){B=i[P];n=B.event;Y=m(C[P]);n=oa("eventRender",n,n,Y);if(n===false)Y.remove();else{if(n&&n!==true){n=m(n).css({position:"absolute",left:B.left});Y.replaceWith(n);Y=n}B.element=Y}}}function f(i){var C,P=i.length,E,B;for(C=0;C<P;C++){E=i[C];(B=E.element)&&ha(E.event,B)}}function g(i,C,P){var E,B=i.length,n,Y,W;for(E=0;E<B;E++){n=i[E];if(Y=n.element){W=n.event;if(W._id===
+P)H(W,Y,n);else Y[0]._fci=E}}Db(C,i,H)}function l(i){var C,P=i.length,E,B,n,Y,W={};for(C=0;C<P;C++){E=i[C];if(B=E.element){n=E.key=Ib(B[0]);Y=W[n];if(Y===ma)Y=W[n]=pb(B,true);E.hsides=Y}}}function j(i){var C,P=i.length,E,B;for(C=0;C<P;C++){E=i[C];if(B=E.element)B[0].style.width=Math.max(0,E.outerWidth-E.hsides)+"px"}}function t(i){var C,P=i.length,E,B,n,Y,W={};for(C=0;C<P;C++){E=i[C];if(B=E.element){n=E.key;Y=W[n];if(Y===ma)Y=W[n]=Fb(B);E.outerHeight=B[0].offsetHeight+Y}}}function y(){var i,C=pa(),
+P=[];for(i=0;i<C;i++)P[i]=ca(i).find("td:first div.fc-day-content > div");return P}function S(i){var C,P=i.length,E=[];for(C=0;C<P;C++)E[C]=i[C][0].offsetTop;return E}function Q(i,C){var P,E=i.length,B,n;for(P=0;P<E;P++){B=i[P];if(n=B.element){n[0].style.top=C[B.row]+(B.top||0)+"px";B=B.event;oa("eventAfterRender",B,B,n)}}}function q(i,C,P){var E=fa("isRTL"),B=E?"w":"e",n=C.find("div.ui-resizable-"+B),Y=false;qb(C);C.mousedown(function(W){W.preventDefault()}).click(function(W){if(Y){W.preventDefault();
+W.stopImmediatePropagation()}});n.mousedown(function(W){function o(ia){oa("eventResizeStop",this,i,ia);m("body").css("cursor","");s.stop();ya();k&&ua(this,i,k,0,ia);setTimeout(function(){Y=false},0)}if(W.which==1){Y=true;var s=u.getHoverListener(),v=pa(),F=U(),r=E?-1:1,J=E?F-1:0,M=C.css("top"),k,D,Z=m.extend({},i),ja=L(i.start);K();m("body").css("cursor",B+"-resize").one("mouseup",o);oa("eventResizeStart",this,i,W);s.start(function(ia,la){if(ia){var $=Math.max(ja.row,ia.row);ia=ia.col;if(v==1)$=0;
+if($==ja.row)ia=E?Math.min(ja.col,ia):Math.max(ja.col,ia);k=$*7+ia*r+J-(la.row*7+la.col*r+J);la=ba(sa(i),k,true);if(k){Z.end=la;$=D;D=b(c([Z]),P.row,M);D.find("*").css("cursor",B+"-resize");$&&$.remove();na(i)}else if(D){da(i);D.remove();D=null}ya();X(i.start,ba(N(la),1))}},W)}})}var u=this;u.renderDaySegs=a;u.resizableDayEvent=q;var fa=u.opt,oa=u.trigger,ga=u.isEventDraggable,ra=u.isEventResizable,sa=u.eventEnd,ha=u.reportEventElement,da=u.showEvents,na=u.hideEvents,ua=u.eventResize,pa=u.getRowCnt,
+U=u.getColCnt,ca=u.allDayRow,ka=u.allDayBounds,qa=u.colContentLeft,G=u.colContentRight,p=u.dayOfWeekCol,L=u.dateCell,c=u.compileDaySegs,z=u.getDaySegmentContainer,H=u.bindDaySeg,T=u.calendar.formatDates,X=u.renderDayOverlay,ya=u.clearOverlays,K=u.clearSelection}function Mb(){function a(Q,q,u){b();q||(q=j(Q,u));t(Q,q,u);e(Q,q,u)}function b(Q){if(S){S=false;y();l("unselect",null,Q)}}function e(Q,q,u,fa){S=true;l("select",null,Q,q,u,fa)}function d(Q){var q=f.cellDate,u=f.cellIsAllDay,fa=f.getHoverListener(),
+oa=f.reportDayClick;if(Q.which==1&&g("selectable")){b(Q);var ga;fa.start(function(ra,sa){y();if(ra&&u(ra)){ga=[q(sa),q(ra)].sort(Gb);t(ga[0],ga[1],true)}else ga=null},Q);m(document).one("mouseup",function(ra){fa.stop();if(ga){+ga[0]==+ga[1]&&oa(ga[0],true,ra);e(ga[0],ga[1],true,ra)}})}}var f=this;f.select=a;f.unselect=b;f.reportSelection=e;f.daySelectionMousedown=d;var g=f.opt,l=f.trigger,j=f.defaultSelectionEnd,t=f.renderSelection,y=f.clearSelection,S=false;g("selectable")&&g("unselectAuto")&&m(document).mousedown(function(Q){var q=
+g("unselectCancel");if(q)if(m(Q.target).parents(q).length)return;b(Q)})}function Lb(){function a(g,l){var j=f.shift();j||(j=m("<div class='fc-cell-overlay' style='position:absolute;z-index:3'/>"));j[0].parentNode!=l[0]&&j.appendTo(l);d.push(j.css(g).show());return j}function b(){for(var g;g=d.shift();)f.push(g.hide().unbind())}var e=this;e.renderOverlay=a;e.clearOverlays=b;var d=[],f=[]}function Nb(a){var b=this,e,d;b.build=function(){e=[];d=[];a(e,d)};b.cell=function(f,g){var l=e.length,j=d.length,
+t,y=-1,S=-1;for(t=0;t<l;t++)if(g>=e[t][0]&&g<e[t][1]){y=t;break}for(t=0;t<j;t++)if(f>=d[t][0]&&f<d[t][1]){S=t;break}return y>=0&&S>=0?{row:y,col:S}:null};b.rect=function(f,g,l,j,t){t=t.offset();return{top:e[f][0]-t.top,left:d[g][0]-t.left,width:d[j][1]-d[g][0],height:e[l][1]-e[f][0]}}}function Ob(a){function b(j){xc(j);j=a.cell(j.pageX,j.pageY);if(!j!=!l||j&&(j.row!=l.row||j.col!=l.col)){if(j){g||(g=j);f(j,g,j.row-g.row,j.col-g.col)}else f(j,g);l=j}}var e=this,d,f,g,l;e.start=function(j,t,y){f=j;
+g=l=null;a.build();b(t);d=y||"mousemove";m(document).bind(d,b)};e.stop=function(){m(document).unbind(d,b);return l}}function xc(a){if(a.pageX===ma){a.pageX=a.originalEvent.pageX;a.pageY=a.originalEvent.pageY}}function Pb(a){function b(l){return d[l]=d[l]||a(l)}var e=this,d={},f={},g={};e.left=function(l){return f[l]=f[l]===ma?b(l).position().left:f[l]};e.right=function(l){return g[l]=g[l]===ma?e.left(l)+b(l).width():g[l]};e.clear=function(){d={};f={};g={}}}var Ya={defaultView:"month",aspectRatio:1.35,
+header:{left:"title",center:"",right:"today prev,next"},weekends:true,allDayDefault:true,ignoreTimezone:true,lazyFetching:true,startParam:"start",endParam:"end",titleFormat:{month:"MMMM yyyy",week:"MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}",day:"dddd, MMM d, yyyy"},columnFormat:{month:"ddd",week:"ddd M/d",day:"dddd M/d"},timeFormat:{"":"h(:mm)t"},isRTL:false,firstDay:0,monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan",
+"Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],buttonText:{prev:"&nbsp;&#9668;&nbsp;",next:"&nbsp;&#9658;&nbsp;",prevYear:"&nbsp;&lt;&lt;&nbsp;",nextYear:"&nbsp;&gt;&gt;&nbsp;",today:"today",month:"month",week:"week",day:"day"},theme:false,buttonIcons:{prev:"circle-triangle-w",next:"circle-triangle-e"},unselectAuto:true,dropAccept:"*"},yc=
+{header:{left:"next,prev today",center:"",right:"title"},buttonText:{prev:"&nbsp;&#9658;&nbsp;",next:"&nbsp;&#9668;&nbsp;",prevYear:"&nbsp;&gt;&gt;&nbsp;",nextYear:"&nbsp;&lt;&lt;&nbsp;"},buttonIcons:{prev:"circle-triangle-e",next:"circle-triangle-w"}},Aa=m.fullCalendar={version:"1.5.4"},Ja=Aa.views={};m.fn.fullCalendar=function(a){if(typeof a=="string"){var b=Array.prototype.slice.call(arguments,1),e;this.each(function(){var f=m.data(this,"fullCalendar");if(f&&m.isFunction(f[a])){f=f[a].apply(f,
+b);if(e===ma)e=f;a=="destroy"&&m.removeData(this,"fullCalendar")}});if(e!==ma)return e;return this}var d=a.eventSources||[];delete a.eventSources;if(a.events){d.push(a.events);delete a.events}a=m.extend(true,{},Ya,a.isRTL||a.isRTL===ma&&Ya.isRTL?yc:{},a);this.each(function(f,g){f=m(g);g=new Yb(f,a,d);f.data("fullCalendar",g);g.render()});return this};Aa.sourceNormalizers=[];Aa.sourceFetchers=[];var ac={dataType:"json",cache:false},bc=1;Aa.addDays=ba;Aa.cloneDate=N;Aa.parseDate=kb;Aa.parseISO8601=
+Bb;Aa.parseTime=mb;Aa.formatDate=Oa;Aa.formatDates=ib;var lc=["sun","mon","tue","wed","thu","fri","sat"],Ab=864E5,cc=36E5,wc=6E4,dc={s:function(a){return a.getSeconds()},ss:function(a){return Pa(a.getSeconds())},m:function(a){return a.getMinutes()},mm:function(a){return Pa(a.getMinutes())},h:function(a){return a.getHours()%12||12},hh:function(a){return Pa(a.getHours()%12||12)},H:function(a){return a.getHours()},HH:function(a){return Pa(a.getHours())},d:function(a){return a.getDate()},dd:function(a){return Pa(a.getDate())},
+ddd:function(a,b){return b.dayNamesShort[a.getDay()]},dddd:function(a,b){return b.dayNames[a.getDay()]},M:function(a){return a.getMonth()+1},MM:function(a){return Pa(a.getMonth()+1)},MMM:function(a,b){return b.monthNamesShort[a.getMonth()]},MMMM:function(a,b){return b.monthNames[a.getMonth()]},yy:function(a){return(a.getFullYear()+"").substring(2)},yyyy:function(a){return a.getFullYear()},t:function(a){return a.getHours()<12?"a":"p"},tt:function(a){return a.getHours()<12?"am":"pm"},T:function(a){return a.getHours()<
+12?"A":"P"},TT:function(a){return a.getHours()<12?"AM":"PM"},u:function(a){return Oa(a,"yyyy-MM-dd'T'HH:mm:ss'Z'")},S:function(a){a=a.getDate();if(a>10&&a<20)return"th";return["st","nd","rd"][a%10-1]||"th"}};Aa.applyAll=$a;Ja.month=mc;Ja.basicWeek=nc;Ja.basicDay=oc;wb({weekMode:"fixed"});Ja.agendaWeek=qc;Ja.agendaDay=rc;wb({allDaySlot:true,allDayText:"all-day",firstHour:6,slotMinutes:30,defaultEventMinutes:120,axisFormat:"h(:mm)tt",timeFormat:{agenda:"h:mm{ - h:mm}"},dragOpacity:{agenda:0.5},minTime:0,
+maxTime:24})})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.print.css b/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.print.css
new file mode 100644
index 00000000..227b80e0
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fullcalendar/fullcalendar.print.css
@@ -0,0 +1,61 @@
+/*
+ * FullCalendar v1.5.4 Print Stylesheet
+ *
+ * Include this stylesheet on your page to get a more printer-friendly calendar.
+ * When including this stylesheet, use the media='print' attribute of the <link> tag.
+ * Make sure to include this stylesheet IN ADDITION to the regular fullcalendar.css.
+ *
+ * Copyright (c) 2011 Adam Shaw
+ * Dual licensed under the MIT and GPL licenses, located in
+ * MIT-LICENSE.txt and GPL-LICENSE.txt respectively.
+ *
+ * Date: Tue Sep 4 23:38:33 2012 -0700
+ *
+ */
+
+
+ /* Events
+-----------------------------------------------------*/
+
+.fc-event-skin {
+ background: none !important;
+ color: #000 !important;
+ }
+
+/* horizontal events */
+
+.fc-event-hori {
+ border-width: 0 0 1px 0 !important;
+ border-bottom-style: dotted !important;
+ border-bottom-color: #000 !important;
+ padding: 1px 0 0 0 !important;
+ }
+
+.fc-event-hori .fc-event-inner {
+ border-width: 0 !important;
+ padding: 0 1px !important;
+ }
+
+/* vertical events */
+
+.fc-event-vert {
+ border-width: 0 0 0 1px !important;
+ border-left-style: dotted !important;
+ border-left-color: #000 !important;
+ padding: 0 1px 0 0 !important;
+ }
+
+.fc-event-vert .fc-event-inner {
+ border-width: 0 !important;
+ padding: 1px 0 !important;
+ }
+
+.fc-event-bg {
+ display: none !important;
+ }
+
+.fc-event .ui-resizable-handle {
+ display: none !important;
+ }
+
+
diff --git a/SemanticResultFormats/resources/jquery/fullcalendar/gcal.js b/SemanticResultFormats/resources/jquery/fullcalendar/gcal.js
new file mode 100644
index 00000000..ba42ac56
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/fullcalendar/gcal.js
@@ -0,0 +1,112 @@
+/*
+ * FullCalendar v1.5.4 Google Calendar Plugin
+ *
+ * Copyright (c) 2011 Adam Shaw
+ * Dual licensed under the MIT and GPL licenses, located in
+ * MIT-LICENSE.txt and GPL-LICENSE.txt respectively.
+ *
+ * Date: Tue Sep 4 23:38:33 2012 -0700
+ *
+ */
+
+(function($) {
+
+
+var fc = $.fullCalendar;
+var formatDate = fc.formatDate;
+var parseISO8601 = fc.parseISO8601;
+var addDays = fc.addDays;
+var applyAll = fc.applyAll;
+
+
+fc.sourceNormalizers.push(function(sourceOptions) {
+ if (sourceOptions.dataType == 'gcal' ||
+ sourceOptions.dataType === undefined &&
+ (sourceOptions.url || '').match(/^(http|https):\/\/www.google.com\/calendar\/feeds\//)) {
+ sourceOptions.dataType = 'gcal';
+ if (sourceOptions.editable === undefined) {
+ sourceOptions.editable = false;
+ }
+ }
+});
+
+
+fc.sourceFetchers.push(function(sourceOptions, start, end) {
+ if (sourceOptions.dataType == 'gcal') {
+ return transformOptions(sourceOptions, start, end);
+ }
+});
+
+
+function transformOptions(sourceOptions, start, end) {
+
+ var success = sourceOptions.success;
+ var data = $.extend({}, sourceOptions.data || {}, {
+ 'start-min': formatDate(start, 'u'),
+ 'start-max': formatDate(end, 'u'),
+ 'singleevents': true,
+ 'max-results': 9999
+ });
+
+ var ctz = sourceOptions.currentTimezone;
+ if (ctz) {
+ data.ctz = ctz = ctz.replace(' ', '_');
+ }
+
+ return $.extend({}, sourceOptions, {
+ url: sourceOptions.url.replace(/\/basic$/, '/full') + '?alt=json-in-script&callback=?',
+ dataType: 'jsonp',
+ data: data,
+ startParam: false,
+ endParam: false,
+ success: function(data) {
+ var events = [];
+ if (data.feed.entry) {
+ $.each(data.feed.entry, function(i, entry) {
+ var startStr = entry['gd$when'][0]['startTime'];
+ var start = parseISO8601(startStr, true);
+ var end = parseISO8601(entry['gd$when'][0]['endTime'], true);
+ var allDay = startStr.indexOf('T') == -1;
+ var url;
+ $.each(entry.link, function(i, link) {
+ if (link.type == 'text/html') {
+ url = link.href;
+ if (ctz) {
+ url += (url.indexOf('?') == -1 ? '?' : '&') + 'ctz=' + ctz;
+ }
+ }
+ });
+ if (allDay) {
+ addDays(end, -1); // make inclusive
+ }
+ events.push({
+ id: entry['gCal$uid']['value'],
+ title: entry['title']['$t'],
+ url: url,
+ start: start,
+ end: end,
+ allDay: allDay,
+ location: entry['gd$where'][0]['valueString'],
+ description: entry['content']['$t']
+ });
+ });
+ }
+ var args = [events].concat(Array.prototype.slice.call(arguments, 1));
+ var res = applyAll(success, this, args);
+ if ($.isArray(res)) {
+ return res;
+ }
+ return events;
+ }
+ });
+
+}
+
+
+// legacy
+fc.gcalFeed = function(url, sourceOptions) {
+ return $.extend({}, sourceOptions, { url: url, dataType: 'gcal' });
+};
+
+
+})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/jplayer/Jplayer.swf b/SemanticResultFormats/resources/jquery/jplayer/Jplayer.swf
new file mode 100644
index 00000000..f324cefe
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/Jplayer.swf
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/jplayer/add-on/jplayer.playlist.min.js b/SemanticResultFormats/resources/jquery/jplayer/add-on/jplayer.playlist.min.js
new file mode 100644
index 00000000..138ccfa5
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/add-on/jplayer.playlist.min.js
@@ -0,0 +1,34 @@
+/*
+ * Playlist Object for the jPlayer Plugin
+ * http://www.jplayer.org
+ *
+ * Copyright (c) 2009 - 2013 Happyworm Ltd
+ * Dual licensed under the MIT and GPL licenses.
+ * - http://www.opensource.org/licenses/mit-license.php
+ * - http://www.gnu.org/copyleft/gpl.html
+ *
+ * Author: Mark J Panaghiston
+ * Version: 2.3.0
+ * Date: 20th April 2013
+ *
+ * Requires:
+ * - jQuery 1.7.0+
+ * - jPlayer 2.3.0+
+ */
+(function(b,f){jPlayerPlaylist=function(a,c,d){var e=this;this.current=0;this.removing=this.shuffled=this.loop=!1;this.cssSelector=b.extend({},this._cssSelector,a);this.options=b.extend(!0,{keyBindings:{next:{key:39,fn:function(){e.next()}},previous:{key:37,fn:function(){e.previous()}}}},this._options,d);this.playlist=[];this.original=[];this._initPlaylist(c);this.cssSelector.title=this.cssSelector.cssSelectorAncestor+" .jp-title";this.cssSelector.playlist=this.cssSelector.cssSelectorAncestor+" .jp-playlist";
+this.cssSelector.next=this.cssSelector.cssSelectorAncestor+" .jp-next";this.cssSelector.previous=this.cssSelector.cssSelectorAncestor+" .jp-previous";this.cssSelector.shuffle=this.cssSelector.cssSelectorAncestor+" .jp-shuffle";this.cssSelector.shuffleOff=this.cssSelector.cssSelectorAncestor+" .jp-shuffle-off";this.options.cssSelectorAncestor=this.cssSelector.cssSelectorAncestor;this.options.repeat=function(a){e.loop=a.jPlayer.options.loop};b(this.cssSelector.jPlayer).bind(b.jPlayer.event.ready,function(){e._init()});
+b(this.cssSelector.jPlayer).bind(b.jPlayer.event.ended,function(){e.next()});b(this.cssSelector.jPlayer).bind(b.jPlayer.event.play,function(){b(this).jPlayer("pauseOthers")});b(this.cssSelector.jPlayer).bind(b.jPlayer.event.resize,function(a){a.jPlayer.options.fullScreen?b(e.cssSelector.title).show():b(e.cssSelector.title).hide()});b(this.cssSelector.previous).click(function(){e.previous();b(this).blur();return!1});b(this.cssSelector.next).click(function(){e.next();b(this).blur();return!1});b(this.cssSelector.shuffle).click(function(){e.shuffle(!0);
+return!1});b(this.cssSelector.shuffleOff).click(function(){e.shuffle(!1);return!1}).hide();this.options.fullScreen||b(this.cssSelector.title).hide();b(this.cssSelector.playlist+" ul").empty();this._createItemHandlers();b(this.cssSelector.jPlayer).jPlayer(this.options)};jPlayerPlaylist.prototype={_cssSelector:{jPlayer:"#jquery_jplayer_1",cssSelectorAncestor:"#jp_container_1"},_options:{playlistOptions:{autoPlay:!1,loopOnPrevious:!1,shuffleOnLoop:!0,enableRemoveControls:!1,displayTime:"slow",addTime:"fast",
+removeTime:"fast",shuffleTime:"slow",itemClass:"jp-playlist-item",freeGroupClass:"jp-free-media",freeItemClass:"jp-playlist-item-free",removeItemClass:"jp-playlist-item-remove"}},option:function(a,b){if(b===f)return this.options.playlistOptions[a];this.options.playlistOptions[a]=b;switch(a){case "enableRemoveControls":this._updateControls();break;case "itemClass":case "freeGroupClass":case "freeItemClass":case "removeItemClass":this._refresh(!0),this._createItemHandlers()}return this},_init:function(){var a=
+this;this._refresh(function(){a.options.playlistOptions.autoPlay?a.play(a.current):a.select(a.current)})},_initPlaylist:function(a){this.current=0;this.removing=this.shuffled=!1;this.original=b.extend(!0,[],a);this._originalPlaylist()},_originalPlaylist:function(){var a=this;this.playlist=[];b.each(this.original,function(b){a.playlist[b]=a.original[b]})},_refresh:function(a){var c=this;if(a&&!b.isFunction(a))b(this.cssSelector.playlist+" ul").empty(),b.each(this.playlist,function(a){b(c.cssSelector.playlist+
+" ul").append(c._createListItem(c.playlist[a]))}),this._updateControls();else{var d=b(this.cssSelector.playlist+" ul").children().length?this.options.playlistOptions.displayTime:0;b(this.cssSelector.playlist+" ul").slideUp(d,function(){var d=b(this);b(this).empty();b.each(c.playlist,function(a){d.append(c._createListItem(c.playlist[a]))});c._updateControls();b.isFunction(a)&&a();c.playlist.length?b(this).slideDown(c.options.playlistOptions.displayTime):b(this).show()})}},_createListItem:function(a){var c=
+this,d="<li><div>",d=d+("<a href='javascript:;' class='"+this.options.playlistOptions.removeItemClass+"'>&times;</a>");if(a.free){var e=!0,d=d+("<span class='"+this.options.playlistOptions.freeGroupClass+"'>(");b.each(a,function(a,f){b.jPlayer.prototype.format[a]&&(e?e=!1:d+=" | ",d+="<a class='"+c.options.playlistOptions.freeItemClass+"' href='"+f+"' tabindex='1'>"+a+"</a>")});d+=")</span>"}d+="<a href='javascript:;' class='"+this.options.playlistOptions.itemClass+"' tabindex='1'>"+a.title+(a.artist?
+" <span class='jp-artist'>by "+a.artist+"</span>":"")+"</a>";return d+="</div></li>"},_createItemHandlers:function(){var a=this;b(this.cssSelector.playlist).off("click","a."+this.options.playlistOptions.itemClass).on("click","a."+this.options.playlistOptions.itemClass,function(){var c=b(this).parent().parent().index();a.current!==c?a.play(c):b(a.cssSelector.jPlayer).jPlayer("play");b(this).blur();return!1});b(this.cssSelector.playlist).off("click","a."+this.options.playlistOptions.freeItemClass).on("click",
+"a."+this.options.playlistOptions.freeItemClass,function(){b(this).parent().parent().find("."+a.options.playlistOptions.itemClass).click();b(this).blur();return!1});b(this.cssSelector.playlist).off("click","a."+this.options.playlistOptions.removeItemClass).on("click","a."+this.options.playlistOptions.removeItemClass,function(){var c=b(this).parent().parent().index();a.remove(c);b(this).blur();return!1})},_updateControls:function(){this.options.playlistOptions.enableRemoveControls?b(this.cssSelector.playlist+
+" ."+this.options.playlistOptions.removeItemClass).show():b(this.cssSelector.playlist+" ."+this.options.playlistOptions.removeItemClass).hide();this.shuffled?(b(this.cssSelector.shuffleOff).show(),b(this.cssSelector.shuffle).hide()):(b(this.cssSelector.shuffleOff).hide(),b(this.cssSelector.shuffle).show())},_highlight:function(a){this.playlist.length&&a!==f&&(b(this.cssSelector.playlist+" .jp-playlist-current").removeClass("jp-playlist-current"),b(this.cssSelector.playlist+" li:nth-child("+(a+1)+
+")").addClass("jp-playlist-current").find(".jp-playlist-item").addClass("jp-playlist-current"),b(this.cssSelector.title+" li").html(this.playlist[a].title+(this.playlist[a].artist?" <span class='jp-artist'>by "+this.playlist[a].artist+"</span>":"")))},setPlaylist:function(a){this._initPlaylist(a);this._init()},add:function(a,c){b(this.cssSelector.playlist+" ul").append(this._createListItem(a)).find("li:last-child").hide().slideDown(this.options.playlistOptions.addTime);this._updateControls();this.original.push(a);
+this.playlist.push(a);c?this.play(this.playlist.length-1):1===this.original.length&&this.select(0)},remove:function(a){var c=this;if(a===f)return this._initPlaylist([]),this._refresh(function(){b(c.cssSelector.jPlayer).jPlayer("clearMedia")}),!0;if(this.removing)return!1;a=0>a?c.original.length+a:a;0<=a&&a<this.playlist.length&&(this.removing=!0,b(this.cssSelector.playlist+" li:nth-child("+(a+1)+")").slideUp(this.options.playlistOptions.removeTime,function(){b(this).remove();if(c.shuffled){var d=
+c.playlist[a];b.each(c.original,function(a){if(c.original[a]===d)return c.original.splice(a,1),!1})}else c.original.splice(a,1);c.playlist.splice(a,1);c.original.length?a===c.current?(c.current=a<c.original.length?c.current:c.original.length-1,c.select(c.current)):a<c.current&&c.current--:(b(c.cssSelector.jPlayer).jPlayer("clearMedia"),c.current=0,c.shuffled=!1,c._updateControls());c.removing=!1}));return!0},select:function(a){a=0>a?this.original.length+a:a;0<=a&&a<this.playlist.length?(this.current=
+a,this._highlight(a),b(this.cssSelector.jPlayer).jPlayer("setMedia",this.playlist[this.current])):this.current=0},play:function(a){a=0>a?this.original.length+a:a;0<=a&&a<this.playlist.length?this.playlist.length&&(this.select(a),b(this.cssSelector.jPlayer).jPlayer("play")):a===f&&b(this.cssSelector.jPlayer).jPlayer("play")},pause:function(){b(this.cssSelector.jPlayer).jPlayer("pause")},next:function(){var a=this.current+1<this.playlist.length?this.current+1:0;this.loop?0===a&&this.shuffled&&this.options.playlistOptions.shuffleOnLoop&&
+1<this.playlist.length?this.shuffle(!0,!0):this.play(a):0<a&&this.play(a)},previous:function(){var a=0<=this.current-1?this.current-1:this.playlist.length-1;(this.loop&&this.options.playlistOptions.loopOnPrevious||a<this.playlist.length-1)&&this.play(a)},shuffle:function(a,c){var d=this;a===f&&(a=!this.shuffled);(a||a!==this.shuffled)&&b(this.cssSelector.playlist+" ul").slideUp(this.options.playlistOptions.shuffleTime,function(){(d.shuffled=a)?d.playlist.sort(function(){return 0.5-Math.random()}):
+d._originalPlaylist();d._refresh(!0);c||!b(d.cssSelector.jPlayer).data("jPlayer").status.paused?d.play(0):d.select(0);b(this).slideDown(d.options.playlistOptions.shuffleTime)})}}})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jplayer/add-on/jquery.jplayer.inspector.js b/SemanticResultFormats/resources/jquery/jplayer/add-on/jquery.jplayer.inspector.js
new file mode 100644
index 00000000..d8f59140
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/add-on/jquery.jplayer.inspector.js
@@ -0,0 +1,338 @@
+/*
+ * jPlayerInspector Plugin for jPlayer Plugin for jQuery JavaScript Library
+ * http://www.jplayer.org
+ *
+ * Copyright (c) 2009 - 2013 Happyworm Ltd
+ * Dual licensed under the MIT and GPL licenses.
+ * - http://www.opensource.org/licenses/mit-license.php
+ * - http://www.gnu.org/copyleft/gpl.html
+ *
+ * Author: Mark J Panaghiston
+ * Version: 1.0.4
+ * Date: 29th January 2013
+ *
+ * For use with jPlayer Version: 2.2.19+
+ *
+ * Note: Declare inspector instances after jPlayer instances. ie., Otherwise the jPlayer instance is nonsense.
+ */
+
+(function($, undefined) {
+ $.jPlayerInspector = {};
+ $.jPlayerInspector.i = 0;
+ $.jPlayerInspector.defaults = {
+ jPlayer: undefined, // The jQuery selector of the jPlayer instance to inspect.
+ idPrefix: "jplayer_inspector_",
+ visible: false
+ };
+
+ var methods = {
+ init: function(options) {
+ var self = this;
+ var $this = $(this);
+
+ var config = $.extend({}, $.jPlayerInspector.defaults, options);
+ $(this).data("jPlayerInspector", config);
+
+ config.id = $(this).attr("id");
+ config.jPlayerId = config.jPlayer.attr("id");
+
+ config.windowId = config.idPrefix + "window_" + $.jPlayerInspector.i;
+ config.statusId = config.idPrefix + "status_" + $.jPlayerInspector.i;
+ config.configId = config.idPrefix + "config_" + $.jPlayerInspector.i;
+ config.toggleId = config.idPrefix + "toggle_" + $.jPlayerInspector.i;
+ config.eventResetId = config.idPrefix + "event_reset_" + $.jPlayerInspector.i;
+ config.updateId = config.idPrefix + "update_" + $.jPlayerInspector.i;
+ config.eventWindowId = config.idPrefix + "event_window_" + $.jPlayerInspector.i;
+
+ config.eventId = {};
+ config.eventJq = {};
+ config.eventTimeout = {};
+ config.eventOccurrence = {};
+
+ $.each($.jPlayer.event, function(eventName,eventType) {
+ config.eventId[eventType] = config.idPrefix + "event_" + eventName + "_" + $.jPlayerInspector.i;
+ config.eventOccurrence[eventType] = 0;
+ });
+
+ var structure =
+ '<p><a href="#" id="' + config.toggleId + '">' + (config.visible ? "Hide" : "Show") + '</a> jPlayer Inspector</p>'
+ + '<div id="' + config.windowId + '">'
+ + '<div id="' + config.statusId + '"></div>'
+ + '<div id="' + config.eventWindowId + '" style="padding:5px 5px 0 5px;background-color:#eee;border:1px dotted #000;">'
+ + '<p style="margin:0 0 10px 0;"><strong>jPlayer events that have occurred over the past 1 second:</strong>'
+ + '<br />(Backgrounds: <span style="padding:0 5px;background-color:#eee;border:1px dotted #000;">Never occurred</span> <span style="padding:0 5px;background-color:#fff;border:1px dotted #000;">Occurred before</span> <span style="padding:0 5px;background-color:#9f9;border:1px dotted #000;">Occurred</span> <span style="padding:0 5px;background-color:#ff9;border:1px dotted #000;">Multiple occurrences</span> <a href="#" id="' + config.eventResetId + '">reset</a>)</p>';
+
+ // MJP: Would use the next 3 lines for ease, but the events are just slapped on the page.
+ // $.each($.jPlayer.event, function(eventName,eventType) {
+ // structure += '<div id="' + config.eventId[eventType] + '" style="float:left;">' + eventName + '</div>';
+ // });
+
+ var eventStyle = "float:left;margin:0 5px 5px 0;padding:0 5px;border:1px dotted #000;";
+ // MJP: Doing it longhand so order and layout easier to control.
+ structure +=
+ '<div id="' + config.eventId[$.jPlayer.event.ready] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.flashreset] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.resize] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.repeat] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.click] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.error] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.warning] + '" style="' + eventStyle + '"></div>'
+
+ + '<div id="' + config.eventId[$.jPlayer.event.loadstart] + '" style="clear:left;' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.progress] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.timeupdate] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.volumechange] + '" style="' + eventStyle + '"></div>'
+
+ + '<div id="' + config.eventId[$.jPlayer.event.play] + '" style="clear:left;' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.pause] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.waiting] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.playing] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.seeking] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.seeked] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.ended] + '" style="' + eventStyle + '"></div>'
+
+ + '<div id="' + config.eventId[$.jPlayer.event.loadeddata] + '" style="clear:left;' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.loadedmetadata] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.canplay] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.canplaythrough] + '" style="' + eventStyle + '"></div>'
+
+ + '<div id="' + config.eventId[$.jPlayer.event.suspend] + '" style="clear:left;' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.abort] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.emptied] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.stalled] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.ratechange] + '" style="' + eventStyle + '"></div>'
+ + '<div id="' + config.eventId[$.jPlayer.event.durationchange] + '" style="' + eventStyle + '"></div>'
+
+ + '<div style="clear:both"></div>';
+
+ // MJP: Would like a check here in case we missed an event.
+
+ // MJP: Check fails, since it is not on the page yet.
+/* $.each($.jPlayer.event, function(eventName,eventType) {
+ if($("#" + config.eventId[eventType])[0] === undefined) {
+ structure += '<div id="' + config.eventId[eventType] + '" style="clear:left;' + eventStyle + '">' + eventName + '</div>';
+ }
+ });
+*/
+ structure +=
+ '</div>'
+ + '<p><a href="#" id="' + config.updateId + '">Update</a> jPlayer Inspector</p>'
+ + '<div id="' + config.configId + '"></div>'
+ + '</div>';
+ $(this).html(structure);
+
+ config.windowJq = $("#" + config.windowId);
+ config.statusJq = $("#" + config.statusId);
+ config.configJq = $("#" + config.configId);
+ config.toggleJq = $("#" + config.toggleId);
+ config.eventResetJq = $("#" + config.eventResetId);
+ config.updateJq = $("#" + config.updateId);
+
+ $.each($.jPlayer.event, function(eventName,eventType) {
+ config.eventJq[eventType] = $("#" + config.eventId[eventType]);
+ config.eventJq[eventType].text(eventName + " (" + config.eventOccurrence[eventType] + ")"); // Sets the text to the event name and (0);
+
+ config.jPlayer.bind(eventType + ".jPlayerInspector", function(e) {
+ config.eventOccurrence[e.type]++;
+ if(config.eventOccurrence[e.type] > 1) {
+ config.eventJq[e.type].css("background-color","#ff9");
+ } else {
+ config.eventJq[e.type].css("background-color","#9f9");
+ }
+ config.eventJq[e.type].text(eventName + " (" + config.eventOccurrence[e.type] + ")");
+ // The timer to handle the color
+ clearTimeout(config.eventTimeout[e.type]);
+ config.eventTimeout[e.type] = setTimeout(function() {
+ config.eventJq[e.type].css("background-color","#fff");
+ }, 1000);
+ // The timer to handle the occurences.
+ setTimeout(function() {
+ config.eventOccurrence[e.type]--;
+ config.eventJq[e.type].text(eventName + " (" + config.eventOccurrence[e.type] + ")");
+ }, 1000);
+ if(config.visible) { // Update the status, if inspector open.
+ $this.jPlayerInspector("updateStatus");
+ }
+ });
+ });
+
+ config.jPlayer.bind($.jPlayer.event.ready + ".jPlayerInspector", function(e) {
+ $this.jPlayerInspector("updateConfig");
+ });
+
+ config.toggleJq.click(function() {
+ if(config.visible) {
+ $(this).text("Show");
+ config.windowJq.hide();
+ config.statusJq.empty();
+ config.configJq.empty();
+ } else {
+ $(this).text("Hide");
+ config.windowJq.show();
+ config.updateJq.click();
+ }
+ config.visible = !config.visible;
+ $(this).blur();
+ return false;
+ });
+
+ config.eventResetJq.click(function() {
+ $.each($.jPlayer.event, function(eventName,eventType) {
+ config.eventJq[eventType].css("background-color","#eee");
+ });
+ $(this).blur();
+ return false;
+ });
+
+ config.updateJq.click(function() {
+ $this.jPlayerInspector("updateStatus");
+ $this.jPlayerInspector("updateConfig");
+ return false;
+ });
+
+ if(!config.visible) {
+ config.windowJq.hide();
+ } else {
+ // config.updateJq.click();
+ }
+
+ $.jPlayerInspector.i++;
+
+ return this;
+ },
+ destroy: function() {
+ $(this).data("jPlayerInspector") && $(this).data("jPlayerInspector").jPlayer.unbind(".jPlayerInspector");
+ $(this).empty();
+ },
+ updateConfig: function() { // This displays information about jPlayer's configuration in inspector
+
+ var jPlayerInfo = "<p>This jPlayer instance is running in your browser where:<br />"
+
+ for(i = 0; i < $(this).data("jPlayerInspector").jPlayer.data("jPlayer").solutions.length; i++) {
+ var solution = $(this).data("jPlayerInspector").jPlayer.data("jPlayer").solutions[i];
+ jPlayerInfo += "&nbsp;jPlayer's <strong>" + solution + "</strong> solution is";
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer")[solution].used) {
+ jPlayerInfo += " being <strong>used</strong> and will support:<strong>";
+ for(format in $(this).data("jPlayerInspector").jPlayer.data("jPlayer")[solution].support) {
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer")[solution].support[format]) {
+ jPlayerInfo += " " + format;
+ }
+ }
+ jPlayerInfo += "</strong><br />";
+ } else {
+ jPlayerInfo += " <strong>not required</strong><br />";
+ }
+ }
+ jPlayerInfo += "</p>";
+
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer").html.active) {
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer").flash.active) {
+ jPlayerInfo += "<strong>Problem with jPlayer since both HTML5 and Flash are active.</strong>";
+ } else {
+ jPlayerInfo += "The <strong>HTML5 is active</strong>.";
+ }
+ } else {
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer").flash.active) {
+ jPlayerInfo += "The <strong>Flash is active</strong>.";
+ } else {
+ jPlayerInfo += "No solution is currently active. jPlayer needs a setMedia().";
+ }
+ }
+ jPlayerInfo += "</p>";
+
+ var formatType = $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.formatType;
+ jPlayerInfo += "<p><code>status.formatType = '" + formatType + "'</code><br />";
+ if(formatType) {
+ jPlayerInfo += "<code>Browser canPlay('" + $.jPlayer.prototype.format[formatType].codec + "')</code>";
+ } else {
+ jPlayerInfo += "</p>";
+ }
+
+ jPlayerInfo += "<p><code>status.src = '" + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.src + "'</code></p>";
+
+ jPlayerInfo += "<p><code>status.media = {<br />";
+ for(prop in $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.media) {
+ jPlayerInfo += "&nbsp;" + prop + ": " + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.media[prop] + "<br />"; // Some are strings
+ }
+ jPlayerInfo += "};</code></p>"
+
+ jPlayerInfo += "<p>";
+ jPlayerInfo += "<code>status.videoWidth = '" + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.videoWidth + "'</code>";
+ jPlayerInfo += " | <code>status.videoHeight = '" + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.videoHeight + "'</code>";
+ jPlayerInfo += "<br /><code>status.width = '" + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.width + "'</code>";
+ jPlayerInfo += " | <code>status.height = '" + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.height + "'</code>";
+ jPlayerInfo += "</p>";
+
+ + "<p>Raw browser test for HTML5 support. Should equal a function if HTML5 is available.<br />";
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer").html.audio.available) {
+ jPlayerInfo += "<code>htmlElement.audio.canPlayType = " + (typeof $(this).data("jPlayerInspector").jPlayer.data("jPlayer").htmlElement.audio.canPlayType) +"</code><br />"
+ }
+ if($(this).data("jPlayerInspector").jPlayer.data("jPlayer").html.video.available) {
+ jPlayerInfo += "<code>htmlElement.video.canPlayType = " + (typeof $(this).data("jPlayerInspector").jPlayer.data("jPlayer").htmlElement.video.canPlayType) +"</code>";
+ }
+ jPlayerInfo += "</p>";
+
+ jPlayerInfo += "<p>This instance is using the constructor options:<br />"
+ + "<code>$('#" + $(this).data("jPlayerInspector").jPlayer.data("jPlayer").internal.self.id + "').jPlayer({<br />"
+
+ + "&nbsp;swfPath: '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "swfPath") + "',<br />"
+
+ + "&nbsp;solution: '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "solution") + "',<br />"
+
+ + "&nbsp;supplied: '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "supplied") + "',<br />"
+
+ + "&nbsp;preload: '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "preload") + "',<br />"
+
+ + "&nbsp;volume: " + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "volume") + ",<br />"
+
+ + "&nbsp;muted: " + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "muted") + ",<br />"
+
+ + "&nbsp;backgroundColor: '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "backgroundColor") + "',<br />"
+
+ + "&nbsp;cssSelectorAncestor: '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "cssSelectorAncestor") + "',<br />"
+
+ + "&nbsp;cssSelector: {";
+
+ var cssSelector = $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "cssSelector");
+ for(prop in cssSelector) {
+
+ // jPlayerInfo += "<br />&nbsp;&nbsp;" + prop + ": '" + cssSelector[prop] + "'," // This works too of course, but want to use option method for deep keys.
+ jPlayerInfo += "<br />&nbsp;&nbsp;" + prop + ": '" + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "cssSelector." + prop) + "',"
+ }
+
+ jPlayerInfo = jPlayerInfo.slice(0, -1); // Because the sloppy comma was bugging me.
+
+ jPlayerInfo += "<br />&nbsp;},<br />"
+
+ + "&nbsp;errorAlerts: " + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "errorAlerts") + ",<br />"
+
+ + "&nbsp;warningAlerts: " + $(this).data("jPlayerInspector").jPlayer.jPlayer("option", "warningAlerts") + "<br />"
+
+ + "});</code></p>";
+ $(this).data("jPlayerInspector").configJq.html(jPlayerInfo);
+ return this;
+ },
+ updateStatus: function() { // This displays information about jPlayer's status in the inspector
+ $(this).data("jPlayerInspector").statusJq.html(
+ "<p>jPlayer is " +
+ ($(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.paused ? "paused" : "playing") +
+ " at time: " + Math.floor($(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.currentTime*10)/10 + "s." +
+ " (d: " + Math.floor($(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.duration*10)/10 + "s" +
+ ", sp: " + Math.floor($(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.seekPercent) + "%" +
+ ", cpr: " + Math.floor($(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.currentPercentRelative) + "%" +
+ ", cpa: " + Math.floor($(this).data("jPlayerInspector").jPlayer.data("jPlayer").status.currentPercentAbsolute) + "%)</p>"
+ );
+ return this;
+ }
+ };
+ $.fn.jPlayerInspector = function( method ) {
+ // Method calling logic
+ if ( methods[method] ) {
+ return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
+ } else if ( typeof method === 'object' || ! method ) {
+ return methods.init.apply( this, arguments );
+ } else {
+ $.error( 'Method ' + method + ' does not exist on jQuery.jPlayerInspector' );
+ }
+ };
+})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/jplayer/jquery.jplayer.min.js b/SemanticResultFormats/resources/jquery/jplayer/jquery.jplayer.min.js
new file mode 100644
index 00000000..d0c72396
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/jquery.jplayer.min.js
@@ -0,0 +1,107 @@
+/*
+ * jPlayer Plugin for jQuery JavaScript Library
+ * http://www.jplayer.org
+ *
+ * Copyright (c) 2009 - 2013 Happyworm Ltd
+ * Dual licensed under the MIT and GPL licenses.
+ * - http://www.opensource.org/licenses/mit-license.php
+ * - http://www.gnu.org/copyleft/gpl.html
+ *
+ * Author: Mark J Panaghiston
+ * Version: 2.3.0
+ * Date: 20th April 2013
+ */
+(function(b,f){"function"===typeof define&&define.amd?define(["jquery"],f):f(b.jQuery)})(this,function(b,f){b.fn.jPlayer=function(a){var c="string"===typeof a,d=Array.prototype.slice.call(arguments,1),e=this;a=!c&&d.length?b.extend.apply(null,[!0,a].concat(d)):a;if(c&&"_"===a.charAt(0))return e;c?this.each(function(){var c=b.data(this,"jPlayer"),h=c&&b.isFunction(c[a])?c[a].apply(c,d):c;if(h!==c&&h!==f)return e=h,!1}):this.each(function(){var c=b.data(this,"jPlayer");c?c.option(a||{}):b.data(this,
+"jPlayer",new b.jPlayer(a,this))});return e};b.jPlayer=function(a,c){if(arguments.length){this.element=b(c);this.options=b.extend(!0,{},this.options,a);var d=this;this.element.bind("remove.jPlayer",function(){d.destroy()});this._init()}};b.jPlayer.emulateMethods="load play pause";b.jPlayer.emulateStatus="src readyState networkState currentTime duration paused ended playbackRate";b.jPlayer.emulateOptions="muted volume";b.jPlayer.reservedEvent="ready flashreset resize repeat error warning";b.jPlayer.event=
+{};b.each("ready flashreset resize repeat click error warning loadstart progress suspend abort emptied stalled play pause loadedmetadata loadeddata waiting playing canplay canplaythrough seeking seeked timeupdate ended ratechange durationchange volumechange".split(" "),function(){b.jPlayer.event[this]="jPlayer_"+this});b.jPlayer.htmlEvent="loadstart abort emptied stalled loadedmetadata loadeddata canplay canplaythrough ratechange".split(" ");b.jPlayer.pause=function(){b.each(b.jPlayer.prototype.instances,
+function(a,c){c.data("jPlayer").status.srcSet&&c.jPlayer("pause")})};b.jPlayer.timeFormat={showHour:!1,showMin:!0,showSec:!0,padHour:!1,padMin:!0,padSec:!0,sepHour:":",sepMin:":",sepSec:""};var l=function(){this.init()};l.prototype={init:function(){this.options={timeFormat:b.jPlayer.timeFormat}},time:function(a){var c=new Date(1E3*(a&&"number"===typeof a?a:0)),b=c.getUTCHours();a=this.options.timeFormat.showHour?c.getUTCMinutes():c.getUTCMinutes()+60*b;c=this.options.timeFormat.showMin?c.getUTCSeconds():
+c.getUTCSeconds()+60*a;b=this.options.timeFormat.padHour&&10>b?"0"+b:b;a=this.options.timeFormat.padMin&&10>a?"0"+a:a;c=this.options.timeFormat.padSec&&10>c?"0"+c:c;b=""+(this.options.timeFormat.showHour?b+this.options.timeFormat.sepHour:"");b+=this.options.timeFormat.showMin?a+this.options.timeFormat.sepMin:"";return b+=this.options.timeFormat.showSec?c+this.options.timeFormat.sepSec:""}};var m=new l;b.jPlayer.convertTime=function(a){return m.time(a)};b.jPlayer.uaBrowser=function(a){a=a.toLowerCase();
+var b=/(opera)(?:.*version)?[ \/]([\w.]+)/,d=/(msie) ([\w.]+)/,e=/(mozilla)(?:.*? rv:([\w.]+))?/;a=/(webkit)[ \/]([\w.]+)/.exec(a)||b.exec(a)||d.exec(a)||0>a.indexOf("compatible")&&e.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}};b.jPlayer.uaPlatform=function(a){var b=a.toLowerCase(),d=/(android)/,e=/(mobile)/;a=/(ipad|iphone|ipod|android|blackberry|playbook|windows ce|webos)/.exec(b)||[];b=/(ipad|playbook)/.exec(b)||!e.exec(b)&&d.exec(b)||[];a[1]&&(a[1]=a[1].replace(/\s/g,"_"));return{platform:a[1]||
+"",tablet:b[1]||""}};b.jPlayer.browser={};b.jPlayer.platform={};var j=b.jPlayer.uaBrowser(navigator.userAgent);j.browser&&(b.jPlayer.browser[j.browser]=!0,b.jPlayer.browser.version=j.version);j=b.jPlayer.uaPlatform(navigator.userAgent);j.platform&&(b.jPlayer.platform[j.platform]=!0,b.jPlayer.platform.mobile=!j.tablet,b.jPlayer.platform.tablet=!!j.tablet);b.jPlayer.getDocMode=function(){var a;b.jPlayer.browser.msie&&(document.documentMode?a=document.documentMode:(a=5,document.compatMode&&"CSS1Compat"===
+document.compatMode&&(a=7)));return a};b.jPlayer.browser.documentMode=b.jPlayer.getDocMode();b.jPlayer.nativeFeatures={init:function(){var a=document,b=a.createElement("video"),d={w3c:"fullscreenEnabled fullscreenElement requestFullscreen exitFullscreen fullscreenchange fullscreenerror".split(" "),moz:"mozFullScreenEnabled mozFullScreenElement mozRequestFullScreen mozCancelFullScreen mozfullscreenchange mozfullscreenerror".split(" "),webkit:" webkitCurrentFullScreenElement webkitRequestFullScreen webkitCancelFullScreen webkitfullscreenchange ".split(" "),
+webkitVideo:"webkitSupportsFullscreen webkitDisplayingFullscreen webkitEnterFullscreen webkitExitFullscreen ".split(" ")},e=["w3c","moz","webkit","webkitVideo"],g,h;this.fullscreen=b={support:{w3c:!!a[d.w3c[0]],moz:!!a[d.moz[0]],webkit:"function"===typeof a[d.webkit[3]],webkitVideo:"function"===typeof b[d.webkitVideo[2]]},used:{}};g=0;for(h=e.length;g<h;g++){var f=e[g];if(b.support[f]){b.spec=f;b.used[f]=!0;break}}if(b.spec){var k=d[b.spec];b.api={fullscreenEnabled:!0,fullscreenElement:function(b){b=
+b?b:a;return b[k[1]]},requestFullscreen:function(a){return a[k[2]]()},exitFullscreen:function(b){b=b?b:a;return b[k[3]]()}};b.event={fullscreenchange:k[4],fullscreenerror:k[5]}}else b.api={fullscreenEnabled:!1,fullscreenElement:function(){return null},requestFullscreen:function(){},exitFullscreen:function(){}},b.event={}}};b.jPlayer.nativeFeatures.init();b.jPlayer.focus=null;b.jPlayer.keyIgnoreElementNames="INPUT TEXTAREA";var n=function(a){var c=b.jPlayer.focus,d;c&&(b.each(b.jPlayer.keyIgnoreElementNames.split(/\s+/g),
+function(b,c){if(a.target.nodeName.toUpperCase()===c.toUpperCase())return d=!0,!1}),d||b.each(c.options.keyBindings,function(d,g){if(g&&a.which===g.key&&b.isFunction(g.fn))return a.preventDefault(),g.fn(c),!1}))};b.jPlayer.keys=function(a){b(document.documentElement).unbind("keydown.jPlayer");a&&b(document.documentElement).bind("keydown.jPlayer",n)};b.jPlayer.keys(!0);b.jPlayer.prototype={count:0,version:{script:"2.3.0",needFlash:"2.3.0",flash:"unknown"},options:{swfPath:"js",solution:"html, flash",
+supplied:"mp3",preload:"metadata",volume:0.8,muted:!1,wmode:"opaque",backgroundColor:"#000000",cssSelectorAncestor:"#jp_container_1",cssSelector:{videoPlay:".jp-video-play",play:".jp-play",pause:".jp-pause",stop:".jp-stop",seekBar:".jp-seek-bar",playBar:".jp-play-bar",mute:".jp-mute",unmute:".jp-unmute",volumeBar:".jp-volume-bar",volumeBarValue:".jp-volume-bar-value",volumeMax:".jp-volume-max",currentTime:".jp-current-time",duration:".jp-duration",fullScreen:".jp-full-screen",restoreScreen:".jp-restore-screen",
+repeat:".jp-repeat",repeatOff:".jp-repeat-off",gui:".jp-gui",noSolution:".jp-no-solution"},smoothPlayBar:!1,fullScreen:!1,fullWindow:!1,autohide:{restored:!1,full:!0,fadeIn:200,fadeOut:600,hold:1E3},loop:!1,repeat:function(a){a.jPlayer.options.loop?b(this).unbind(".jPlayerRepeat").bind(b.jPlayer.event.ended+".jPlayer.jPlayerRepeat",function(){b(this).jPlayer("play")}):b(this).unbind(".jPlayerRepeat")},nativeVideoControls:{},noFullWindow:{msie:/msie [0-6]\./,ipad:/ipad.*?os [0-4]\./,iphone:/iphone/,
+ipod:/ipod/,android_pad:/android [0-3]\.(?!.*?mobile)/,android_phone:/android.*?mobile/,blackberry:/blackberry/,windows_ce:/windows ce/,iemobile:/iemobile/,webos:/webos/},noVolume:{ipad:/ipad/,iphone:/iphone/,ipod:/ipod/,android_pad:/android(?!.*?mobile)/,android_phone:/android.*?mobile/,blackberry:/blackberry/,windows_ce:/windows ce/,iemobile:/iemobile/,webos:/webos/,playbook:/playbook/},timeFormat:{},keyEnabled:!1,audioFullScreen:!1,keyBindings:{play:{key:32,fn:function(a){a.status.paused?a.play():
+a.pause()}},fullScreen:{key:13,fn:function(a){(a.status.video||a.options.audioFullScreen)&&a._setOption("fullScreen",!a.options.fullScreen)}},muted:{key:8,fn:function(a){a._muted(!a.options.muted)}},volumeUp:{key:38,fn:function(a){a.volume(a.options.volume+0.1)}},volumeDown:{key:40,fn:function(a){a.volume(a.options.volume-0.1)}}},verticalVolume:!1,idPrefix:"jp",noConflict:"jQuery",emulateHtml:!1,errorAlerts:!1,warningAlerts:!1},optionsAudio:{size:{width:"0px",height:"0px",cssClass:""},sizeFull:{width:"0px",
+height:"0px",cssClass:""}},optionsVideo:{size:{width:"480px",height:"270px",cssClass:"jp-video-270p"},sizeFull:{width:"100%",height:"100%",cssClass:"jp-video-full"}},instances:{},status:{src:"",media:{},paused:!0,format:{},formatType:"",waitForPlay:!0,waitForLoad:!0,srcSet:!1,video:!1,seekPercent:0,currentPercentRelative:0,currentPercentAbsolute:0,currentTime:0,duration:0,videoWidth:0,videoHeight:0,readyState:0,networkState:0,playbackRate:1,ended:0},internal:{ready:!1},solution:{html:!0,flash:!0},
+format:{mp3:{codec:'audio/mpeg; codecs="mp3"',flashCanPlay:!0,media:"audio"},m4a:{codec:'audio/mp4; codecs="mp4a.40.2"',flashCanPlay:!0,media:"audio"},oga:{codec:'audio/ogg; codecs="vorbis"',flashCanPlay:!1,media:"audio"},wav:{codec:'audio/wav; codecs="1"',flashCanPlay:!1,media:"audio"},webma:{codec:'audio/webm; codecs="vorbis"',flashCanPlay:!1,media:"audio"},fla:{codec:"audio/x-flv",flashCanPlay:!0,media:"audio"},rtmpa:{codec:'audio/rtmp; codecs="rtmp"',flashCanPlay:!0,media:"audio"},m4v:{codec:'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
+flashCanPlay:!0,media:"video"},ogv:{codec:'video/ogg; codecs="theora, vorbis"',flashCanPlay:!1,media:"video"},webmv:{codec:'video/webm; codecs="vorbis, vp8"',flashCanPlay:!1,media:"video"},flv:{codec:"video/x-flv",flashCanPlay:!0,media:"video"},rtmpv:{codec:'video/rtmp; codecs="rtmp"',flashCanPlay:!0,media:"video"}},_init:function(){var a=this;this.element.empty();this.status=b.extend({},this.status);this.internal=b.extend({},this.internal);this.options.timeFormat=b.extend({},b.jPlayer.timeFormat,
+this.options.timeFormat);this.internal.cmdsIgnored=b.jPlayer.platform.ipad||b.jPlayer.platform.iphone||b.jPlayer.platform.ipod;this.internal.domNode=this.element.get(0);this.options.keyEnabled&&!b.jPlayer.focus&&(b.jPlayer.focus=this);this.formats=[];this.solutions=[];this.require={};this.htmlElement={};this.html={};this.html.audio={};this.html.video={};this.flash={};this.css={};this.css.cs={};this.css.jq={};this.ancestorJq=[];this.options.volume=this._limitValue(this.options.volume,0,1);b.each(this.options.supplied.toLowerCase().split(","),
+function(c,d){var e=d.replace(/^\s+|\s+$/g,"");if(a.format[e]){var f=!1;b.each(a.formats,function(a,b){if(e===b)return f=!0,!1});f||a.formats.push(e)}});b.each(this.options.solution.toLowerCase().split(","),function(c,d){var e=d.replace(/^\s+|\s+$/g,"");if(a.solution[e]){var f=!1;b.each(a.solutions,function(a,b){if(e===b)return f=!0,!1});f||a.solutions.push(e)}});this.internal.instance="jp_"+this.count;this.instances[this.internal.instance]=this.element;this.element.attr("id")||this.element.attr("id",
+this.options.idPrefix+"_jplayer_"+this.count);this.internal.self=b.extend({},{id:this.element.attr("id"),jq:this.element});this.internal.audio=b.extend({},{id:this.options.idPrefix+"_audio_"+this.count,jq:f});this.internal.video=b.extend({},{id:this.options.idPrefix+"_video_"+this.count,jq:f});this.internal.flash=b.extend({},{id:this.options.idPrefix+"_flash_"+this.count,jq:f,swf:this.options.swfPath+(".swf"!==this.options.swfPath.toLowerCase().slice(-4)?(this.options.swfPath&&"/"!==this.options.swfPath.slice(-1)?
+"/":"")+"Jplayer.swf":"")});this.internal.poster=b.extend({},{id:this.options.idPrefix+"_poster_"+this.count,jq:f});b.each(b.jPlayer.event,function(b,c){a.options[b]!==f&&(a.element.bind(c+".jPlayer",a.options[b]),a.options[b]=f)});this.require.audio=!1;this.require.video=!1;b.each(this.formats,function(b,c){a.require[a.format[c].media]=!0});this.options=this.require.video?b.extend(!0,{},this.optionsVideo,this.options):b.extend(!0,{},this.optionsAudio,this.options);this._setSize();this.status.nativeVideoControls=
+this._uaBlocklist(this.options.nativeVideoControls);this.status.noFullWindow=this._uaBlocklist(this.options.noFullWindow);this.status.noVolume=this._uaBlocklist(this.options.noVolume);b.jPlayer.nativeFeatures.fullscreen.api.fullscreenEnabled&&this._fullscreenAddEventListeners();this._restrictNativeVideoControls();this.htmlElement.poster=document.createElement("img");this.htmlElement.poster.id=this.internal.poster.id;this.htmlElement.poster.onload=function(){(!a.status.video||a.status.waitForPlay)&&
+a.internal.poster.jq.show()};this.element.append(this.htmlElement.poster);this.internal.poster.jq=b("#"+this.internal.poster.id);this.internal.poster.jq.css({width:this.status.width,height:this.status.height});this.internal.poster.jq.hide();this.internal.poster.jq.bind("click.jPlayer",function(){a._trigger(b.jPlayer.event.click)});this.html.audio.available=!1;this.require.audio&&(this.htmlElement.audio=document.createElement("audio"),this.htmlElement.audio.id=this.internal.audio.id,this.html.audio.available=
+!!this.htmlElement.audio.canPlayType&&this._testCanPlayType(this.htmlElement.audio));this.html.video.available=!1;this.require.video&&(this.htmlElement.video=document.createElement("video"),this.htmlElement.video.id=this.internal.video.id,this.html.video.available=!!this.htmlElement.video.canPlayType&&this._testCanPlayType(this.htmlElement.video));this.flash.available=this._checkForFlash(10.1);this.html.canPlay={};this.flash.canPlay={};b.each(this.formats,function(b,c){a.html.canPlay[c]=a.html[a.format[c].media].available&&
+""!==a.htmlElement[a.format[c].media].canPlayType(a.format[c].codec);a.flash.canPlay[c]=a.format[c].flashCanPlay&&a.flash.available});this.html.desired=!1;this.flash.desired=!1;b.each(this.solutions,function(c,d){if(0===c)a[d].desired=!0;else{var e=!1,f=!1;b.each(a.formats,function(b,c){a[a.solutions[0]].canPlay[c]&&("video"===a.format[c].media?f=!0:e=!0)});a[d].desired=a.require.audio&&!e||a.require.video&&!f}});this.html.support={};this.flash.support={};b.each(this.formats,function(b,c){a.html.support[c]=
+a.html.canPlay[c]&&a.html.desired;a.flash.support[c]=a.flash.canPlay[c]&&a.flash.desired});this.html.used=!1;this.flash.used=!1;b.each(this.solutions,function(c,d){b.each(a.formats,function(b,c){if(a[d].support[c])return a[d].used=!0,!1})});this._resetActive();this._resetGate();this._cssSelectorAncestor(this.options.cssSelectorAncestor);!this.html.used&&!this.flash.used?(this._error({type:b.jPlayer.error.NO_SOLUTION,context:"{solution:'"+this.options.solution+"', supplied:'"+this.options.supplied+
+"'}",message:b.jPlayer.errorMsg.NO_SOLUTION,hint:b.jPlayer.errorHint.NO_SOLUTION}),this.css.jq.noSolution.length&&this.css.jq.noSolution.show()):this.css.jq.noSolution.length&&this.css.jq.noSolution.hide();if(this.flash.used){var c,d="jQuery="+encodeURI(this.options.noConflict)+"&id="+encodeURI(this.internal.self.id)+"&vol="+this.options.volume+"&muted="+this.options.muted;if(b.jPlayer.browser.msie&&(9>Number(b.jPlayer.browser.version)||9>b.jPlayer.browser.documentMode)){d=['<param name="movie" value="'+
+this.internal.flash.swf+'" />','<param name="FlashVars" value="'+d+'" />','<param name="allowScriptAccess" value="always" />','<param name="bgcolor" value="'+this.options.backgroundColor+'" />','<param name="wmode" value="'+this.options.wmode+'" />'];c=document.createElement('<object id="'+this.internal.flash.id+'" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="0" height="0" tabindex="-1"></object>');for(var e=0;e<d.length;e++)c.appendChild(document.createElement(d[e]))}else e=function(a,
+b,c){var d=document.createElement("param");d.setAttribute("name",b);d.setAttribute("value",c);a.appendChild(d)},c=document.createElement("object"),c.setAttribute("id",this.internal.flash.id),c.setAttribute("data",this.internal.flash.swf),c.setAttribute("type","application/x-shockwave-flash"),c.setAttribute("width","1"),c.setAttribute("height","1"),c.setAttribute("tabindex","-1"),e(c,"flashvars",d),e(c,"allowscriptaccess","always"),e(c,"bgcolor",this.options.backgroundColor),e(c,"wmode",this.options.wmode);
+this.element.append(c);this.internal.flash.jq=b(c)}this.html.used&&(this.html.audio.available&&(this._addHtmlEventListeners(this.htmlElement.audio,this.html.audio),this.element.append(this.htmlElement.audio),this.internal.audio.jq=b("#"+this.internal.audio.id)),this.html.video.available&&(this._addHtmlEventListeners(this.htmlElement.video,this.html.video),this.element.append(this.htmlElement.video),this.internal.video.jq=b("#"+this.internal.video.id),this.status.nativeVideoControls?this.internal.video.jq.css({width:this.status.width,
+height:this.status.height}):this.internal.video.jq.css({width:"0px",height:"0px"}),this.internal.video.jq.bind("click.jPlayer",function(){a._trigger(b.jPlayer.event.click)})));this.options.emulateHtml&&this._emulateHtmlBridge();this.html.used&&!this.flash.used&&setTimeout(function(){a.internal.ready=!0;a.version.flash="n/a";a._trigger(b.jPlayer.event.repeat);a._trigger(b.jPlayer.event.ready)},100);this._updateNativeVideoControls();this._updateInterface();this._updateButtons(!1);this._updateAutohide();
+this._updateVolume(this.options.volume);this._updateMute(this.options.muted);this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide();b.jPlayer.prototype.count++},destroy:function(){this.clearMedia();this._removeUiClass();this.css.jq.currentTime.length&&this.css.jq.currentTime.text("");this.css.jq.duration.length&&this.css.jq.duration.text("");b.each(this.css.jq,function(a,b){b.length&&b.unbind(".jPlayer")});this.internal.poster.jq.unbind(".jPlayer");this.internal.video.jq&&this.internal.video.jq.unbind(".jPlayer");
+this._fullscreenRemoveEventListeners();this===b.jPlayer.focus&&(b.jPlayer.focus=null);this.options.emulateHtml&&this._destroyHtmlBridge();this.element.removeData("jPlayer");this.element.unbind(".jPlayer");this.element.empty();delete this.instances[this.internal.instance]},enable:function(){},disable:function(){},_testCanPlayType:function(a){try{return a.canPlayType(this.format.mp3.codec),!0}catch(b){return!1}},_uaBlocklist:function(a){var c=navigator.userAgent.toLowerCase(),d=!1;b.each(a,function(a,
+b){if(b&&b.test(c))return d=!0,!1});return d},_restrictNativeVideoControls:function(){this.require.audio&&this.status.nativeVideoControls&&(this.status.nativeVideoControls=!1,this.status.noFullWindow=!0)},_updateNativeVideoControls:function(){this.html.video.available&&this.html.used&&(this.htmlElement.video.controls=this.status.nativeVideoControls,this._updateAutohide(),this.status.nativeVideoControls&&this.require.video?(this.internal.poster.jq.hide(),this.internal.video.jq.css({width:this.status.width,
+height:this.status.height})):this.status.waitForPlay&&this.status.video&&(this.internal.poster.jq.show(),this.internal.video.jq.css({width:"0px",height:"0px"})))},_addHtmlEventListeners:function(a,c){var d=this;a.preload=this.options.preload;a.muted=this.options.muted;a.volume=this.options.volume;a.addEventListener("progress",function(){c.gate&&(d.internal.cmdsIgnored&&0<this.readyState&&(d.internal.cmdsIgnored=!1),d._getHtmlStatus(a),d._updateInterface(),d._trigger(b.jPlayer.event.progress))},!1);
+a.addEventListener("timeupdate",function(){c.gate&&(d._getHtmlStatus(a),d._updateInterface(),d._trigger(b.jPlayer.event.timeupdate))},!1);a.addEventListener("durationchange",function(){c.gate&&(d._getHtmlStatus(a),d._updateInterface(),d._trigger(b.jPlayer.event.durationchange))},!1);a.addEventListener("play",function(){c.gate&&(d._updateButtons(!0),d._html_checkWaitForPlay(),d._trigger(b.jPlayer.event.play))},!1);a.addEventListener("playing",function(){c.gate&&(d._updateButtons(!0),d._seeked(),d._trigger(b.jPlayer.event.playing))},
+!1);a.addEventListener("pause",function(){c.gate&&(d._updateButtons(!1),d._trigger(b.jPlayer.event.pause))},!1);a.addEventListener("waiting",function(){c.gate&&(d._seeking(),d._trigger(b.jPlayer.event.waiting))},!1);a.addEventListener("seeking",function(){c.gate&&(d._seeking(),d._trigger(b.jPlayer.event.seeking))},!1);a.addEventListener("seeked",function(){c.gate&&(d._seeked(),d._trigger(b.jPlayer.event.seeked))},!1);a.addEventListener("volumechange",function(){c.gate&&(d.options.volume=a.volume,
+d.options.muted=a.muted,d._updateMute(),d._updateVolume(),d._trigger(b.jPlayer.event.volumechange))},!1);a.addEventListener("suspend",function(){c.gate&&(d._seeked(),d._trigger(b.jPlayer.event.suspend))},!1);a.addEventListener("ended",function(){c.gate&&(b.jPlayer.browser.webkit||(d.htmlElement.media.currentTime=0),d.htmlElement.media.pause(),d._updateButtons(!1),d._getHtmlStatus(a,!0),d._updateInterface(),d._trigger(b.jPlayer.event.ended))},!1);a.addEventListener("error",function(){c.gate&&(d._updateButtons(!1),
+d._seeked(),d.status.srcSet&&(clearTimeout(d.internal.htmlDlyCmdId),d.status.waitForLoad=!0,d.status.waitForPlay=!0,d.status.video&&!d.status.nativeVideoControls&&d.internal.video.jq.css({width:"0px",height:"0px"}),d._validString(d.status.media.poster)&&!d.status.nativeVideoControls&&d.internal.poster.jq.show(),d.css.jq.videoPlay.length&&d.css.jq.videoPlay.show(),d._error({type:b.jPlayer.error.URL,context:d.status.src,message:b.jPlayer.errorMsg.URL,hint:b.jPlayer.errorHint.URL})))},!1);b.each(b.jPlayer.htmlEvent,
+function(e,g){a.addEventListener(this,function(){c.gate&&d._trigger(b.jPlayer.event[g])},!1)})},_getHtmlStatus:function(a,b){var d=0,e=0,g=0,f=0;isFinite(a.duration)&&(this.status.duration=a.duration);d=a.currentTime;e=0<this.status.duration?100*d/this.status.duration:0;"object"===typeof a.seekable&&0<a.seekable.length?(g=0<this.status.duration?100*a.seekable.end(a.seekable.length-1)/this.status.duration:100,f=0<this.status.duration?100*a.currentTime/a.seekable.end(a.seekable.length-1):0):(g=100,
+f=e);b&&(e=f=d=0);this.status.seekPercent=g;this.status.currentPercentRelative=f;this.status.currentPercentAbsolute=e;this.status.currentTime=d;this.status.videoWidth=a.videoWidth;this.status.videoHeight=a.videoHeight;this.status.readyState=a.readyState;this.status.networkState=a.networkState;this.status.playbackRate=a.playbackRate;this.status.ended=a.ended},_resetStatus:function(){this.status=b.extend({},this.status,b.jPlayer.prototype.status)},_trigger:function(a,c,d){a=b.Event(a);a.jPlayer={};
+a.jPlayer.version=b.extend({},this.version);a.jPlayer.options=b.extend(!0,{},this.options);a.jPlayer.status=b.extend(!0,{},this.status);a.jPlayer.html=b.extend(!0,{},this.html);a.jPlayer.flash=b.extend(!0,{},this.flash);c&&(a.jPlayer.error=b.extend({},c));d&&(a.jPlayer.warning=b.extend({},d));this.element.trigger(a)},jPlayerFlashEvent:function(a,c){if(a===b.jPlayer.event.ready)if(this.internal.ready){if(this.flash.gate){if(this.status.srcSet){var d=this.status.currentTime,e=this.status.paused;this.setMedia(this.status.media);
+0<d&&(e?this.pause(d):this.play(d))}this._trigger(b.jPlayer.event.flashreset)}}else this.internal.ready=!0,this.internal.flash.jq.css({width:"0px",height:"0px"}),this.version.flash=c.version,this.version.needFlash!==this.version.flash&&this._error({type:b.jPlayer.error.VERSION,context:this.version.flash,message:b.jPlayer.errorMsg.VERSION+this.version.flash,hint:b.jPlayer.errorHint.VERSION}),this._trigger(b.jPlayer.event.repeat),this._trigger(a);if(this.flash.gate)switch(a){case b.jPlayer.event.progress:this._getFlashStatus(c);
+this._updateInterface();this._trigger(a);break;case b.jPlayer.event.timeupdate:this._getFlashStatus(c);this._updateInterface();this._trigger(a);break;case b.jPlayer.event.play:this._seeked();this._updateButtons(!0);this._trigger(a);break;case b.jPlayer.event.pause:this._updateButtons(!1);this._trigger(a);break;case b.jPlayer.event.ended:this._updateButtons(!1);this._trigger(a);break;case b.jPlayer.event.click:this._trigger(a);break;case b.jPlayer.event.error:this.status.waitForLoad=!0;this.status.waitForPlay=
+!0;this.status.video&&this.internal.flash.jq.css({width:"0px",height:"0px"});this._validString(this.status.media.poster)&&this.internal.poster.jq.show();this.css.jq.videoPlay.length&&this.status.video&&this.css.jq.videoPlay.show();this.status.video?this._flash_setVideo(this.status.media):this._flash_setAudio(this.status.media);this._updateButtons(!1);this._error({type:b.jPlayer.error.URL,context:c.src,message:b.jPlayer.errorMsg.URL,hint:b.jPlayer.errorHint.URL});break;case b.jPlayer.event.seeking:this._seeking();
+this._trigger(a);break;case b.jPlayer.event.seeked:this._seeked();this._trigger(a);break;case b.jPlayer.event.ready:break;default:this._trigger(a)}return!1},_getFlashStatus:function(a){this.status.seekPercent=a.seekPercent;this.status.currentPercentRelative=a.currentPercentRelative;this.status.currentPercentAbsolute=a.currentPercentAbsolute;this.status.currentTime=a.currentTime;this.status.duration=a.duration;this.status.videoWidth=a.videoWidth;this.status.videoHeight=a.videoHeight;this.status.readyState=
+4;this.status.networkState=0;this.status.playbackRate=1;this.status.ended=!1},_updateButtons:function(a){a!==f&&(this.status.paused=!a,this.css.jq.play.length&&this.css.jq.pause.length&&(a?(this.css.jq.play.hide(),this.css.jq.pause.show()):(this.css.jq.play.show(),this.css.jq.pause.hide())));this.css.jq.restoreScreen.length&&this.css.jq.fullScreen.length&&(this.status.noFullWindow?(this.css.jq.fullScreen.hide(),this.css.jq.restoreScreen.hide()):this.options.fullWindow?(this.css.jq.fullScreen.hide(),
+this.css.jq.restoreScreen.show()):(this.css.jq.fullScreen.show(),this.css.jq.restoreScreen.hide()));this.css.jq.repeat.length&&this.css.jq.repeatOff.length&&(this.options.loop?(this.css.jq.repeat.hide(),this.css.jq.repeatOff.show()):(this.css.jq.repeat.show(),this.css.jq.repeatOff.hide()))},_updateInterface:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.width(this.status.seekPercent+"%");this.css.jq.playBar.length&&(this.options.smoothPlayBar?this.css.jq.playBar.stop().animate({width:this.status.currentPercentAbsolute+
+"%"},250,"linear"):this.css.jq.playBar.width(this.status.currentPercentRelative+"%"));this.css.jq.currentTime.length&&this.css.jq.currentTime.text(this._convertTime(this.status.currentTime));this.css.jq.duration.length&&this.css.jq.duration.text(this._convertTime(this.status.duration))},_convertTime:l.prototype.time,_seeking:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.addClass("jp-seeking-bg")},_seeked:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.removeClass("jp-seeking-bg")},
+_resetGate:function(){this.html.audio.gate=!1;this.html.video.gate=!1;this.flash.gate=!1},_resetActive:function(){this.html.active=!1;this.flash.active=!1},setMedia:function(a){var c=this,d=!1,e=this.status.media.poster!==a.poster;this._resetMedia();this._resetGate();this._resetActive();b.each(this.formats,function(e,f){var j="video"===c.format[f].media;b.each(c.solutions,function(b,e){if(c[e].support[f]&&c._validString(a[f])){var g="html"===e;j?(g?(c.html.video.gate=!0,c._html_setVideo(a),c.html.active=
+!0):(c.flash.gate=!0,c._flash_setVideo(a),c.flash.active=!0),c.css.jq.videoPlay.length&&c.css.jq.videoPlay.show(),c.status.video=!0):(g?(c.html.audio.gate=!0,c._html_setAudio(a),c.html.active=!0):(c.flash.gate=!0,c._flash_setAudio(a),c.flash.active=!0),c.css.jq.videoPlay.length&&c.css.jq.videoPlay.hide(),c.status.video=!1);d=!0;return!1}});if(d)return!1});if(d){if((!this.status.nativeVideoControls||!this.html.video.gate)&&this._validString(a.poster))e?this.htmlElement.poster.src=a.poster:this.internal.poster.jq.show();
+this.status.srcSet=!0;this.status.media=b.extend({},a);this._updateButtons(!1);this._updateInterface()}else this._error({type:b.jPlayer.error.NO_SUPPORT,context:"{supplied:'"+this.options.supplied+"'}",message:b.jPlayer.errorMsg.NO_SUPPORT,hint:b.jPlayer.errorHint.NO_SUPPORT})},_resetMedia:function(){this._resetStatus();this._updateButtons(!1);this._updateInterface();this._seeked();this.internal.poster.jq.hide();clearTimeout(this.internal.htmlDlyCmdId);this.html.active?this._html_resetMedia():this.flash.active&&
+this._flash_resetMedia()},clearMedia:function(){this._resetMedia();this.html.active?this._html_clearMedia():this.flash.active&&this._flash_clearMedia();this._resetGate();this._resetActive()},load:function(){this.status.srcSet?this.html.active?this._html_load():this.flash.active&&this._flash_load():this._urlNotSetError("load")},focus:function(){this.options.keyEnabled&&(b.jPlayer.focus=this)},play:function(a){a="number"===typeof a?a:NaN;this.status.srcSet?(this.focus(),this.html.active?this._html_play(a):
+this.flash.active&&this._flash_play(a)):this._urlNotSetError("play")},videoPlay:function(){this.play()},pause:function(a){a="number"===typeof a?a:NaN;this.status.srcSet?this.html.active?this._html_pause(a):this.flash.active&&this._flash_pause(a):this._urlNotSetError("pause")},pauseOthers:function(){var a=this;b.each(this.instances,function(b,d){a.element!==d&&d.data("jPlayer").status.srcSet&&d.jPlayer("pause")})},stop:function(){this.status.srcSet?this.html.active?this._html_pause(0):this.flash.active&&
+this._flash_pause(0):this._urlNotSetError("stop")},playHead:function(a){a=this._limitValue(a,0,100);this.status.srcSet?this.html.active?this._html_playHead(a):this.flash.active&&this._flash_playHead(a):this._urlNotSetError("playHead")},_muted:function(a){this.options.muted=a;this.html.used&&this._html_mute(a);this.flash.used&&this._flash_mute(a);!this.html.video.gate&&!this.html.audio.gate&&(this._updateMute(a),this._updateVolume(this.options.volume),this._trigger(b.jPlayer.event.volumechange))},
+mute:function(a){a=a===f?!0:!!a;this._muted(a)},unmute:function(a){a=a===f?!0:!!a;this._muted(!a)},_updateMute:function(a){a===f&&(a=this.options.muted);this.css.jq.mute.length&&this.css.jq.unmute.length&&(this.status.noVolume?(this.css.jq.mute.hide(),this.css.jq.unmute.hide()):a?(this.css.jq.mute.hide(),this.css.jq.unmute.show()):(this.css.jq.mute.show(),this.css.jq.unmute.hide()))},volume:function(a){a=this._limitValue(a,0,1);this.options.volume=a;this.html.used&&this._html_volume(a);this.flash.used&&
+this._flash_volume(a);!this.html.video.gate&&!this.html.audio.gate&&(this._updateVolume(a),this._trigger(b.jPlayer.event.volumechange))},volumeBar:function(a){if(this.css.jq.volumeBar.length){var b=this.css.jq.volumeBar.offset(),d=a.pageX-b.left,e=this.css.jq.volumeBar.width();a=this.css.jq.volumeBar.height()-a.pageY+b.top;b=this.css.jq.volumeBar.height();this.options.verticalVolume?this.volume(a/b):this.volume(d/e)}this.options.muted&&this._muted(!1)},volumeBarValue:function(a){this.volumeBar(a)},
+_updateVolume:function(a){a===f&&(a=this.options.volume);a=this.options.muted?0:a;this.status.noVolume?(this.css.jq.volumeBar.length&&this.css.jq.volumeBar.hide(),this.css.jq.volumeBarValue.length&&this.css.jq.volumeBarValue.hide(),this.css.jq.volumeMax.length&&this.css.jq.volumeMax.hide()):(this.css.jq.volumeBar.length&&this.css.jq.volumeBar.show(),this.css.jq.volumeBarValue.length&&(this.css.jq.volumeBarValue.show(),this.css.jq.volumeBarValue[this.options.verticalVolume?"height":"width"](100*a+
+"%")),this.css.jq.volumeMax.length&&this.css.jq.volumeMax.show())},volumeMax:function(){this.volume(1);this.options.muted&&this._muted(!1)},_cssSelectorAncestor:function(a){var c=this;this.options.cssSelectorAncestor=a;this._removeUiClass();this.ancestorJq=a?b(a):[];a&&1!==this.ancestorJq.length&&this._warning({type:b.jPlayer.warning.CSS_SELECTOR_COUNT,context:a,message:b.jPlayer.warningMsg.CSS_SELECTOR_COUNT+this.ancestorJq.length+" found for cssSelectorAncestor.",hint:b.jPlayer.warningHint.CSS_SELECTOR_COUNT});
+this._addUiClass();b.each(this.options.cssSelector,function(a,b){c._cssSelector(a,b)})},_cssSelector:function(a,c){var d=this;"string"===typeof c?b.jPlayer.prototype.options.cssSelector[a]?(this.css.jq[a]&&this.css.jq[a].length&&this.css.jq[a].unbind(".jPlayer"),this.options.cssSelector[a]=c,this.css.cs[a]=this.options.cssSelectorAncestor+" "+c,this.css.jq[a]=c?b(this.css.cs[a]):[],this.css.jq[a].length&&this.css.jq[a].bind("click.jPlayer",function(c){c.preventDefault();d[a](c);b(this).blur()}),c&&
+1!==this.css.jq[a].length&&this._warning({type:b.jPlayer.warning.CSS_SELECTOR_COUNT,context:this.css.cs[a],message:b.jPlayer.warningMsg.CSS_SELECTOR_COUNT+this.css.jq[a].length+" found for "+a+" method.",hint:b.jPlayer.warningHint.CSS_SELECTOR_COUNT})):this._warning({type:b.jPlayer.warning.CSS_SELECTOR_METHOD,context:a,message:b.jPlayer.warningMsg.CSS_SELECTOR_METHOD,hint:b.jPlayer.warningHint.CSS_SELECTOR_METHOD}):this._warning({type:b.jPlayer.warning.CSS_SELECTOR_STRING,context:c,message:b.jPlayer.warningMsg.CSS_SELECTOR_STRING,
+hint:b.jPlayer.warningHint.CSS_SELECTOR_STRING})},seekBar:function(a){if(this.css.jq.seekBar){var b=this.css.jq.seekBar.offset();a=a.pageX-b.left;b=this.css.jq.seekBar.width();this.playHead(100*a/b)}},playBar:function(a){this.seekBar(a)},repeat:function(){this._loop(!0)},repeatOff:function(){this._loop(!1)},_loop:function(a){this.options.loop!==a&&(this.options.loop=a,this._updateButtons(),this._trigger(b.jPlayer.event.repeat))},currentTime:function(){},duration:function(){},gui:function(){},noSolution:function(){},
+option:function(a,c){var d=a;if(0===arguments.length)return b.extend(!0,{},this.options);if("string"===typeof a){var e=a.split(".");if(c===f){for(var d=b.extend(!0,{},this.options),g=0;g<e.length;g++)if(d[e[g]]!==f)d=d[e[g]];else return this._warning({type:b.jPlayer.warning.OPTION_KEY,context:a,message:b.jPlayer.warningMsg.OPTION_KEY,hint:b.jPlayer.warningHint.OPTION_KEY}),f;return d}for(var g=d={},h=0;h<e.length;h++)h<e.length-1?(g[e[h]]={},g=g[e[h]]):g[e[h]]=c}this._setOptions(d);return this},_setOptions:function(a){var c=
+this;b.each(a,function(a,b){c._setOption(a,b)});return this},_setOption:function(a,c){var d=this;switch(a){case "volume":this.volume(c);break;case "muted":this._muted(c);break;case "cssSelectorAncestor":this._cssSelectorAncestor(c);break;case "cssSelector":b.each(c,function(a,b){d._cssSelector(a,b)});break;case "fullScreen":if(this.options[a]!==c){var e=b.jPlayer.nativeFeatures.fullscreen.used.webkitVideo;if(!e||e&&!this.status.waitForPlay)e||(this.options[a]=c),c?this._requestFullscreen():this._exitFullscreen(),
+e||this._setOption("fullWindow",c)}break;case "fullWindow":this.options[a]!==c&&(this._removeUiClass(),this.options[a]=c,this._refreshSize());break;case "size":!this.options.fullWindow&&this.options[a].cssClass!==c.cssClass&&this._removeUiClass();this.options[a]=b.extend({},this.options[a],c);this._refreshSize();break;case "sizeFull":this.options.fullWindow&&this.options[a].cssClass!==c.cssClass&&this._removeUiClass();this.options[a]=b.extend({},this.options[a],c);this._refreshSize();break;case "autohide":this.options[a]=
+b.extend({},this.options[a],c);this._updateAutohide();break;case "loop":this._loop(c);break;case "nativeVideoControls":this.options[a]=b.extend({},this.options[a],c);this.status.nativeVideoControls=this._uaBlocklist(this.options.nativeVideoControls);this._restrictNativeVideoControls();this._updateNativeVideoControls();break;case "noFullWindow":this.options[a]=b.extend({},this.options[a],c);this.status.nativeVideoControls=this._uaBlocklist(this.options.nativeVideoControls);this.status.noFullWindow=
+this._uaBlocklist(this.options.noFullWindow);this._restrictNativeVideoControls();this._updateButtons();break;case "noVolume":this.options[a]=b.extend({},this.options[a],c);this.status.noVolume=this._uaBlocklist(this.options.noVolume);this._updateVolume();this._updateMute();break;case "emulateHtml":this.options[a]!==c&&((this.options[a]=c)?this._emulateHtmlBridge():this._destroyHtmlBridge());break;case "timeFormat":this.options[a]=b.extend({},this.options[a],c);break;case "keyEnabled":this.options[a]=
+c;!c&&this===b.jPlayer.focus&&(b.jPlayer.focus=null);break;case "keyBindings":this.options[a]=b.extend(!0,{},this.options[a],c);break;case "audioFullScreen":this.options[a]=c}return this},_refreshSize:function(){this._setSize();this._addUiClass();this._updateSize();this._updateButtons();this._updateAutohide();this._trigger(b.jPlayer.event.resize)},_setSize:function(){this.options.fullWindow?(this.status.width=this.options.sizeFull.width,this.status.height=this.options.sizeFull.height,this.status.cssClass=
+this.options.sizeFull.cssClass):(this.status.width=this.options.size.width,this.status.height=this.options.size.height,this.status.cssClass=this.options.size.cssClass);this.element.css({width:this.status.width,height:this.status.height})},_addUiClass:function(){this.ancestorJq.length&&this.ancestorJq.addClass(this.status.cssClass)},_removeUiClass:function(){this.ancestorJq.length&&this.ancestorJq.removeClass(this.status.cssClass)},_updateSize:function(){this.internal.poster.jq.css({width:this.status.width,
+height:this.status.height});!this.status.waitForPlay&&this.html.active&&this.status.video||this.html.video.available&&this.html.used&&this.status.nativeVideoControls?this.internal.video.jq.css({width:this.status.width,height:this.status.height}):!this.status.waitForPlay&&(this.flash.active&&this.status.video)&&this.internal.flash.jq.css({width:this.status.width,height:this.status.height})},_updateAutohide:function(){var a=this,b=function(){a.css.jq.gui.fadeIn(a.options.autohide.fadeIn,function(){clearTimeout(a.internal.autohideId);
+a.internal.autohideId=setTimeout(function(){a.css.jq.gui.fadeOut(a.options.autohide.fadeOut)},a.options.autohide.hold)})};this.css.jq.gui.length&&(this.css.jq.gui.stop(!0,!0),clearTimeout(this.internal.autohideId),this.element.unbind(".jPlayerAutohide"),this.css.jq.gui.unbind(".jPlayerAutohide"),this.status.nativeVideoControls?this.css.jq.gui.hide():this.options.fullWindow&&this.options.autohide.full||!this.options.fullWindow&&this.options.autohide.restored?(this.element.bind("mousemove.jPlayer.jPlayerAutohide",
+b),this.css.jq.gui.bind("mousemove.jPlayer.jPlayerAutohide",b),this.css.jq.gui.hide()):this.css.jq.gui.show())},fullScreen:function(){this._setOption("fullScreen",!0)},restoreScreen:function(){this._setOption("fullScreen",!1)},_fullscreenAddEventListeners:function(){var a=this,c=b.jPlayer.nativeFeatures.fullscreen;c.api.fullscreenEnabled&&c.event.fullscreenchange&&("function"!==typeof this.internal.fullscreenchangeHandler&&(this.internal.fullscreenchangeHandler=function(){a._fullscreenchange()}),
+document.addEventListener(c.event.fullscreenchange,this.internal.fullscreenchangeHandler,!1))},_fullscreenRemoveEventListeners:function(){var a=b.jPlayer.nativeFeatures.fullscreen;this.internal.fullscreenchangeHandler&&document.addEventListener(a.event.fullscreenchange,this.internal.fullscreenchangeHandler,!1)},_fullscreenchange:function(){this.options.fullScreen&&!b.jPlayer.nativeFeatures.fullscreen.api.fullscreenElement()&&this._setOption("fullScreen",!1)},_requestFullscreen:function(){var a=this.ancestorJq.length?
+this.ancestorJq[0]:this.element[0],c=b.jPlayer.nativeFeatures.fullscreen;c.used.webkitVideo&&(a=this.htmlElement.video);c.api.fullscreenEnabled&&c.api.requestFullscreen(a)},_exitFullscreen:function(){var a=b.jPlayer.nativeFeatures.fullscreen,c;a.used.webkitVideo&&(c=this.htmlElement.video);a.api.fullscreenEnabled&&a.api.exitFullscreen(c)},_html_initMedia:function(a){var c=b(this.htmlElement.media).empty();b.each(a.track||[],function(a,b){var g=document.createElement("track");g.setAttribute("kind",
+b.kind?b.kind:"");g.setAttribute("src",b.src?b.src:"");g.setAttribute("srclang",b.srclang?b.srclang:"");g.setAttribute("label",b.label?b.label:"");b.def&&g.setAttribute("default",b.def);c.append(g)});this.htmlElement.media.src=this.status.src;"none"!==this.options.preload&&this._html_load();this._trigger(b.jPlayer.event.timeupdate)},_html_setFormat:function(a){var c=this;b.each(this.formats,function(b,e){if(c.html.support[e]&&a[e])return c.status.src=a[e],c.status.format[e]=!0,c.status.formatType=
+e,!1})},_html_setAudio:function(a){this._html_setFormat(a);this.htmlElement.media=this.htmlElement.audio;this._html_initMedia(a)},_html_setVideo:function(a){this._html_setFormat(a);this.status.nativeVideoControls&&(this.htmlElement.video.poster=this._validString(a.poster)?a.poster:"");this.htmlElement.media=this.htmlElement.video;this._html_initMedia(a)},_html_resetMedia:function(){this.htmlElement.media&&(this.htmlElement.media.id===this.internal.video.id&&!this.status.nativeVideoControls&&this.internal.video.jq.css({width:"0px",
+height:"0px"}),this.htmlElement.media.pause())},_html_clearMedia:function(){this.htmlElement.media&&(this.htmlElement.media.src="about:blank",this.htmlElement.media.load())},_html_load:function(){this.status.waitForLoad&&(this.status.waitForLoad=!1,this.htmlElement.media.load());clearTimeout(this.internal.htmlDlyCmdId)},_html_play:function(a){var b=this,d=this.htmlElement.media;this._html_load();if(isNaN(a))d.play();else{this.internal.cmdsIgnored&&d.play();try{if(!d.seekable||"object"===typeof d.seekable&&
+0<d.seekable.length)d.currentTime=a,d.play();else throw 1;}catch(e){this.internal.htmlDlyCmdId=setTimeout(function(){b.play(a)},250);return}}this._html_checkWaitForPlay()},_html_pause:function(a){var b=this,d=this.htmlElement.media;0<a?this._html_load():clearTimeout(this.internal.htmlDlyCmdId);d.pause();if(!isNaN(a))try{if(!d.seekable||"object"===typeof d.seekable&&0<d.seekable.length)d.currentTime=a;else throw 1;}catch(e){this.internal.htmlDlyCmdId=setTimeout(function(){b.pause(a)},250);return}0<
+a&&this._html_checkWaitForPlay()},_html_playHead:function(a){var b=this,d=this.htmlElement.media;this._html_load();try{if("object"===typeof d.seekable&&0<d.seekable.length)d.currentTime=a*d.seekable.end(d.seekable.length-1)/100;else if(0<d.duration&&!isNaN(d.duration))d.currentTime=a*d.duration/100;else throw"e";}catch(e){this.internal.htmlDlyCmdId=setTimeout(function(){b.playHead(a)},250);return}this.status.waitForLoad||this._html_checkWaitForPlay()},_html_checkWaitForPlay:function(){this.status.waitForPlay&&
+(this.status.waitForPlay=!1,this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide(),this.status.video&&(this.internal.poster.jq.hide(),this.internal.video.jq.css({width:this.status.width,height:this.status.height})))},_html_volume:function(a){this.html.audio.available&&(this.htmlElement.audio.volume=a);this.html.video.available&&(this.htmlElement.video.volume=a)},_html_mute:function(a){this.html.audio.available&&(this.htmlElement.audio.muted=a);this.html.video.available&&(this.htmlElement.video.muted=
+a)},_flash_setAudio:function(a){var c=this;try{b.each(this.formats,function(b,d){if(c.flash.support[d]&&a[d]){switch(d){case "m4a":case "fla":c._getMovie().fl_setAudio_m4a(a[d]);break;case "mp3":c._getMovie().fl_setAudio_mp3(a[d]);break;case "rtmpa":c._getMovie().fl_setAudio_rtmp(a[d])}c.status.src=a[d];c.status.format[d]=!0;c.status.formatType=d;return!1}}),"auto"===this.options.preload&&(this._flash_load(),this.status.waitForLoad=!1)}catch(d){this._flashError(d)}},_flash_setVideo:function(a){var c=
+this;try{b.each(this.formats,function(b,d){if(c.flash.support[d]&&a[d]){switch(d){case "m4v":case "flv":c._getMovie().fl_setVideo_m4v(a[d]);break;case "rtmpv":c._getMovie().fl_setVideo_rtmp(a[d])}c.status.src=a[d];c.status.format[d]=!0;c.status.formatType=d;return!1}}),"auto"===this.options.preload&&(this._flash_load(),this.status.waitForLoad=!1)}catch(d){this._flashError(d)}},_flash_resetMedia:function(){this.internal.flash.jq.css({width:"0px",height:"0px"});this._flash_pause(NaN)},_flash_clearMedia:function(){try{this._getMovie().fl_clearMedia()}catch(a){this._flashError(a)}},
+_flash_load:function(){try{this._getMovie().fl_load()}catch(a){this._flashError(a)}this.status.waitForLoad=!1},_flash_play:function(a){try{this._getMovie().fl_play(a)}catch(b){this._flashError(b)}this.status.waitForLoad=!1;this._flash_checkWaitForPlay()},_flash_pause:function(a){try{this._getMovie().fl_pause(a)}catch(b){this._flashError(b)}0<a&&(this.status.waitForLoad=!1,this._flash_checkWaitForPlay())},_flash_playHead:function(a){try{this._getMovie().fl_play_head(a)}catch(b){this._flashError(b)}this.status.waitForLoad||
+this._flash_checkWaitForPlay()},_flash_checkWaitForPlay:function(){this.status.waitForPlay&&(this.status.waitForPlay=!1,this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide(),this.status.video&&(this.internal.poster.jq.hide(),this.internal.flash.jq.css({width:this.status.width,height:this.status.height})))},_flash_volume:function(a){try{this._getMovie().fl_volume(a)}catch(b){this._flashError(b)}},_flash_mute:function(a){try{this._getMovie().fl_mute(a)}catch(b){this._flashError(b)}},_getMovie:function(){return document[this.internal.flash.id]},
+_getFlashPluginVersion:function(){var a=0,b;if(window.ActiveXObject)try{if(b=new ActiveXObject("ShockwaveFlash.ShockwaveFlash")){var d=b.GetVariable("$version");d&&(d=d.split(" ")[1].split(","),a=parseInt(d[0],10)+"."+parseInt(d[1],10))}}catch(e){}else navigator.plugins&&0<navigator.mimeTypes.length&&(b=navigator.plugins["Shockwave Flash"])&&(a=navigator.plugins["Shockwave Flash"].description.replace(/.*\s(\d+\.\d+).*/,"$1"));return 1*a},_checkForFlash:function(a){var b=!1;this._getFlashPluginVersion()>=
+a&&(b=!0);return b},_validString:function(a){return a&&"string"===typeof a},_limitValue:function(a,b,d){return a<b?b:a>d?d:a},_urlNotSetError:function(a){this._error({type:b.jPlayer.error.URL_NOT_SET,context:a,message:b.jPlayer.errorMsg.URL_NOT_SET,hint:b.jPlayer.errorHint.URL_NOT_SET})},_flashError:function(a){var c;c=this.internal.ready?"FLASH_DISABLED":"FLASH";this._error({type:b.jPlayer.error[c],context:this.internal.flash.swf,message:b.jPlayer.errorMsg[c]+a.message,hint:b.jPlayer.errorHint[c]});
+this.internal.flash.jq.css({width:"1px",height:"1px"})},_error:function(a){this._trigger(b.jPlayer.event.error,a);this.options.errorAlerts&&this._alert("Error!"+(a.message?"\n\n"+a.message:"")+(a.hint?"\n\n"+a.hint:"")+"\n\nContext: "+a.context)},_warning:function(a){this._trigger(b.jPlayer.event.warning,f,a);this.options.warningAlerts&&this._alert("Warning!"+(a.message?"\n\n"+a.message:"")+(a.hint?"\n\n"+a.hint:"")+"\n\nContext: "+a.context)},_alert:function(a){alert("jPlayer "+this.version.script+
+" : id='"+this.internal.self.id+"' : "+a)},_emulateHtmlBridge:function(){var a=this;b.each(b.jPlayer.emulateMethods.split(/\s+/g),function(b,d){a.internal.domNode[d]=function(b){a[d](b)}});b.each(b.jPlayer.event,function(c,d){var e=!0;b.each(b.jPlayer.reservedEvent.split(/\s+/g),function(a,b){if(b===c)return e=!1});e&&a.element.bind(d+".jPlayer.jPlayerHtml",function(){a._emulateHtmlUpdate();var b=document.createEvent("Event");b.initEvent(c,!1,!0);a.internal.domNode.dispatchEvent(b)})})},_emulateHtmlUpdate:function(){var a=
+this;b.each(b.jPlayer.emulateStatus.split(/\s+/g),function(b,d){a.internal.domNode[d]=a.status[d]});b.each(b.jPlayer.emulateOptions.split(/\s+/g),function(b,d){a.internal.domNode[d]=a.options[d]})},_destroyHtmlBridge:function(){var a=this;this.element.unbind(".jPlayerHtml");b.each((b.jPlayer.emulateMethods+" "+b.jPlayer.emulateStatus+" "+b.jPlayer.emulateOptions).split(/\s+/g),function(b,d){delete a.internal.domNode[d]})}};b.jPlayer.error={FLASH:"e_flash",FLASH_DISABLED:"e_flash_disabled",NO_SOLUTION:"e_no_solution",
+NO_SUPPORT:"e_no_support",URL:"e_url",URL_NOT_SET:"e_url_not_set",VERSION:"e_version"};b.jPlayer.errorMsg={FLASH:"jPlayer's Flash fallback is not configured correctly, or a command was issued before the jPlayer Ready event. Details: ",FLASH_DISABLED:"jPlayer's Flash fallback has been disabled by the browser due to the CSS rules you have used. Details: ",NO_SOLUTION:"No solution can be found by jPlayer in this browser. Neither HTML nor Flash can be used.",NO_SUPPORT:"It is not possible to play any media format provided in setMedia() on this browser using your current options.",
+URL:"Media URL could not be loaded.",URL_NOT_SET:"Attempt to issue media playback commands, while no media url is set.",VERSION:"jPlayer "+b.jPlayer.prototype.version.script+" needs Jplayer.swf version "+b.jPlayer.prototype.version.needFlash+" but found "};b.jPlayer.errorHint={FLASH:"Check your swfPath option and that Jplayer.swf is there.",FLASH_DISABLED:"Check that you have not display:none; the jPlayer entity or any ancestor.",NO_SOLUTION:"Review the jPlayer options: support and supplied.",NO_SUPPORT:"Video or audio formats defined in the supplied option are missing.",
+URL:"Check media URL is valid.",URL_NOT_SET:"Use setMedia() to set the media URL.",VERSION:"Update jPlayer files."};b.jPlayer.warning={CSS_SELECTOR_COUNT:"e_css_selector_count",CSS_SELECTOR_METHOD:"e_css_selector_method",CSS_SELECTOR_STRING:"e_css_selector_string",OPTION_KEY:"e_option_key"};b.jPlayer.warningMsg={CSS_SELECTOR_COUNT:"The number of css selectors found did not equal one: ",CSS_SELECTOR_METHOD:"The methodName given in jPlayer('cssSelector') is not a valid jPlayer method.",CSS_SELECTOR_STRING:"The methodCssSelector given in jPlayer('cssSelector') is not a String or is empty.",
+OPTION_KEY:"The option requested in jPlayer('option') is undefined."};b.jPlayer.warningHint={CSS_SELECTOR_COUNT:"Check your css selector and the ancestor.",CSS_SELECTOR_METHOD:"Check your method name.",CSS_SELECTOR_STRING:"Check your css selector is a string.",OPTION_KEY:"Check your option name."}}); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.css b/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.css
new file mode 100644
index 00000000..9b639734
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.css
@@ -0,0 +1,640 @@
+/*
+ * Skin for jPlayer Plugin (jQuery JavaScript Library)
+ * http://www.jplayer.org
+ *
+ * Skin Name: Blue Monday
+ *
+ * Copyright (c) 2010-2012 Happyworm Ltd
+ * Dual licensed under the MIT and GPL licenses.
+ * - http://www.opensource.org/licenses/mit-license.php
+ * - http://www.gnu.org/copyleft/gpl.html
+ *
+ * Author: Silvia Benvenuti
+ * Skin Version: 4.2 (jPlayer 2.2.0)
+ * Date: 22nd October 2012
+ */
+
+div.jp-audio,
+div.jp-audio-stream,
+div.jp-video {
+
+ /* Edit the font-size to counteract inherited font sizing.
+ * Eg. 1.25em = 1 / 0.8em
+ */
+
+ font-size:1.25em; /* 1.25em for testing in site pages */ /* No parent CSS that can effect the size in the demos ZIP */
+
+ font-family:Verdana, Arial, sans-serif;
+ line-height:1.6;
+ color: #666;
+ border:1px solid #009be3;
+ background-color:#eee;
+}
+div.jp-audio {
+ width:420px;
+}
+div.jp-audio-stream {
+ width:182px;
+}
+div.jp-video-270p {
+ width:480px;
+}
+div.jp-video-360p {
+ width:640px;
+}
+div.jp-video-full {
+ /* Rules for IE6 (full-screen) */
+ width:480px;
+ height:270px;
+ /* Rules for IE7 (full-screen) - Otherwise the relative container causes other page items that are not position:static (default) to appear over the video/gui. */
+ position:static !important; position:relative
+}
+
+/* The z-index rule is defined in this manner to enable Popcorn plugins that add overlays to video area. EG. Subtitles. */
+div.jp-video-full div div {
+ z-index:1000;
+}
+
+div.jp-video-full div.jp-jplayer {
+ top: 0;
+ left: 0;
+ position: fixed !important; position: relative; /* Rules for IE6 (full-screen) */
+ overflow: hidden;
+}
+
+div.jp-video-full div.jp-gui {
+ position: fixed !important; position: static; /* Rules for IE6 (full-screen) */
+ top: 0;
+ left: 0;
+ width:100%;
+ height:100%;
+ z-index:1001; /* 1 layer above the others. */
+}
+
+div.jp-video-full div.jp-interface {
+ position: absolute !important; position: relative; /* Rules for IE6 (full-screen) */
+ bottom: 0;
+ left: 0;
+}
+
+div.jp-interface {
+ position: relative;
+ background-color:#eee;
+ width:100%;
+}
+
+div.jp-audio div.jp-type-single div.jp-interface {
+ height:80px;
+}
+div.jp-audio div.jp-type-playlist div.jp-interface {
+ height:80px;
+}
+
+div.jp-audio-stream div.jp-type-single div.jp-interface {
+ height:80px;
+}
+
+div.jp-video div.jp-interface {
+ border-top:1px solid #009be3;
+}
+
+/* @group CONTROLS */
+
+div.jp-controls-holder {
+ clear: both;
+ width:440px;
+ margin:0 auto;
+ position: relative;
+ overflow:hidden;
+ top:-8px; /* This negative value depends on the size of the text in jp-currentTime and jp-duration */
+}
+
+div.jp-interface ul.jp-controls {
+ list-style-type:none;
+ margin:0;
+ padding: 0;
+ overflow:hidden;
+}
+
+div.jp-audio ul.jp-controls {
+ width: 380px;
+ padding:20px 20px 0 20px;
+}
+
+div.jp-audio-stream ul.jp-controls {
+ width: 142px;
+ padding:20px 20px 0 20px;
+}
+
+div.jp-video div.jp-type-single ul.jp-controls {
+ width: 78px;
+ margin-left: 200px;
+}
+
+div.jp-video div.jp-type-playlist ul.jp-controls {
+ width: 134px;
+ margin-left: 172px;
+}
+div.jp-video ul.jp-controls,
+div.jp-interface ul.jp-controls li {
+ display:inline;
+ float: left;
+}
+
+div.jp-interface ul.jp-controls a {
+ display:block;
+ overflow:hidden;
+ text-indent:-9999px;
+}
+a.jp-play,
+a.jp-pause {
+ width:40px;
+ height:40px;
+}
+
+a.jp-play {
+ background: url("jplayer.blue.monday.jpg") 0 0 no-repeat;
+}
+a.jp-play:hover {
+ background: url("jplayer.blue.monday.jpg") -41px 0 no-repeat;
+}
+a.jp-pause {
+ background: url("jplayer.blue.monday.jpg") 0 -42px no-repeat;
+ display: none;
+}
+a.jp-pause:hover {
+ background: url("jplayer.blue.monday.jpg") -41px -42px no-repeat;
+}
+
+a.jp-stop, a.jp-previous, a.jp-next {
+ width:28px;
+ height:28px;
+ margin-top:6px;
+}
+
+a.jp-stop {
+ background: url("jplayer.blue.monday.jpg") 0 -83px no-repeat;
+ margin-left:10px;
+}
+
+a.jp-stop:hover {
+ background: url("jplayer.blue.monday.jpg") -29px -83px no-repeat;
+}
+
+a.jp-previous {
+ background: url("jplayer.blue.monday.jpg") 0 -112px no-repeat;
+}
+a.jp-previous:hover {
+ background: url("jplayer.blue.monday.jpg") -29px -112px no-repeat;
+}
+
+a.jp-next {
+ background: url("jplayer.blue.monday.jpg") 0 -141px no-repeat;
+}
+a.jp-next:hover {
+ background: url("jplayer.blue.monday.jpg") -29px -141px no-repeat;
+}
+
+/* @end */
+
+/* @group progress bar */
+
+div.jp-progress {
+ overflow:hidden;
+ background-color: #ddd;
+}
+div.jp-audio div.jp-progress {
+ position: absolute;
+ top:32px;
+ height:15px;
+}
+div.jp-audio div.jp-type-single div.jp-progress {
+ left:110px;
+ width:186px;
+}
+div.jp-audio div.jp-type-playlist div.jp-progress {
+ left:166px;
+ width:130px;
+}
+div.jp-video div.jp-progress {
+ top:0px;
+ left:0px;
+ width:100%;
+ height:10px;
+}
+div.jp-seek-bar {
+ background: url("jplayer.blue.monday.jpg") 0 -202px repeat-x;
+ width:0px;
+ height:100%;
+ cursor: pointer;
+}
+div.jp-play-bar {
+ background: url("jplayer.blue.monday.jpg") 0 -218px repeat-x ;
+ width:0px;
+ height:100%;
+}
+
+/* The seeking class is added/removed inside jPlayer */
+div.jp-seeking-bg {
+ background: url("jplayer.blue.monday.seeking.gif");
+}
+
+/* @end */
+
+/* @group volume controls */
+
+
+a.jp-mute,
+a.jp-unmute,
+a.jp-volume-max {
+ width:18px;
+ height:15px;
+ margin-top:12px;
+}
+
+div.jp-audio div.jp-type-single a.jp-mute,
+div.jp-audio div.jp-type-single a.jp-unmute {
+ margin-left: 210px;
+}
+div.jp-audio div.jp-type-playlist a.jp-mute,
+div.jp-audio div.jp-type-playlist a.jp-unmute {
+ margin-left: 154px;
+}
+
+div.jp-audio-stream div.jp-type-single a.jp-mute,
+div.jp-audio-stream div.jp-type-single a.jp-unmute {
+ margin-left:10px;
+}
+
+div.jp-audio a.jp-volume-max,
+div.jp-audio-stream a.jp-volume-max {
+ margin-left: 56px;
+}
+
+div.jp-video a.jp-mute,
+div.jp-video a.jp-unmute,
+div.jp-video a.jp-volume-max {
+ position: absolute;
+ top:12px;
+ margin-top:0;
+}
+
+div.jp-video a.jp-mute,
+div.jp-video a.jp-unmute {
+ left: 50px;
+}
+
+div.jp-video a.jp-volume-max {
+ left: 134px;
+}
+
+a.jp-mute {
+ background: url("jplayer.blue.monday.jpg") 0 -170px no-repeat;
+}
+a.jp-mute:hover {
+ background: url("jplayer.blue.monday.jpg") -19px -170px no-repeat;
+}
+a.jp-unmute {
+ background: url("jplayer.blue.monday.jpg") -60px -170px no-repeat;
+ display: none;
+}
+a.jp-unmute:hover {
+ background: url("jplayer.blue.monday.jpg") -79px -170px no-repeat;
+}
+a.jp-volume-max {
+ background: url("jplayer.blue.monday.jpg") 0 -186px no-repeat;
+}
+a.jp-volume-max:hover {
+ background: url("jplayer.blue.monday.jpg") -19px -186px no-repeat;
+}
+
+div.jp-volume-bar {
+ position: absolute;
+ overflow:hidden;
+ background: url("jplayer.blue.monday.jpg") 0 -250px repeat-x;
+ width:46px;
+ height:5px;
+ cursor: pointer;
+}
+div.jp-audio div.jp-volume-bar {
+ top:37px;
+ left:330px;
+}
+div.jp-audio-stream div.jp-volume-bar {
+ top:37px;
+ left:92px;
+}
+div.jp-video div.jp-volume-bar {
+ top:17px;
+ left:72px;
+}
+div.jp-volume-bar-value {
+ background: url("jplayer.blue.monday.jpg") 0 -256px repeat-x;
+ width:0px;
+ height:5px;
+}
+
+/* @end */
+
+/* @group current time and duration */
+
+div.jp-audio div.jp-time-holder {
+ position:absolute;
+ top:50px;
+}
+div.jp-audio div.jp-type-single div.jp-time-holder {
+ left:110px;
+ width:186px;
+}
+div.jp-audio div.jp-type-playlist div.jp-time-holder {
+ left:166px;
+ width:130px;
+}
+
+div.jp-current-time,
+div.jp-duration {
+ width:60px;
+ font-size:.64em;
+ font-style:oblique;
+}
+div.jp-current-time {
+ float: left;
+ display:inline;
+}
+div.jp-duration {
+ float: right;
+ display:inline;
+ text-align: right;
+}
+
+div.jp-video div.jp-current-time {
+ margin-left:20px;
+}
+div.jp-video div.jp-duration {
+ margin-right:20px;
+}
+
+/* @end */
+
+/* @group playlist */
+
+div.jp-title {
+ font-weight:bold;
+ text-align:center;
+}
+
+div.jp-title,
+div.jp-playlist {
+ width:100%;
+ background-color:#ccc;
+ border-top:1px solid #009be3;
+}
+div.jp-type-single div.jp-title,
+div.jp-type-playlist div.jp-title,
+div.jp-type-single div.jp-playlist {
+ border-top:none;
+}
+div.jp-title ul,
+div.jp-playlist ul {
+ list-style-type:none;
+ margin:0;
+ padding:0 20px;
+ font-size:.72em;
+}
+
+div.jp-title li {
+ padding:5px 0;
+ font-weight:bold;
+}
+div.jp-playlist li {
+ padding:5px 0 4px 20px;
+ border-bottom:1px solid #eee;
+}
+
+div.jp-playlist li div {
+ display:inline;
+}
+
+/* Note that the first-child (IE6) and last-child (IE6/7/8) selectors do not work on IE */
+
+div.jp-type-playlist div.jp-playlist li:last-child {
+ padding:5px 0 5px 20px;
+ border-bottom:none;
+}
+div.jp-type-playlist div.jp-playlist li.jp-playlist-current {
+ list-style-type:square;
+ list-style-position:inside;
+ padding-left:7px;
+}
+div.jp-type-playlist div.jp-playlist a {
+ color: #333;
+ text-decoration: none;
+}
+div.jp-type-playlist div.jp-playlist a:hover {
+ color:#0d88c1;
+}
+div.jp-type-playlist div.jp-playlist a.jp-playlist-current {
+ color:#0d88c1;
+}
+
+div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove {
+ float:right;
+ display:inline;
+ text-align:right;
+ margin-right:10px;
+ font-weight:bold;
+ color:#666;
+}
+div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove:hover {
+ color:#0d88c1;
+}
+div.jp-type-playlist div.jp-playlist span.jp-free-media {
+ float:right;
+ display:inline;
+ text-align:right;
+ margin-right:10px;
+}
+div.jp-type-playlist div.jp-playlist span.jp-free-media a{
+ color:#666;
+}
+div.jp-type-playlist div.jp-playlist span.jp-free-media a:hover{
+ color:#0d88c1;
+}
+span.jp-artist {
+ font-size:.8em;
+ color:#666;
+}
+
+/* @end */
+
+div.jp-video-play {
+ width:100%;
+ overflow:hidden; /* Important for nested negative margins to work in modern browsers */
+ cursor:pointer;
+ background-color:rgba(0,0,0,0); /* Makes IE9 work with the active area over the whole video area. IE6/7/8 only have the button as active area. */
+}
+div.jp-video-270p div.jp-video-play {
+ margin-top:-270px;
+ height:270px;
+}
+div.jp-video-360p div.jp-video-play {
+ margin-top:-360px;
+ height:360px;
+}
+div.jp-video-full div.jp-video-play {
+ height:100%;
+}
+a.jp-video-play-icon {
+ position:relative;
+ display:block;
+ width: 112px;
+ height: 100px;
+
+ margin-left:-56px;
+ margin-top:-50px;
+ left:50%;
+ top:50%;
+
+ background: url("jplayer.blue.monday.video.play.png") 0 0 no-repeat;
+ text-indent:-9999px;
+}
+div.jp-video-play:hover a.jp-video-play-icon {
+ background: url("jplayer.blue.monday.video.play.png") 0 -100px no-repeat;
+}
+
+
+
+
+
+div.jp-jplayer audio,
+div.jp-jplayer {
+ width:0px;
+ height:0px;
+}
+
+div.jp-jplayer {
+ background-color: #000000;
+}
+
+
+
+
+
+/* @group TOGGLES */
+
+/* The audio toggles are nested inside jp-time-holder */
+
+ul.jp-toggles {
+ list-style-type:none;
+ padding:0;
+ margin:0 auto;
+ overflow:hidden;
+}
+
+div.jp-audio .jp-type-single ul.jp-toggles {
+ width:25px;
+}
+div.jp-audio .jp-type-playlist ul.jp-toggles {
+ width:55px;
+ margin: 0;
+ position: absolute;
+ left: 325px;
+ top: 50px;
+}
+
+div.jp-video ul.jp-toggles {
+ margin-top:10px;
+ width:100px;
+}
+
+ul.jp-toggles li {
+ display:block;
+ float:right;
+}
+
+ul.jp-toggles li a {
+ display:block;
+ width:25px;
+ height:18px;
+ text-indent:-9999px;
+ line-height:100%; /* need this for IE6 */
+}
+
+a.jp-full-screen {
+ background: url("jplayer.blue.monday.jpg") 0 -310px no-repeat;
+ margin-left: 20px;
+}
+
+a.jp-full-screen:hover {
+ background: url("jplayer.blue.monday.jpg") -30px -310px no-repeat;
+}
+
+a.jp-restore-screen {
+ background: url("jplayer.blue.monday.jpg") -60px -310px no-repeat;
+ margin-left: 20px;
+}
+
+a.jp-restore-screen:hover {
+ background: url("jplayer.blue.monday.jpg") -90px -310px no-repeat;
+}
+
+a.jp-repeat {
+ background: url("jplayer.blue.monday.jpg") 0 -290px no-repeat;
+}
+
+a.jp-repeat:hover {
+ background: url("jplayer.blue.monday.jpg") -30px -290px no-repeat;
+}
+
+a.jp-repeat-off {
+ background: url("jplayer.blue.monday.jpg") -60px -290px no-repeat;
+}
+
+a.jp-repeat-off:hover {
+ background: url("jplayer.blue.monday.jpg") -90px -290px no-repeat;
+}
+
+a.jp-shuffle {
+ background: url("jplayer.blue.monday.jpg") 0 -270px no-repeat;
+ margin-left: 5px;
+}
+
+a.jp-shuffle:hover {
+ background: url("jplayer.blue.monday.jpg") -30px -270px no-repeat;
+}
+
+a.jp-shuffle-off {
+ background: url("jplayer.blue.monday.jpg") -60px -270px no-repeat;
+ margin-left: 5px;
+}
+
+a.jp-shuffle-off:hover {
+ background: url("jplayer.blue.monday.jpg") -90px -270px no-repeat;
+}
+
+
+/* @end */
+
+/* @group NO SOLUTION error feedback */
+
+.jp-no-solution {
+ padding:5px;
+ font-size:.8em;
+ background-color:#eee;
+ border:2px solid #009be3;
+ color:#000;
+ display:none;
+}
+
+.jp-no-solution a {
+ color:#000;
+}
+
+.jp-no-solution span {
+ font-size:1em;
+ display:block;
+ text-align:center;
+ font-weight:bold;
+}
+
+/* @end */
diff --git a/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.jpg b/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.jpg
new file mode 100644
index 00000000..adab53ff
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.jpg
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.seeking.gif b/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.seeking.gif
new file mode 100644
index 00000000..dbd2105a
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.seeking.gif
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.video.play.png b/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.video.play.png
new file mode 100644
index 00000000..8e97df01
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/skin/blue.monday/jplayer.blue.monday.video.play.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/README.morning.light.md b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/README.morning.light.md
new file mode 100644
index 00000000..5587d7f4
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/README.morning.light.md
@@ -0,0 +1,29 @@
+Morning Light
+=========
+Quite a while ago, I found this great jPlayer skin on GitHub. It was nice, simple, and great looking! But what I soon found out was that it was only for jPlayer 2.0.0. That got me thinking, "Hey! Why don't I update it?!". And I did just that!
+
+It actually ended up looking pretty good :D
+
+Compatibility
+=========
+Morning Light will support any jPlayer version from 2.1.0 all the way to the current developmental build. I recommend you keep up to date on your jPlayer installation. Morning Light also uses some CSS3 features such as *border-radius*, *text-shadow*, and *box-shadow* (specifically *box-shdaow: inset*) so it won't show up in IE8 or lower. If you want, you can use [CSS3PIE](http://css3pie.com/) to enable *border-radius* in IE8 and lower but *text-shadow* and *box-shadow: inset* are still a WIP. I'll add support for CSS3PIE as soon as they add more functionality to it.
+
+Licensing
+=========
+This is skin is dual licensed under the MIT and GPL licenses.
+* http://www.opensource.org/licenses/mit-license.php
+* http://www.gnu.org/copyleft/gpl.html
+
+Authors and Contributors
+=========
+This skin was originally created by [persand](https://github.com/persand). He made it for jPlayer 2.0.0 and I simply updated the CSS and added a few more images. I only take 40% credit for this work.
+
+The orginal theme for jPlayer 2.0.0 can be found here - https://github.com/persand/jPlayer-skins
+
+Support or Contact
+=========
+If you are having issues with the skin, please feel free to post in the [Issues](https://github.com/TheInfection/Morning-Light/issues) section on the GitHub repository. I will try my hardest to respond and solve all of your problems.
+
+Also Check Out Midnight Black!
+=========
+If you want a darker jPlayer skin, go check out Midnight Black! - http://theinfection.github.com/Midnight-Black/ \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.css b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.css
new file mode 100644
index 00000000..7ed33c48
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.css
@@ -0,0 +1,749 @@
+/*
+ * Skin for jPlayer Plugin (jQuery JavaScript Library)
+ * http://www.happyworm.com/jquery/jplayer
+ *
+ * Skin Name: Morning Light
+ *
+ * Copyright (c) 2012 Per Sandstrm (https://github.com/persand) and Kasim Ahmic (https://github.com/TheInfection)
+ * Dual licensed under the MIT and GPL licenses.
+ * - http://www.opensource.org/licenses/mit-license.php
+ * - http://www.gnu.org/copyleft/gpl.html
+ *
+ * Authors: Per Sandstrm (Updated to support jPlayer 2.1.0 by Kasim Ahmic)
+ * Skin Version: 2.0 (jPlayer 2.1.0)
+ * Date: April 27th 2012
+ */
+
+*:focus, *:active {
+ outline: none !important;
+}
+
+.noScroll {
+ overflow: hidden !important;
+}
+
+div.jp-jplayer {
+ background-color: #000000;
+ margin: auto auto;
+}
+
+div.jp-audio,
+div.jp-audio-stream,
+div.jp-video {
+
+ /* Edit the font-size to counteract inherited font sizing.
+ * Eg. 1.25em = 1 / 0.8em
+ */
+
+ font-size:1em; /* 1.25em for testing in site pages */ /* No parent CSS that can effect the size in the demos ZIP */
+
+ font-family:Verdana, Arial, sans-serif;
+ line-height:1.6;
+ color:#666;
+ border:1px solid #DDD;
+ border-radius:0 0 8px 8px !important;
+ background:transparent;
+ position:relative;
+}
+div.jp-audio {
+ width:480px;
+ border-radius: 8px !important;
+}
+div.jp-audio-stream {
+ width:180px;
+ border-radius: 8px !important;
+}
+div.jp-video-270p {
+ width:480px;
+}
+div.jp-video-360p {
+ width:640px;
+}
+div.jp-video-full {
+ /* Rules for IE6 (full-screen) */
+ width:480px;
+ height:270px;
+ /* Rules for IE7 (full-screen) - Otherwise the relative container causes other page items that are not position:static (default) to appear over the video/gui. */
+ position:static !important; position:relative;
+}
+
+div.jp-video-full div.jp-jplayer {
+ top: 0;
+ left: 0;
+ position: fixed !important; position: relative; /* Rules for IE6 (full-screen) */
+ overflow: hidden;
+ z-index:1000;
+ margin-left: 0 !important;
+}
+
+div.jp-video-full div.jp-gui {
+ position: fixed !important; position: static; /* Rules for IE6 (full-screen) */
+ top: 0;
+ left: 0;
+ width:100%;
+ height:100%;
+ z-index:1000;
+}
+
+div.jp-video-full div.jp-interface {
+ position: absolute !important; position: relative; /* Rules for IE6 (full-screen) */
+ bottom: 0;
+ left: 0;
+ z-index:1000;
+}
+
+div.jp-gui {
+ width: 100%;
+}
+
+div.jp-gui div.jp-interface {
+ border: none !important;
+}
+
+div.jp-interface {
+ width: 100%;
+ position: relative;
+ background: url("jplayer.morning.light.interface.png") repeat-x;
+}
+
+div.jp-audio div.jp-type-single div.jp-interface {
+ height:75px;
+ border-radius: 6px 6px 0 0 !important;
+}
+div.jp-audio div.jp-type-playlist div.jp-interface {
+ height:70px;
+ border-radius: 6px 6px 0 0 !important;
+}
+div.jp-audio-stream div.jp-type-single div.jp-interface {
+ height:50px;
+ border-radius: 6px 6px 0 0 !important;
+}
+div.jp-video div.jp-interface {
+ border:0;
+}
+
+/* @group CONTROLS */
+
+div.jp-controls-holder {
+ clear: both;
+ width:440px;
+ margin:0 auto;
+ position: relative;
+ overflow:hidden;
+ top:-8px; /* This negative value depends on the size of the text in jp-currentTime and jp-duration */
+}
+
+div.jp-interface ul.jp-controls {
+ list-style-type:none;
+ margin:0;
+ padding: 0;
+ overflow:hidden;
+}
+
+div.jp-audio ul.jp-controls {
+ width: auto;
+ padding: 15px 15px 0 10px;
+}
+
+div.jp-audio-stream ul.jp-controls {
+ width: 142px;
+ padding:5px;
+}
+
+div.jp-video div.jp-type-single ul.jp-controls {
+ width: 78px;
+ margin-left: 200px;
+}
+
+div.jp-video div.jp-type-playlist ul.jp-controls {
+ width: 134px;
+ margin-left: 150px;
+}
+div.jp-video ul.jp-controls,
+div.jp-interface ul.jp-controls li {
+ display:inline;
+ float: left;
+}
+
+div.jp-interface ul.jp-controls a {
+ display:block;
+ overflow:hidden;
+ text-indent:-9999px;
+}
+a.jp-play,
+a.jp-pause {
+ width:40px;
+ height:40px;
+}
+
+a.jp-play {
+ background: url("jplayer.morning.light.png") 0 0 no-repeat;
+}
+a.jp-play:hover {
+ background: url("jplayer.morning.light.png") -41px 0 no-repeat;
+}
+a.jp-pause {
+ background: url("jplayer.morning.light.png") 0 -42px no-repeat;
+ display: none;
+}
+a.jp-pause:hover {
+ background: url("jplayer.morning.light.png") -41px -42px no-repeat;
+}
+
+a.jp-stop, a.jp-previous, a.jp-next {
+ width:28px;
+ height:28px;
+ margin-top:6px;
+}
+
+a.jp-stop {
+ background: url("jplayer.morning.light.png") 0 -83px no-repeat;
+ margin-left:10px;
+}
+
+a.jp-stop:hover {
+ background: url("jplayer.morning.light.png") -29px -83px no-repeat;
+}
+
+a.jp-previous {
+ background: url("jplayer.morning.light.png") 0 -112px no-repeat;
+}
+a.jp-previous:hover {
+ background: url("jplayer.morning.light.png") -29px -112px no-repeat;
+}
+
+a.jp-next {
+ background: url("jplayer.morning.light.png") 0 -141px no-repeat;
+}
+a.jp-next:hover {
+ background: url("jplayer.morning.light.png") -29px -141px no-repeat;
+}
+
+/* @end */
+
+/* @group progress bar */
+
+div.jp-progress {
+ overflow:hidden;
+ background: url("jplayer.morning.light.png") 0 -202px repeat-x;
+}
+div.jp-audio div.jp-progress {
+ position: absolute;
+ top:27px;
+ height:15px;
+ border-radius: 5px;
+}
+div.jp-audio div.jp-type-single div.jp-progress {
+ left:100px;
+ right:130px;
+}
+div.jp-audio div.jp-type-playlist div.jp-progress {
+ left:156px;
+ right: 180px;
+}
+div.jp-video div.jp-progress {
+ top:0px;
+ left:0px;
+ width:100%;
+ height:10px;
+}
+div.jp-seek-bar {
+ background: url("jplayer.morning.light.png") 0 -202px repeat-x;
+ width:0px;
+ height:100%;
+ cursor: pointer;
+ border-radius: 5px;
+ box-shadow: inset 0 0 5px #000;
+}
+div.jp-play-bar {
+ background: url("jplayer.morning.light.png") 0 -218px repeat-x ;
+ width:0px;
+ height:100%;
+ border-radius: 4px;
+ box-shadow: inset 0 0 5px #000;
+}
+div.jp-video div.jp-seek-bar {
+ border-radius: 0 !important;
+}
+div.jp-video div.jp-play-bar {
+ border-radius: 0 !important;
+}
+
+
+/* The seeking class is added/removed inside jPlayer */
+div.jp-seeking-bg {
+ background: url("jplayer.morning.light.seeking.gif");
+}
+
+/* @end */
+
+/* @group volume controls */
+
+
+a.jp-mute,
+a.jp-unmute,
+a.jp-volume-max {
+ position: absolute;
+ top: 27px;
+ width:18px;
+ height:15px;
+}
+
+div.jp-audio div.jp-type-single a.jp-mute,
+div.jp-audio div.jp-type-single a.jp-unmute {
+ right: 98px;
+}
+
+div.jp-audio div.jp-type-single a.jp-volume-max {
+ right: 15px;
+}
+
+div.jp-audio div.jp-type-playlist a.jp-mute,
+div.jp-audio div.jp-type-playlist a.jp-unmute {
+ right: 148px;
+}
+
+div.jp-audio div.jp-type-playlist a.jp-volume-max {
+ right: 85px;
+}
+
+div.jp-audio-stream div.jp-type-single a.jp-mute,
+div.jp-audio-stream div.jp-type-single a.jp-unmute {
+ top: 18px;
+ left: 60px;
+}
+
+div.jp-audio-stream a.jp-volume-max {
+ top: 18px;
+ left: 150px;
+}
+
+div.jp-video a.jp-mute,
+div.jp-video a.jp-unmute,
+div.jp-video a.jp-volume-max {
+ position: absolute;
+ top: 12px;
+ width:18px;
+ height:15px;
+}
+
+div.jp-video div.jp-type-single a.jp-mute,
+div.jp-video div.jp-type-single a.jp-unmute {
+ left: 0px;
+}
+
+div.jp-video div.jp-type-playlist a.jp-mute,
+div.jp-video div.jp-type-playlist a.jp-unmute {
+ left: 0;
+}
+
+div.jp-video div.jp-type-single a.jp-volume-max {
+ left: 160px;
+}
+
+div.jp-video div.jp-type-playlist a.jp-volume-max {
+ left: 128px;
+}
+
+a.jp-mute {
+ background: url("jplayer.morning.light.png") 0 -170px no-repeat;
+}
+a.jp-mute:hover {
+ background: url("jplayer.morning.light.png") -19px -170px no-repeat;
+}
+a.jp-unmute {
+ background: url("jplayer.morning.light.png") -39px -170px no-repeat;
+ display: none;
+}
+a.jp-unmute:hover {
+ background: url("jplayer.morning.light.png") -60px -170px no-repeat;
+}
+
+a.jp-volume-max {
+ background: url("jplayer.morning.light.png") 0 -186px no-repeat;
+}
+a.jp-volume-max:hover {
+ background: url("jplayer.morning.light.png") -19px -186px no-repeat;
+}
+
+div.jp-video div.jp-volume-bar,
+div.jp-audio-stream div.jp-volume-bar,
+div.jp-audio div.jp-volume-bar {
+ position:absolute !important;
+ overflow:hidden;
+ background:url("jplayer.morning.light.png") 0 -250px repeat-x;
+ height:5px;
+ cursor:pointer;
+ border-radius:5px;
+ box-shadow: inset 0 0 3px #000;
+}
+
+div.jp-audio div.jp-type-single div.jp-volume-bar {
+ top:32px;
+ right:45px;
+ width:50px;
+}
+div.jp-audio div.jp-type-playlist div.jp-volume-bar {
+ top:32px;
+ right:110px;
+ width:40px;
+}
+div.jp-audio-stream div.jp-type-single div.jp-volume-bar {
+ width:60px;
+ top:23px;
+ left:80px;
+}
+div.jp-video div.jp-type-single div.jp-volume-bar {
+ top:17px;
+ left:20px;
+ width:130px;
+}
+div.jp-video div.jp-type-playlist div.jp-volume-bar {
+ top:17px;
+ left:20px;
+ width:100px;
+}
+div.jp-volume-bar-value {
+ background:url("jplayer.morning.light.png") 0 -256px repeat-x;
+ width:0px;
+ height:5px;
+ border-radius: 5px;
+ box-shadow: inset 0 0 3px #000;
+}
+
+/* @end */
+
+/* @group current time and duration */
+
+div.jp-audio div.jp-time-holder {
+ position:absolute;
+ top:50px;
+}
+div.jp-audio div.jp-type-single div.jp-time-holder {
+ left:100px;
+ right:130px;
+}
+div.jp-audio div.jp-type-playlist div.jp-time-holder {
+ left:156px;
+ right:180px;
+}
+
+div.jp-current-time,
+div.jp-duration {
+ width:auto;
+ font-size:.64em;
+ font-style:oblique;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, .8);
+}
+div.jp-current-time {
+ float: left;
+ display:inline;
+ text-align: left;
+}
+div.jp-duration {
+ float: right;
+ display:inline;
+ text-align: right;
+}
+
+div.jp-video div.jp-current-time {
+ margin-left:10px;
+}
+div.jp-video div.jp-duration {
+ margin-right:10px;
+}
+/* @end */
+
+/* @group playlist */
+
+div.jp-title {
+ font-weight:bold;
+ text-align:center;
+ color: #666;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, .8);
+}
+
+div.jp-video div.jp-title {
+ border: none !important;
+}
+
+div.jp-title,
+div.jp-playlist {
+ background: url("jplayer.morning.light.playlist.png");
+ border-top: none !important;
+ text-align: left !important;
+ width: 100%;
+ border-radius: 0 0 6px 6px !important;
+}
+div.jp-type-single div.jp-title {
+ border-radius: 0 0 6px 6px;
+}
+div.video div.jp-type-single div.jp-playlist div.jp-title {
+ border-radius: 0;
+}
+div.jp-type-single div.jp-title,
+div.jp-type-playlist div.jp-title,
+div.jp-type-single div.jp-playlist {
+ border-top:none;
+}
+div.jp-title ul,
+div.jp-playlist ul {
+ list-style-type:none !important;
+ margin:0;
+ padding:0 0;
+ font-size:.72em;
+}
+
+div.jp-title li {
+ padding:5px 15px 5px 15px;
+ font-weight:bold;
+}
+div.jp-playlist li {
+ padding:5px 15px 5px 15px;
+ border-bottom: 1px solid #DDD;
+ background: url(jplayer.morning.light.playlist.png);
+ text-shadow: 0 1px 1px rgba(255, 255, 255, .8);
+}
+
+div.jp-playlist li div {
+ display:inline;
+}
+
+/* Note that the first-child (IE6) and last-child (IE6/7/8) selectors do not work on IE */
+
+div.jp-type-playlist div.jp-playlist li:last-child {
+ padding:5px 15px 5px 15px;
+ border-bottom: none !important;
+ border-radius: 0 0 6px 6px !important;
+}
+div.jp-type-playlist div.jp-playlist li.jp-playlist-current {
+ list-style-type:none;
+ list-style-position:inside;
+ padding-left:15px;
+}
+div.jp-type-playlist div.jp-playlist a {
+ color: #666;
+ text-decoration: none;
+}
+div.jp-type-playlist div.jp-playlist a:hover {
+ color:#0D88C1;
+}
+div.jp-type-playlist div.jp-playlist a.jp-playlist-current {
+ color:#0D88C1;
+ font-weight: bold;
+}
+
+div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove {
+ float:right;
+ display:inline;
+ text-align:right;
+ margin-right:10px;
+ font-weight:bold;
+ color:#666;
+}
+div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove:hover {
+ color:#0d88c1;
+}
+div.jp-type-playlist div.jp-playlist span.jp-free-media {
+ float:right;
+ display:inline;
+ text-align:right;
+ margin-right:10px;
+}
+div.jp-type-playlist div.jp-playlist span.jp-free-media a{
+ color:#666;
+}
+div.jp-type-playlist div.jp-playlist span.jp-free-media a:hover{
+ color:#0d88c1;
+}
+span.jp-artist {
+ font-size:.8em;
+ color:#666;
+}
+
+/* @end */
+
+div.jp-video-play {
+ position:absolute;
+ top:0;
+ left:0;
+ width:100%;
+ cursor:pointer;
+ background-color:rgba(0,0,0,0); /* Makes IE9 work with the active area over the whole video area. IE6/7/8 only have the button as active area. */
+}
+div.jp-video-270p div.jp-video-play {
+ height:270px;
+}
+div.jp-video-360p div.jp-video-play {
+ height:360px;
+}
+div.jp-video-full div.jp-video-play {
+ height:100%;
+ z-index:1000;
+}
+a.jp-video-play-icon {
+ position:relative;
+ display:block;
+ width: 112px;
+ height: 100px;
+
+ margin-left:-56px;
+ margin-top:-50px;
+ left:50%;
+ top:50%;
+
+ background: url("jplayer.morning.light.video.play.png") 0 0 no-repeat;
+ text-indent:-9999px;
+}
+div.jp-video-play:hover a.jp-video-play-icon {
+ background: url("jplayer.morning.light.video.play.png") 0 -100px no-repeat;
+}
+
+
+
+
+
+div.jp-jplayer audio,
+div.jp-jplayer {
+ width:0px;
+ height:0px;
+}
+
+div.jp-jplayer {
+ background-color: #000000;
+}
+
+
+
+
+
+/* @group TOGGLES */
+
+/* The audio toggles are nested inside jp-time-holder */
+
+ul.jp-toggles {
+ width: 110px;
+ display: block;
+ list-style-type:none;
+ padding:0;
+ margin:0 auto;
+ overflow:hidden;
+}
+
+div.jp-audio .jp-type-single ul.jp-toggles {
+ width:28px;
+ margin: 0 0 0 -14px;
+ position: absolute;
+ left: 50%;
+ top: -5px;
+}
+div.jp-audio .jp-type-playlist ul.jp-toggles {
+ width:65px;
+ margin: 0;
+ position: absolute;
+ right: 8px;
+ top: 22px;
+}
+
+div.jp-video ul.jp-toggles {
+ margin-top:7px;
+ width:110px;
+}
+
+ul.jp-toggles li {
+ display:block;
+ float:right;
+}
+
+ul.jp-toggles li a {
+ display:block;
+ width:28px;
+ height:28px;
+ text-indent:-9999px;
+ line-height:100%; /* need this for IE6 */
+}
+
+a.jp-shuffle {
+ background: url("jplayer.morning.light.png") 0 -262px no-repeat;
+ margin-left: 5px;
+}
+
+a.jp-shuffle:hover {
+ background: url("jplayer.morning.light.png") -30px -262px no-repeat;
+}
+
+a.jp-shuffle-off {
+ background: url("jplayer.morning.light.png") -60px -262px no-repeat;
+ margin-left: 5px;
+}
+
+a.jp-shuffle-off:hover {
+ background: url("jplayer.morning.light.png") -90px -262px no-repeat;
+}
+
+a.jp-repeat {
+ background: url("jplayer.morning.light.png") 0 -290px no-repeat;
+}
+
+a.jp-repeat:hover {
+ background: url("jplayer.morning.light.png") -30px -290px no-repeat;
+}
+
+a.jp-repeat-off {
+ background: url("jplayer.morning.light.png") -60px -290px no-repeat;
+}
+
+a.jp-repeat-off:hover {
+ background: url("jplayer.morning.light.png") -90px -290px no-repeat;
+}
+
+a.jp-full-screen {
+ background: url("jplayer.morning.light.png") 0 -318px no-repeat;
+ margin-left: 20px;
+}
+
+a.jp-full-screen:hover {
+ background: url("jplayer.morning.light.png") -30px -318px no-repeat;
+}
+
+a.jp-restore-screen {
+ background: url("jplayer.morning.light.png") -60px -318px no-repeat;
+ margin-left: 20px;
+}
+
+a.jp-restore-screen:hover {
+ background: url("jplayer.morning.light.png") -90px -318px no-repeat;
+}
+
+
+/* @end */
+
+/* @group NO SOLUTION error feedback */
+
+.jp-no-solution {
+ position:absolute;
+ width:390px;
+ margin-left:-202px;
+ left:50%;
+ top: 10px;
+
+ padding:5px;
+ font-size:.8em;
+ background-color:#eee;
+ border:2px solid #009be3;
+ color:#000;
+ display:none;
+}
+
+.jp-no-solution a {
+ color:#000;
+}
+
+.jp-no-solution span {
+ font-size:1em;
+ display:block;
+ text-align:center;
+ font-weight:bold;
+}
+
+/* @end */
diff --git a/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.interface.png b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.interface.png
new file mode 100644
index 00000000..901ffc35
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.interface.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.playlist.png b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.playlist.png
new file mode 100644
index 00000000..38c9d755
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.playlist.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.png b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.png
new file mode 100644
index 00000000..3470f629
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.seeking.gif b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.seeking.gif
new file mode 100644
index 00000000..dbd2105a
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.seeking.gif
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.video.play.png b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.video.play.png
new file mode 100644
index 00000000..e8d7f896
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jplayer/skin/morning.light/jplayer.morning.light.video.play.png
Binary files differ
diff --git a/SemanticResultFormats/resources/jquery/jqgrid/grid.locale-en.js b/SemanticResultFormats/resources/jquery/jqgrid/grid.locale-en.js
new file mode 100644
index 00000000..14dd4c64
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqgrid/grid.locale-en.js
@@ -0,0 +1,169 @@
+;(function($){
+/**
+ * jqGrid English Translation
+ * Tony Tomov tony@trirand.com
+ * http://trirand.com/blog/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = $.jgrid || {};
+$.extend($.jgrid,{
+ defaults : {
+ recordtext: "View {0} - {1} of {2}",
+ emptyrecords: "No records to view",
+ loadtext: "Loading...",
+ pgtext : "Page {0} of {1}"
+ },
+ search : {
+ caption: "Search...",
+ Find: "Find",
+ Reset: "Reset",
+ odata : ['equal', 'not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is in','is not in','ends with','does not end with','contains','does not contain'],
+ groupOps: [ { op: "AND", text: "all" }, { op: "OR", text: "any" } ],
+ matchText: " match",
+ rulesText: " rules"
+ },
+ edit : {
+ addCaption: "Add Record",
+ editCaption: "Edit Record",
+ bSubmit: "Submit",
+ bCancel: "Cancel",
+ bClose: "Close",
+ saveData: "Data has been changed! Save changes?",
+ bYes : "Yes",
+ bNo : "No",
+ bExit : "Cancel",
+ msg: {
+ required:"Field is required",
+ number:"Please, enter valid number",
+ minValue:"value must be greater than or equal to ",
+ maxValue:"value must be less than or equal to",
+ email: "is not a valid e-mail",
+ integer: "Please, enter valid integer value",
+ date: "Please, enter valid date value",
+ url: "is not a valid URL. Prefix required ('http://' or 'https://')",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+
+ }
+ },
+ view : {
+ caption: "View Record",
+ bClose: "Close"
+ },
+ del : {
+ caption: "Delete",
+ msg: "Delete selected record(s)?",
+ bSubmit: "Delete",
+ bCancel: "Cancel"
+ },
+ nav : {
+ edittext: "",
+ edittitle: "Edit selected row",
+ addtext:"",
+ addtitle: "Add new row",
+ deltext: "",
+ deltitle: "Delete selected row",
+ searchtext: "",
+ searchtitle: "Find records",
+ refreshtext: "",
+ refreshtitle: "Reload Grid",
+ alertcap: "Warning",
+ alerttext: "Please, select row",
+ viewtext: "",
+ viewtitle: "View selected row"
+ },
+ col : {
+ caption: "Select columns",
+ bSubmit: "Ok",
+ bCancel: "Cancel"
+ },
+ errors : {
+ errcap : "Error",
+ nourl : "No url is set",
+ norecords: "No records to process",
+ model : "Length of colNames <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: ",", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: ",", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: ",", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat",
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th';},
+ srcformat: 'Y-m-d',
+ newformat: 'n/j/Y',
+ masks : {
+ // see http://php.net/manual/en/function.date.php for PHP format used in jqGrid
+ // and see http://docs.jquery.com/UI/Datepicker/formatDate
+ // and https://github.com/jquery/globalize#dates for alternative formats used frequently
+ // one can find on https://github.com/jquery/globalize/tree/master/lib/cultures many
+ // information about date, time, numbers and currency formats used in different countries
+ // one should just convert the information in PHP format
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ // short date:
+ // n - Numeric representation of a month, without leading zeros
+ // j - Day of the month without leading zeros
+ // Y - A full numeric representation of a year, 4 digits
+ // example: 3/1/2012 which means 1 March 2012
+ ShortDate: "n/j/Y", // in jQuery UI Datepicker: "M/d/yyyy"
+ // long date:
+ // l - A full textual representation of the day of the week
+ // F - A full textual representation of a month
+ // d - Day of the month, 2 digits with leading zeros
+ // Y - A full numeric representation of a year, 4 digits
+ LongDate: "l, F d, Y", // in jQuery UI Datepicker: "dddd, MMMM dd, yyyy"
+ // long date with long time:
+ // l - A full textual representation of the day of the week
+ // F - A full textual representation of a month
+ // d - Day of the month, 2 digits with leading zeros
+ // Y - A full numeric representation of a year, 4 digits
+ // g - 12-hour format of an hour without leading zeros
+ // i - Minutes with leading zeros
+ // s - Seconds, with leading zeros
+ // A - Uppercase Ante meridiem and Post meridiem (AM or PM)
+ FullDateTime: "l, F d, Y g:i:s A", // in jQuery UI Datepicker: "dddd, MMMM dd, yyyy h:mm:ss tt"
+ // month day:
+ // F - A full textual representation of a month
+ // d - Day of the month, 2 digits with leading zeros
+ MonthDay: "F d", // in jQuery UI Datepicker: "MMMM dd"
+ // short time (without seconds)
+ // g - 12-hour format of an hour without leading zeros
+ // i - Minutes with leading zeros
+ // A - Uppercase Ante meridiem and Post meridiem (AM or PM)
+ ShortTime: "g:i A", // in jQuery UI Datepicker: "h:mm tt"
+ // long time (with seconds)
+ // g - 12-hour format of an hour without leading zeros
+ // i - Minutes with leading zeros
+ // s - Seconds, with leading zeros
+ // A - Uppercase Ante meridiem and Post meridiem (AM or PM)
+ LongTime: "g:i:s A", // in jQuery UI Datepicker: "h:mm:ss tt"
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ // month with year
+ // Y - A full numeric representation of a year, 4 digits
+ // F - A full textual representation of a month
+ YearMonth: "F, Y" // in jQuery UI Datepicker: "MMMM, yyyy"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+});
+})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/jqgrid/jquery.jqGrid.js b/SemanticResultFormats/resources/jquery/jqgrid/jquery.jqGrid.js
new file mode 100644
index 00000000..e89e54d4
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqgrid/jquery.jqGrid.js
@@ -0,0 +1,516 @@
+/*
+* jqGrid 4.4.0 - jQuery Grid
+* Copyright (c) 2008, Tony Tomov, tony@trirand.com
+* Dual licensed under the MIT and GPL licenses
+* http://www.opensource.org/licenses/mit-license.php
+* http://www.gnu.org/licenses/gpl-2.0.html
+* Date:2012-06-14
+* Modules: grid.base.js; jquery.fmatter.js; grid.custom.js; grid.common.js; grid.formedit.js; grid.filter.js; grid.inlinedit.js; grid.celledit.js; jqModal.js; jqDnR.js; grid.subgrid.js; grid.grouping.js; grid.treegrid.js; grid.import.js; JsonXml.js; grid.tbltogrid.js; grid.jqueryui.js;
+*/
+(function(b){b.jgrid=b.jgrid||{};b.extend(b.jgrid,{version:"4.4.0",htmlDecode:function(b){return b&&("&nbsp;"==b||"&#160;"==b||1===b.length&&160===b.charCodeAt(0))?"":!b?b:(""+b).replace(/&gt;/g,">").replace(/&lt;/g,"<").replace(/&quot;/g,'"').replace(/&amp;/g,"&")},htmlEncode:function(b){return!b?b:(""+b).replace(/&/g,"&amp;").replace(/\"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")},format:function(f){var e=b.makeArray(arguments).slice(1);void 0===f&&(f="");return f.replace(/\{(\d+)\}/g,
+function(b,d){return e[d]})},getCellIndex:function(f){f=b(f);if(f.is("tr"))return-1;f=(!f.is("td")&&!f.is("th")?f.closest("td,th"):f)[0];return b.browser.msie?b.inArray(f,f.parentNode.cells):f.cellIndex},stripHtml:function(b){var b=b+"",e=/<("[^"]*"|'[^']*'|[^'">])*>/gi;return b?(b=b.replace(e,""))&&"&nbsp;"!==b&&"&#160;"!==b?b.replace(/\"/g,"'"):"":b},stripPref:function(f,e){var c=b.type(f);if("string"==c||"number"==c)f=""+f,e=""!==f?(""+e).replace(""+f,""):e;return e},stringToDoc:function(b){var e;
+if("string"!==typeof b)return b;try{e=(new DOMParser).parseFromString(b,"text/xml")}catch(c){e=new ActiveXObject("Microsoft.XMLDOM"),e.async=!1,e.loadXML(b)}return e&&e.documentElement&&"parsererror"!=e.documentElement.tagName?e:null},parse:function(f){"while(1);"==f.substr(0,9)&&(f=f.substr(9));"/*"==f.substr(0,2)&&(f=f.substr(2,f.length-4));f||(f="{}");return!0===b.jgrid.useJSON&&"object"===typeof JSON&&"function"===typeof JSON.parse?JSON.parse(f):eval("("+f+")")},parseDate:function(f,e){var c=
+{m:1,d:1,y:1970,h:0,i:0,s:0,u:0},d,a,h;d=/[\\\/:_;.,\t\T\s-]/;if(e&&null!==e&&void 0!==e){e=b.trim(e);e=e.split(d);void 0!==b.jgrid.formatter.date.masks[f]&&(f=b.jgrid.formatter.date.masks[f]);var f=f.split(d),g=b.jgrid.formatter.date.monthNames,i=b.jgrid.formatter.date.AmPm,j=function(a,b){0===a?12===b&&(b=0):12!==b&&(b+=12);return b};d=0;for(a=f.length;d<a;d++)"M"==f[d]&&(h=b.inArray(e[d],g),-1!==h&&12>h&&(e[d]=h+1,c.m=e[d])),"F"==f[d]&&(h=b.inArray(e[d],g),-1!==h&&11<h&&(e[d]=h+1-12,c.m=e[d])),
+"a"==f[d]&&(h=b.inArray(e[d],i),-1!==h&&2>h&&e[d]==i[h]&&(e[d]=h,c.h=j(e[d],c.h))),"A"==f[d]&&(h=b.inArray(e[d],i),-1!==h&&1<h&&e[d]==i[h]&&(e[d]=h-2,c.h=j(e[d],c.h))),void 0!==e[d]&&(c[f[d].toLowerCase()]=parseInt(e[d],10));c.m=parseInt(c.m,10)-1;d=c.y;70<=d&&99>=d?c.y=1900+c.y:0<=d&&69>=d&&(c.y=2E3+c.y);void 0!==c.j&&(c.d=c.j);void 0!==c.n&&(c.m=parseInt(c.n,10)-1)}return new Date(c.y,c.m,c.d,c.h,c.i,c.s,c.u)},jqID:function(b){return(""+b).replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]\^`{|}~]/g,"\\$&")},
+guid:1,uidPref:"jqg",randId:function(f){return(f?f:b.jgrid.uidPref)+b.jgrid.guid++},getAccessor:function(b,e){var c,d,a=[],h;if("function"===typeof e)return e(b);c=b[e];if(void 0===c)try{if("string"===typeof e&&(a=e.split(".")),h=a.length)for(c=b;c&&h--;)d=a.shift(),c=c[d]}catch(g){}return c},getXmlData:function(f,e,c){var d="string"===typeof e?e.match(/^(.*)\[(\w+)\]$/):null;if("function"===typeof e)return e(f);if(d&&d[2])return d[1]?b(d[1],f).attr(d[2]):b(f).attr(d[2]);f=b(e,f);return c?f:0<f.length?
+b(f).text():void 0},cellWidth:function(){var f=b("<div class='ui-jqgrid' style='left:10000px'><table class='ui-jqgrid-btable' style='width:5px;'><tr class='jqgrow'><td style='width:5px;'></td></tr></table></div>"),e=f.appendTo("body").find("td").width();f.remove();return 5!==e},ajaxOptions:{},from:function(f){return new function(e,c){"string"==typeof e&&(e=b.data(e));var d=this,a=e,h=!0,f=!1,i=c,j=/[\$,%]/g,l=null,k=null,m=0,o=!1,p="",v=[],u=!0;if("object"==typeof e&&e.push)0<e.length&&(u="object"!=
+typeof e[0]?!1:!0);else throw"data provides is not an array";this._hasData=function(){return null===a?!1:0===a.length?!1:!0};this._getStr=function(a){var b=[];f&&b.push("jQuery.trim(");b.push("String("+a+")");f&&b.push(")");h||b.push(".toLowerCase()");return b.join("")};this._strComp=function(a){return"string"==typeof a?".toString()":""};this._group=function(a,b){return{field:a.toString(),unique:b,items:[]}};this._toStr=function(a){f&&(a=b.trim(a));a=a.toString().replace(/\\/g,"\\\\").replace(/\"/g,
+'\\"');return h?a:a.toLowerCase()};this._funcLoop=function(d){var c=[];b.each(a,function(a,b){c.push(d(b))});return c};this._append=function(a){var b;i=null===i?"":i+(""===p?" && ":p);for(b=0;b<m;b++)i+="(";o&&(i+="!");i+="("+a+")";o=!1;p="";m=0};this._setCommand=function(a,b){l=a;k=b};this._resetNegate=function(){o=!1};this._repeatCommand=function(a,b){return null===l?d:null!==a&&null!==b?l(a,b):null===k||!u?l(a):l(k,a)};this._equals=function(a,b){return 0===d._compare(a,b,1)};this._compare=function(a,
+b,d){var c=Object.prototype.toString;void 0===d&&(d=1);void 0===a&&(a=null);void 0===b&&(b=null);if(null===a&&null===b)return 0;if(null===a&&null!==b)return 1;if(null!==a&&null===b)return-1;if("[object Date]"===c.call(a)&&"[object Date]"===c.call(b))return a<b?-d:a>b?d:0;!h&&"number"!==typeof a&&"number"!==typeof b&&(a=(""+a).toLowerCase(),b=(""+b).toLowerCase());return a<b?-d:a>b?d:0};this._performSort=function(){0!==v.length&&(a=d._doSort(a,0))};this._doSort=function(a,b){var c=v[b].by,f=v[b].dir,
+h=v[b].type,e=v[b].datefmt;if(b==v.length-1)return d._getOrder(a,c,f,h,e);b++;c=d._getGroup(a,c,f,h,e);f=[];for(h=0;h<c.length;h++)for(var e=d._doSort(c[h].items,b),g=0;g<e.length;g++)f.push(e[g]);return f};this._getOrder=function(a,c,h,f,e){var g=[],i=[],l="a"==h?1:-1,k,m;void 0===f&&(f="text");m="float"==f||"number"==f||"currency"==f||"numeric"==f?function(a){a=parseFloat((""+a).replace(j,""));return isNaN(a)?0:a}:"int"==f||"integer"==f?function(a){return a?parseFloat((""+a).replace(j,"")):0}:"date"==
+f||"datetime"==f?function(a){return b.jgrid.parseDate(e,a).getTime()}:b.isFunction(f)?f:function(a){a||(a="");return b.trim((""+a).toUpperCase())};b.each(a,function(a,d){k=""!==c?b.jgrid.getAccessor(d,c):d;void 0===k&&(k="");k=m(k,d);i.push({vSort:k,index:a})});i.sort(function(a,b){a=a.vSort;b=b.vSort;return d._compare(a,b,l)});for(var f=0,o=a.length;f<o;)h=i[f].index,g.push(a[h]),f++;return g};this._getGroup=function(a,c,f,h,e){var g=[],i=null,j=null,k;b.each(d._getOrder(a,c,f,h,e),function(a,f){k=
+b.jgrid.getAccessor(f,c);void 0===k&&(k="");d._equals(j,k)||(j=k,null!==i&&g.push(i),i=d._group(c,k));i.items.push(f)});null!==i&&g.push(i);return g};this.ignoreCase=function(){h=!1;return d};this.useCase=function(){h=!0;return d};this.trim=function(){f=!0;return d};this.noTrim=function(){f=!1;return d};this.execute=function(){var c=i,f=[];if(null===c)return d;b.each(a,function(){eval(c)&&f.push(this)});a=f;return d};this.data=function(){return a};this.select=function(c){d._performSort();if(!d._hasData())return[];
+d.execute();if(b.isFunction(c)){var f=[];b.each(a,function(a,b){f.push(c(b))});return f}return a};this.hasMatch=function(){if(!d._hasData())return!1;d.execute();return 0<a.length};this.andNot=function(a,b,c){o=!o;return d.and(a,b,c)};this.orNot=function(a,b,c){o=!o;return d.or(a,b,c)};this.not=function(a,b,c){return d.andNot(a,b,c)};this.and=function(a,b,c){p=" && ";return void 0===a?d:d._repeatCommand(a,b,c)};this.or=function(a,b,c){p=" || ";return void 0===a?d:d._repeatCommand(a,b,c)};this.orBegin=
+function(){m++;return d};this.orEnd=function(){null!==i&&(i+=")");return d};this.isNot=function(a){o=!o;return d.is(a)};this.is=function(a){d._append("this."+a);d._resetNegate();return d};this._compareValues=function(a,c,f,h,e){var g;g=u?"jQuery.jgrid.getAccessor(this,'"+c+"')":"this";void 0===f&&(f=null);var i=f,k=void 0===e.stype?"text":e.stype;if(null!==f)switch(k){case "int":case "integer":i=isNaN(Number(i))||""===i?"0":i;g="parseInt("+g+",10)";i="parseInt("+i+",10)";break;case "float":case "number":case "numeric":i=
+(""+i).replace(j,"");i=isNaN(Number(i))||""===i?"0":i;g="parseFloat("+g+")";i="parseFloat("+i+")";break;case "date":case "datetime":i=""+b.jgrid.parseDate(e.newfmt||"Y-m-d",i).getTime();g='jQuery.jgrid.parseDate("'+e.srcfmt+'",'+g+").getTime()";break;default:g=d._getStr(g),i=d._getStr('"'+d._toStr(i)+'"')}d._append(g+" "+h+" "+i);d._setCommand(a,c);d._resetNegate();return d};this.equals=function(a,b,c){return d._compareValues(d.equals,a,b,"==",c)};this.notEquals=function(a,b,c){return d._compareValues(d.equals,
+a,b,"!==",c)};this.isNull=function(a,b,c){return d._compareValues(d.equals,a,null,"===",c)};this.greater=function(a,b,c){return d._compareValues(d.greater,a,b,">",c)};this.less=function(a,b,c){return d._compareValues(d.less,a,b,"<",c)};this.greaterOrEquals=function(a,b,c){return d._compareValues(d.greaterOrEquals,a,b,">=",c)};this.lessOrEquals=function(a,b,c){return d._compareValues(d.lessOrEquals,a,b,"<=",c)};this.startsWith=function(a,c){var h=void 0===c||null===c?a:c,h=f?b.trim(h.toString()).length:
+h.toString().length;u?d._append(d._getStr("jQuery.jgrid.getAccessor(this,'"+a+"')")+".substr(0,"+h+") == "+d._getStr('"'+d._toStr(c)+'"')):(h=f?b.trim(c.toString()).length:c.toString().length,d._append(d._getStr("this")+".substr(0,"+h+") == "+d._getStr('"'+d._toStr(a)+'"')));d._setCommand(d.startsWith,a);d._resetNegate();return d};this.endsWith=function(a,c){var h=void 0===c||null===c?a:c,h=f?b.trim(h.toString()).length:h.toString().length;u?d._append(d._getStr("jQuery.jgrid.getAccessor(this,'"+a+
+"')")+".substr("+d._getStr("jQuery.jgrid.getAccessor(this,'"+a+"')")+".length-"+h+","+h+') == "'+d._toStr(c)+'"'):d._append(d._getStr("this")+".substr("+d._getStr("this")+'.length-"'+d._toStr(a)+'".length,"'+d._toStr(a)+'".length) == "'+d._toStr(a)+'"');d._setCommand(d.endsWith,a);d._resetNegate();return d};this.contains=function(a,b){u?d._append(d._getStr("jQuery.jgrid.getAccessor(this,'"+a+"')")+'.indexOf("'+d._toStr(b)+'",0) > -1'):d._append(d._getStr("this")+'.indexOf("'+d._toStr(a)+'",0) > -1');
+d._setCommand(d.contains,a);d._resetNegate();return d};this.groupBy=function(b,c,f,h){return!d._hasData()?null:d._getGroup(a,b,c,f,h)};this.orderBy=function(a,c,f,h){c=void 0===c||null===c?"a":b.trim(c.toString().toLowerCase());if(null===f||void 0===f)f="text";if(null===h||void 0===h)h="Y-m-d";if("desc"==c||"descending"==c)c="d";if("asc"==c||"ascending"==c)c="a";v.push({by:a,dir:c,type:f,datefmt:h});return d};return d}(f,null)},extend:function(f){b.extend(b.fn.jqGrid,f);this.no_legacy_api||b.fn.extend(f)}});
+b.fn.jqGrid=function(f){if("string"==typeof f){var e=b.jgrid.getAccessor(b.fn.jqGrid,f);if(!e)throw"jqGrid - No such method: "+f;var c=b.makeArray(arguments).slice(1);return e.apply(this,c)}return this.each(function(){if(!this.grid){var d=b.extend(!0,{url:"",height:150,page:1,rowNum:20,rowTotal:null,records:0,pager:"",pgbuttons:!0,pginput:!0,colModel:[],rowList:[],colNames:[],sortorder:"asc",sortname:"",datatype:"xml",mtype:"GET",altRows:!1,selarrrow:[],savedRow:[],shrinkToFit:!0,xmlReader:{},jsonReader:{},
+subGrid:!1,subGridModel:[],reccount:0,lastpage:0,lastsort:0,selrow:null,beforeSelectRow:null,onSelectRow:null,onSortCol:null,ondblClickRow:null,onRightClickRow:null,onPaging:null,onSelectAll:null,loadComplete:null,gridComplete:null,loadError:null,loadBeforeSend:null,afterInsertRow:null,beforeRequest:null,beforeProcessing:null,onHeaderClick:null,viewrecords:!1,loadonce:!1,multiselect:!1,multikey:!1,editurl:null,search:!1,caption:"",hidegrid:!0,hiddengrid:!1,postData:{},userData:{},treeGrid:!1,treeGridModel:"nested",
+treeReader:{},treeANode:-1,ExpandColumn:null,tree_root_level:0,prmNames:{page:"page",rows:"rows",sort:"sidx",order:"sord",search:"_search",nd:"nd",id:"id",oper:"oper",editoper:"edit",addoper:"add",deloper:"del",subgridid:"id",npage:null,totalrows:"totalrows"},forceFit:!1,gridstate:"visible",cellEdit:!1,cellsubmit:"remote",nv:0,loadui:"enable",toolbar:[!1,""],scroll:!1,multiboxonly:!1,deselectAfterSort:!0,scrollrows:!1,autowidth:!1,scrollOffset:18,cellLayout:5,subGridWidth:20,multiselectWidth:20,gridview:!1,
+rownumWidth:25,rownumbers:!1,pagerpos:"center",recordpos:"right",footerrow:!1,userDataOnFooter:!1,hoverrows:!0,altclass:"ui-priority-secondary",viewsortcols:[!1,"vertical",!0],resizeclass:"",autoencode:!1,remapColumns:[],ajaxGridOptions:{},direction:"ltr",toppager:!1,headertitles:!1,scrollTimeout:40,data:[],_index:{},grouping:!1,groupingView:{groupField:[],groupOrder:[],groupText:[],groupColumnShow:[],groupSummary:[],showSummaryOnHide:!1,sortitems:[],sortnames:[],summary:[],summaryval:[],plusicon:"ui-icon-circlesmall-plus",
+minusicon:"ui-icon-circlesmall-minus"},ignoreCase:!1,cmTemplate:{},idPrefix:""},b.jgrid.defaults,f||{}),a=this,c={headers:[],cols:[],footers:[],dragStart:function(c,e,f){this.resizing={idx:c,startX:e.clientX,sOL:f[0]};this.hDiv.style.cursor="col-resize";this.curGbox=b("#rs_m"+b.jgrid.jqID(d.id),"#gbox_"+b.jgrid.jqID(d.id));this.curGbox.css({display:"block",left:f[0],top:f[1],height:f[2]});b(a).triggerHandler("jqGridResizeStart",[e,c]);b.isFunction(d.resizeStart)&&d.resizeStart.call(this,e,c);document.onselectstart=
+function(){return!1}},dragMove:function(a){if(this.resizing){var b=a.clientX-this.resizing.startX,a=this.headers[this.resizing.idx],c="ltr"===d.direction?a.width+b:a.width-b,e;33<c&&(this.curGbox.css({left:this.resizing.sOL+b}),!0===d.forceFit?(e=this.headers[this.resizing.idx+d.nv],b="ltr"===d.direction?e.width-b:e.width+b,33<b&&(a.newWidth=c,e.newWidth=b)):(this.newWidth="ltr"===d.direction?d.tblwidth+b:d.tblwidth-b,a.newWidth=c))}},dragEnd:function(){this.hDiv.style.cursor="default";if(this.resizing){var c=
+this.resizing.idx,e=this.headers[c].newWidth||this.headers[c].width,e=parseInt(e,10);this.resizing=!1;b("#rs_m"+b.jgrid.jqID(d.id)).css("display","none");d.colModel[c].width=e;this.headers[c].width=e;this.headers[c].el.style.width=e+"px";this.cols[c].style.width=e+"px";0<this.footers.length&&(this.footers[c].style.width=e+"px");!0===d.forceFit?(e=this.headers[c+d.nv].newWidth||this.headers[c+d.nv].width,this.headers[c+d.nv].width=e,this.headers[c+d.nv].el.style.width=e+"px",this.cols[c+d.nv].style.width=
+e+"px",0<this.footers.length&&(this.footers[c+d.nv].style.width=e+"px"),d.colModel[c+d.nv].width=e):(d.tblwidth=this.newWidth||d.tblwidth,b("table:first",this.bDiv).css("width",d.tblwidth+"px"),b("table:first",this.hDiv).css("width",d.tblwidth+"px"),this.hDiv.scrollLeft=this.bDiv.scrollLeft,d.footerrow&&(b("table:first",this.sDiv).css("width",d.tblwidth+"px"),this.sDiv.scrollLeft=this.bDiv.scrollLeft));b(a).triggerHandler("jqGridResizeStop",[e,c]);b.isFunction(d.resizeStop)&&d.resizeStop.call(this,
+e,c)}this.curGbox=null;document.onselectstart=function(){return!0}},populateVisible:function(){c.timer&&clearTimeout(c.timer);c.timer=null;var a=b(c.bDiv).height();if(a){var e=b("table:first",c.bDiv),f,G;if(e[0].rows.length)try{G=(f=e[0].rows[1])?b(f).outerHeight()||c.prevRowHeight:c.prevRowHeight}catch(g){G=c.prevRowHeight}if(G){c.prevRowHeight=G;var i=d.rowNum;f=c.scrollTop=c.bDiv.scrollTop;var j=Math.round(e.position().top)-f,k=j+e.height();G*=i;var y,z,B;if(k<a&&0>=j&&(void 0===d.lastpage||parseInt((k+
+f+G-1)/G,10)<=d.lastpage))z=parseInt((a-k+G-1)/G,10),0<=k||2>z||!0===d.scroll?(y=Math.round((k+f)/G)+1,j=-1):j=1;0<j&&(y=parseInt(f/G,10)+1,z=parseInt((f+a)/G,10)+2-y,B=!0);if(z&&!(d.lastpage&&y>d.lastpage||1==d.lastpage||y===d.page&&y===d.lastpage))c.hDiv.loading?c.timer=setTimeout(c.populateVisible,d.scrollTimeout):(d.page=y,B&&(c.selectionPreserver(e[0]),c.emptyRows.call(e[0],!1,!1)),c.populate(z))}}},scrollGrid:function(a){if(d.scroll){var b=c.bDiv.scrollTop;void 0===c.scrollTop&&(c.scrollTop=
+0);b!=c.scrollTop&&(c.scrollTop=b,c.timer&&clearTimeout(c.timer),c.timer=setTimeout(c.populateVisible,d.scrollTimeout))}c.hDiv.scrollLeft=c.bDiv.scrollLeft;d.footerrow&&(c.sDiv.scrollLeft=c.bDiv.scrollLeft);a&&a.stopPropagation()},selectionPreserver:function(a){var c=a.p,d=c.selrow,e=c.selarrrow?b.makeArray(c.selarrrow):null,f=a.grid.bDiv.scrollLeft,g=function(){var h;c.selrow=null;c.selarrrow=[];if(c.multiselect&&e&&0<e.length)for(h=0;h<e.length;h++)e[h]!=d&&b(a).jqGrid("setSelection",e[h],!1,null);
+d&&b(a).jqGrid("setSelection",d,!1,null);a.grid.bDiv.scrollLeft=f;b(a).unbind(".selectionPreserver",g)};b(a).bind("jqGridGridComplete.selectionPreserver",g)}};if("TABLE"!=this.tagName.toUpperCase())alert("Element is not a table");else if(void 0!==document.documentMode&&5>=document.documentMode)alert("Grid can not be used in this ('quirks') mode!");else{b(this).empty().attr("tabindex","1");this.p=d;this.p.useProp=!!b.fn.prop;var e,i;if(0===this.p.colNames.length)for(e=0;e<this.p.colModel.length;e++)this.p.colNames[e]=
+this.p.colModel[e].label||this.p.colModel[e].name;if(this.p.colNames.length!==this.p.colModel.length)alert(b.jgrid.errors.model);else{var j=b("<div class='ui-jqgrid-view'></div>"),l,k=b.browser.msie?!0:!1;a.p.direction=b.trim(a.p.direction.toLowerCase());-1==b.inArray(a.p.direction,["ltr","rtl"])&&(a.p.direction="ltr");i=a.p.direction;b(j).insertBefore(this);b(this).appendTo(j).removeClass("scroll");var m=b("<div class='ui-jqgrid ui-widget ui-widget-content ui-corner-all'></div>");b(m).insertBefore(j).attr({id:"gbox_"+
+this.id,dir:i});b(j).appendTo(m).attr("id","gview_"+this.id);l=k&&6>=b.browser.version?'<iframe style="display:block;position:absolute;z-index:-1;filter:Alpha(Opacity=\'0\');" src="javascript:false;"></iframe>':"";b("<div class='ui-widget-overlay jqgrid-overlay' id='lui_"+this.id+"'></div>").append(l).insertBefore(j);b("<div class='loading ui-state-default ui-state-active' id='load_"+this.id+"'>"+this.p.loadtext+"</div>").insertBefore(j);b(this).attr({cellspacing:"0",cellpadding:"0",border:"0",role:"grid",
+"aria-multiselectable":!!this.p.multiselect,"aria-labelledby":"gbox_"+this.id});var o=function(a,b){a=parseInt(a,10);return isNaN(a)?b?b:0:a},p=function(d,e,f,g,i,j){var K=a.p.colModel[d],k=K.align,y='style="',z=K.classes,B=K.name,q=[];k&&(y=y+("text-align:"+k+";"));K.hidden===true&&(y=y+"display:none;");if(e===0)y=y+("width: "+c.headers[d].width+"px;");else if(K.cellattr&&b.isFunction(K.cellattr))if((d=K.cellattr.call(a,i,f,g,K,j))&&typeof d==="string"){d=d.replace(/style/i,"style").replace(/title/i,
+"title");if(d.indexOf("title")>-1)K.title=false;d.indexOf("class")>-1&&(z=void 0);q=d.split("style");if(q.length===2){q[1]=b.trim(q[1].replace("=",""));if(q[1].indexOf("'")===0||q[1].indexOf('"')===0)q[1]=q[1].substring(1);y=y+q[1].replace(/'/gi,'"')}else y=y+'"'}if(!q.length){q[0]="";y=y+'"'}y=y+((z!==void 0?' class="'+z+'"':"")+(K.title&&f?' title="'+b.jgrid.stripHtml(f)+'"':""));y=y+(' aria-describedby="'+a.p.id+"_"+B+'"');return y+q[0]},v=function(c){return c===void 0||c===null||c===""?"&#160;":
+a.p.autoencode?b.jgrid.htmlEncode(c):c+""},u=function(c,d,e,f,g){var h=a.p.colModel[e];if(typeof h.formatter!=="undefined"){c={rowId:c,colModel:h,gid:a.p.id,pos:e};d=b.isFunction(h.formatter)?h.formatter.call(a,d,c,f,g):b.fmatter?b.fn.fmatter.call(a,h.formatter,d,c,f,g):v(d)}else d=v(d);return d},M=function(a,b,c,d,e){b=u(a,b,c,e,"add");return'<td role="gridcell" '+p(c,d,b,e,a,true)+">"+b+"</td>"},F=function(b,c,d){var e='<input role="checkbox" type="checkbox" id="jqg_'+a.p.id+"_"+b+'" class="cbox" name="jqg_'+
+a.p.id+"_"+b+'"/>';return'<td role="gridcell" '+p(c,d,"",null,b,true)+">"+e+"</td>"},Z=function(a,b,c,d){c=(parseInt(c,10)-1)*parseInt(d,10)+1+b;return'<td role="gridcell" class="ui-state-default jqgrid-rownum" '+p(a,b,c,null,b,true)+">"+c+"</td>"},U=function(b){var c,d=[],e=0,f;for(f=0;f<a.p.colModel.length;f++){c=a.p.colModel[f];if(c.name!=="cb"&&c.name!=="subgrid"&&c.name!=="rn"){d[e]=b=="local"?c.name:b=="xml"||b==="xmlstring"?c.xmlmap||c.name:c.jsonmap||c.name;e++}}return d},V=function(c){var d=
+a.p.remapColumns;if(!d||!d.length)d=b.map(a.p.colModel,function(a,b){return b});c&&(d=b.map(d,function(a){return a<c?null:a-c}));return d},N=function(a,c){var d;if(this.p.deepempty)b(this.rows).slice(1).remove();else{d=this.rows.length>0?this.rows[0]:null;b(this.firstChild).empty().append(d)}if(a&&this.p.scroll){b(this.grid.bDiv.firstChild).css({height:"auto"});b(this.grid.bDiv.firstChild.firstChild).css({height:0,display:"none"});if(this.grid.bDiv.scrollTop!==0)this.grid.bDiv.scrollTop=0}if(c===
+true&&this.p.treeGrid){this.p.data=[];this.p._index={}}},S=function(){var c=a.p.data.length,d,e,f;d=a.p.rownumbers===true?1:0;e=a.p.multiselect===true?1:0;f=a.p.subGrid===true?1:0;d=a.p.keyIndex===false||a.p.loadonce===true?a.p.localReader.id:a.p.colModel[a.p.keyIndex+e+f+d].name;for(e=0;e<c;e++){f=b.jgrid.getAccessor(a.p.data[e],d);a.p._index[f]=e}},J=function(c,d,e,f,g){var h="-1",i="",j,d=d?"display:none;":"",e="ui-widget-content jqgrow ui-row-"+a.p.direction+e,f=b.isFunction(a.p.rowattr)?a.p.rowattr.call(a,
+f,g):{};if(!b.isEmptyObject(f)){if(f.hasOwnProperty("id")){c=f.id;delete f.id}if(f.hasOwnProperty("tabindex")){h=f.tabindex;delete f.tabindex}if(f.hasOwnProperty("style")){d=d+f.style;delete f.style}if(f.hasOwnProperty("class")){e=e+(" "+f["class"]);delete f["class"]}try{delete f.role}catch(k){}for(j in f)f.hasOwnProperty(j)&&(i=i+(" "+j+"="+f[j]))}return'<tr role="row" id="'+c+'" tabindex="'+h+'" class="'+e+'"'+(d===""?"":' style="'+d+'"')+i+">"},$=function(c,d,e,f,g){var h=new Date,i=a.p.datatype!=
+"local"&&a.p.loadonce||a.p.datatype=="xmlstring",j=a.p.xmlReader,k=a.p.datatype=="local"?"local":"xml";if(i){a.p.data=[];a.p._index={};a.p.localReader.id="_id_"}a.p.reccount=0;if(b.isXMLDoc(c)){if(a.p.treeANode===-1&&!a.p.scroll){N.call(a,false,true);e=1}else e=e>1?e:1;var z,B,q=0,l,s=a.p.multiselect===true?1:0,P=a.p.subGrid===true?1:0,m=a.p.rownumbers===true?1:0,o,p=[],u,n={},r,w,C=[],v=a.p.altRows===true?" "+a.p.altclass:"",A;j.repeatitems||(p=U(k));o=a.p.keyIndex===false?b.isFunction(j.id)?j.id.call(a,
+c):j.id:a.p.keyIndex;if(p.length>0&&!isNaN(o)){a.p.remapColumns&&a.p.remapColumns.length&&(o=b.inArray(o,a.p.remapColumns));o=p[o]}k=(o+"").indexOf("[")===-1?p.length?function(a,c){return b(o,a).text()||c}:function(a,c){return b(j.cell,a).eq(o).text()||c}:function(a,b){return a.getAttribute(o.replace(/[\[\]]/g,""))||b};a.p.userData={};a.p.page=b.jgrid.getXmlData(c,j.page)||0;a.p.lastpage=b.jgrid.getXmlData(c,j.total);if(a.p.lastpage===void 0)a.p.lastpage=1;a.p.records=b.jgrid.getXmlData(c,j.records)||
+0;b.isFunction(j.userdata)?a.p.userData=j.userdata.call(a,c)||{}:b.jgrid.getXmlData(c,j.userdata,true).each(function(){a.p.userData[this.getAttribute("name")]=b(this).text()});c=b.jgrid.getXmlData(c,j.root,true);(c=b.jgrid.getXmlData(c,j.row,true))||(c=[]);var t=c.length,H=0,Q=[],x=parseInt(a.p.rowNum,10);if(t>0&&a.p.page<=0)a.p.page=1;if(c&&t){var D=a.p.scroll?b.jgrid.randId():1;g&&(x=x*(g+1));for(var g=b.isFunction(a.p.afterInsertRow),E=a.p.grouping&&a.p.groupingView.groupCollapse===true;H<t;){r=
+c[H];w=k(r,D+H);w=a.p.idPrefix+w;z=e===0?0:e+1;A=(z+H)%2==1?v:"";var I=C.length;C.push("");m&&C.push(Z(0,H,a.p.page,a.p.rowNum));s&&C.push(F(w,m,H));P&&C.push(b(a).jqGrid("addSubGridCell",s+m,H+e));if(j.repeatitems){u||(u=V(s+P+m));var L=b.jgrid.getXmlData(r,j.cell,true);b.each(u,function(b){var c=L[this];if(!c)return false;l=c.textContent||c.text;n[a.p.colModel[b+s+P+m].name]=l;C.push(M(w,l,b+s+P+m,H+e,r))})}else for(z=0;z<p.length;z++){l=b.jgrid.getXmlData(r,p[z]);n[a.p.colModel[z+s+P+m].name]=
+l;C.push(M(w,l,z+s+P+m,H+e,r))}C[I]=J(w,E,A,n,r);C.push("</tr>");if(a.p.grouping){Q=b(a).jqGrid("groupingPrepare",C,Q,n,H);C=[]}if(i||a.p.treeGrid===true){n._id_=w;a.p.data.push(n);a.p._index[w]=a.p.data.length-1}if(a.p.gridview===false){b("tbody:first",d).append(C.join(""));b(a).triggerHandler("jqGridAfterInsertRow",[w,n,r]);g&&a.p.afterInsertRow.call(a,w,n,r);C=[]}n={};q++;H++;if(q==x)break}}if(a.p.gridview===true){B=a.p.treeANode>-1?a.p.treeANode:0;if(a.p.grouping){b(a).jqGrid("groupingRender",
+Q,a.p.colModel.length);Q=null}else a.p.treeGrid===true&&B>0?b(a.rows[B]).after(C.join("")):b("tbody:first",d).append(C.join(""))}if(a.p.subGrid===true)try{b(a).jqGrid("addSubGrid",s+m)}catch(R){}a.p.totaltime=new Date-h;if(q>0&&a.p.records===0)a.p.records=t;C=null;if(a.p.treeGrid===true)try{b(a).jqGrid("setTreeNode",B+1,q+B+1)}catch(S){}if(!a.p.treeGrid&&!a.p.scroll)a.grid.bDiv.scrollTop=0;a.p.reccount=q;a.p.treeANode=-1;a.p.userDataOnFooter&&b(a).jqGrid("footerData","set",a.p.userData,true);if(i){a.p.records=
+t;a.p.lastpage=Math.ceil(t/x)}f||a.updatepager(false,true);if(i)for(;q<t;){r=c[q];w=k(r,q+D);w=a.p.idPrefix+w;if(j.repeatitems){u||(u=V(s+P+m));var O=b.jgrid.getXmlData(r,j.cell,true);b.each(u,function(b){var c=O[this];if(!c)return false;l=c.textContent||c.text;n[a.p.colModel[b+s+P+m].name]=l})}else for(z=0;z<p.length;z++){l=b.jgrid.getXmlData(r,p[z]);n[a.p.colModel[z+s+P+m].name]=l}n._id_=w;a.p.data.push(n);a.p._index[w]=a.p.data.length-1;n={};q++}}},aa=function(c,d,e,f,g){d=new Date;if(c){if(a.p.treeANode===
+-1&&!a.p.scroll){N.call(a,false,true);e=1}else e=e>1?e:1;var h,i,j=a.p.datatype!="local"&&a.p.loadonce||a.p.datatype=="jsonstring";if(j){a.p.data=[];a.p._index={};a.p.localReader.id="_id_"}a.p.reccount=0;if(a.p.datatype=="local"){h=a.p.localReader;i="local"}else{h=a.p.jsonReader;i="json"}var k=0,l,B,q=[],m,s=a.p.multiselect?1:0,o=a.p.subGrid?1:0,p=a.p.rownumbers===true?1:0,n,u,t={},v,r,w=[],C=a.p.altRows===true?" "+a.p.altclass:"",A;a.p.page=b.jgrid.getAccessor(c,h.page)||0;n=b.jgrid.getAccessor(c,
+h.total);a.p.lastpage=n===void 0?1:n;a.p.records=b.jgrid.getAccessor(c,h.records)||0;a.p.userData=b.jgrid.getAccessor(c,h.userdata)||{};h.repeatitems||(m=q=U(i));i=a.p.keyIndex===false?b.isFunction(h.id)?h.id.call(a,c):h.id:a.p.keyIndex;if(q.length>0&&!isNaN(i)){a.p.remapColumns&&a.p.remapColumns.length&&(i=b.inArray(i,a.p.remapColumns));i=q[i]}(u=b.jgrid.getAccessor(c,h.root))||(u=[]);n=u.length;c=0;if(n>0&&a.p.page<=0)a.p.page=1;var x=parseInt(a.p.rowNum,10),D=a.p.scroll?b.jgrid.randId():1;g&&(x=
+x*(g+1));for(var H=b.isFunction(a.p.afterInsertRow),Q=[],E=a.p.grouping&&a.p.groupingView.groupCollapse===true;c<n;){g=u[c];r=b.jgrid.getAccessor(g,i);if(r===void 0){r=D+c;if(q.length===0&&h.cell){l=b.jgrid.getAccessor(g,h.cell);r=l!==void 0?l[i]||r:r}}r=a.p.idPrefix+r;l=e===1?0:e;A=(l+c)%2==1?C:"";var I=w.length;w.push("");p&&w.push(Z(0,c,a.p.page,a.p.rowNum));s&&w.push(F(r,p,c));o&&w.push(b(a).jqGrid("addSubGridCell",s+p,c+e));if(h.repeatitems){h.cell&&(g=b.jgrid.getAccessor(g,h.cell));m||(m=V(s+
+o+p))}for(B=0;B<m.length;B++){l=b.jgrid.getAccessor(g,m[B]);w.push(M(r,l,B+s+o+p,c+e,g));t[a.p.colModel[B+s+o+p].name]=l}w[I]=J(r,E,A,t,g);w.push("</tr>");if(a.p.grouping){Q=b(a).jqGrid("groupingPrepare",w,Q,t,c);w=[]}if(j||a.p.treeGrid===true){t._id_=r;a.p.data.push(t);a.p._index[r]=a.p.data.length-1}if(a.p.gridview===false){b("#"+b.jgrid.jqID(a.p.id)+" tbody:first").append(w.join(""));b(a).triggerHandler("jqGridAfterInsertRow",[r,t,g]);H&&a.p.afterInsertRow.call(a,r,t,g);w=[]}t={};k++;c++;if(k==
+x)break}if(a.p.gridview===true){v=a.p.treeANode>-1?a.p.treeANode:0;a.p.grouping?b(a).jqGrid("groupingRender",Q,a.p.colModel.length):a.p.treeGrid===true&&v>0?b(a.rows[v]).after(w.join("")):b("#"+b.jgrid.jqID(a.p.id)+" tbody:first").append(w.join(""))}if(a.p.subGrid===true)try{b(a).jqGrid("addSubGrid",s+p)}catch(L){}a.p.totaltime=new Date-d;if(k>0&&a.p.records===0)a.p.records=n;if(a.p.treeGrid===true)try{b(a).jqGrid("setTreeNode",v+1,k+v+1)}catch(O){}if(!a.p.treeGrid&&!a.p.scroll)a.grid.bDiv.scrollTop=
+0;a.p.reccount=k;a.p.treeANode=-1;a.p.userDataOnFooter&&b(a).jqGrid("footerData","set",a.p.userData,true);if(j){a.p.records=n;a.p.lastpage=Math.ceil(n/x)}f||a.updatepager(false,true);if(j)for(;k<n&&u[k];){g=u[k];r=b.jgrid.getAccessor(g,i);if(r===void 0){r=D+k;q.length===0&&h.cell&&(r=b.jgrid.getAccessor(g,h.cell)[i]||r)}if(g){r=a.p.idPrefix+r;if(h.repeatitems){h.cell&&(g=b.jgrid.getAccessor(g,h.cell));m||(m=V(s+o+p))}for(B=0;B<m.length;B++){l=b.jgrid.getAccessor(g,m[B]);t[a.p.colModel[B+s+o+p].name]=
+l}t._id_=r;a.p.data.push(t);a.p._index[r]=a.p.data.length-1;t={}}k++}}},ma=function(){function c(d){var e=0,g,h,i,j,T;if(d.groups!==void 0){(h=d.groups.length&&d.groupOp.toString().toUpperCase()==="OR")&&s.orBegin();for(g=0;g<d.groups.length;g++){e>0&&h&&s.or();try{c(d.groups[g])}catch(k){alert(k)}e++}h&&s.orEnd()}if(d.rules!==void 0){if(e>0){h=s.select();s=b.jgrid.from(h);a.p.ignoreCase&&(s=s.ignoreCase())}try{(i=d.rules.length&&d.groupOp.toString().toUpperCase()==="OR")&&s.orBegin();for(g=0;g<d.rules.length;g++){T=
+d.rules[g];j=d.groupOp.toString().toUpperCase();if(o[T.op]&&T.field){e>0&&j&&j==="OR"&&(s=s.or());s=o[T.op](s,j)(T.field,T.data,f[T.field])}e++}i&&s.orEnd()}catch(na){alert(na)}}}var d,e=false,f={},g=[],h=[],i,j,k;if(b.isArray(a.p.data)){var l=a.p.grouping?a.p.groupingView:false,m,q;b.each(a.p.colModel,function(){j=this.sorttype||"text";if(j=="date"||j=="datetime"){if(this.formatter&&typeof this.formatter==="string"&&this.formatter=="date"){i=this.formatoptions&&this.formatoptions.srcformat?this.formatoptions.srcformat:
+b.jgrid.formatter.date.srcformat;k=this.formatoptions&&this.formatoptions.newformat?this.formatoptions.newformat:b.jgrid.formatter.date.newformat}else i=k=this.datefmt||"Y-m-d";f[this.name]={stype:j,srcfmt:i,newfmt:k}}else f[this.name]={stype:j,srcfmt:"",newfmt:""};if(a.p.grouping){q=0;for(m=l.groupField.length;q<m;q++)if(this.name==l.groupField[q]){var c=this.name;if(typeof this.index!="undefined")c=this.index;g[q]=f[c];h[q]=c}}if(!e&&(this.index==a.p.sortname||this.name==a.p.sortname)){d=this.name;
+e=true}});if(a.p.treeGrid)b(a).jqGrid("SortTree",d,a.p.sortorder,f[d].stype,f[d].srcfmt);else{var o={eq:function(a){return a.equals},ne:function(a){return a.notEquals},lt:function(a){return a.less},le:function(a){return a.lessOrEquals},gt:function(a){return a.greater},ge:function(a){return a.greaterOrEquals},cn:function(a){return a.contains},nc:function(a,b){return b==="OR"?a.orNot().contains:a.andNot().contains},bw:function(a){return a.startsWith},bn:function(a,b){return b==="OR"?a.orNot().startsWith:
+a.andNot().startsWith},en:function(a,b){return b==="OR"?a.orNot().endsWith:a.andNot().endsWith},ew:function(a){return a.endsWith},ni:function(a,b){return b==="OR"?a.orNot().equals:a.andNot().equals},"in":function(a){return a.equals},nu:function(a){return a.isNull},nn:function(a,b){return b==="OR"?a.orNot().isNull:a.andNot().isNull}},s=b.jgrid.from(a.p.data);a.p.ignoreCase&&(s=s.ignoreCase());if(a.p.search===true){var n=a.p.postData.filters;if(n){typeof n=="string"&&(n=b.jgrid.parse(n));c(n)}else try{s=
+o[a.p.postData.searchOper](s)(a.p.postData.searchField,a.p.postData.searchString,f[a.p.postData.searchField])}catch(p){}}if(a.p.grouping)for(q=0;q<m;q++)s.orderBy(h[q],l.groupOrder[q],g[q].stype,g[q].srcfmt);d&&a.p.sortorder&&e&&(a.p.sortorder.toUpperCase()=="DESC"?s.orderBy(a.p.sortname,"d",f[d].stype,f[d].srcfmt):s.orderBy(a.p.sortname,"a",f[d].stype,f[d].srcfmt));var n=s.select(),u=parseInt(a.p.rowNum,10),t=n.length,v=parseInt(a.p.page,10),x=Math.ceil(t/u),r={},n=n.slice((v-1)*u,v*u),f=s=null;
+r[a.p.localReader.total]=x;r[a.p.localReader.page]=v;r[a.p.localReader.records]=t;r[a.p.localReader.root]=n;r[a.p.localReader.userdata]=a.p.userData;n=null;return r}}},ca=function(){a.grid.hDiv.loading=true;if(!a.p.hiddengrid)switch(a.p.loadui){case "enable":b("#load_"+b.jgrid.jqID(a.p.id)).show();break;case "block":b("#lui_"+b.jgrid.jqID(a.p.id)).show();b("#load_"+b.jgrid.jqID(a.p.id)).show()}},O=function(){a.grid.hDiv.loading=false;switch(a.p.loadui){case "enable":b("#load_"+b.jgrid.jqID(a.p.id)).hide();
+break;case "block":b("#lui_"+b.jgrid.jqID(a.p.id)).hide();b("#load_"+b.jgrid.jqID(a.p.id)).hide()}},I=function(c){if(!a.grid.hDiv.loading){var d=a.p.scroll&&c===false,e={},f,g=a.p.prmNames;if(a.p.page<=0)a.p.page=1;if(g.search!==null)e[g.search]=a.p.search;g.nd!==null&&(e[g.nd]=(new Date).getTime());if(g.rows!==null)e[g.rows]=a.p.rowNum;if(g.page!==null)e[g.page]=a.p.page;if(g.sort!==null)e[g.sort]=a.p.sortname;if(g.order!==null)e[g.order]=a.p.sortorder;if(a.p.rowTotal!==null&&g.totalrows!==null)e[g.totalrows]=
+a.p.rowTotal;var h=b.isFunction(a.p.loadComplete),i=h?a.p.loadComplete:null,j=0,c=c||1;if(c>1)if(g.npage!==null){e[g.npage]=c;j=c-1;c=1}else i=function(b){a.p.page++;a.grid.hDiv.loading=false;h&&a.p.loadComplete.call(a,b);I(c-1)};else g.npage!==null&&delete a.p.postData[g.npage];if(a.p.grouping){b(a).jqGrid("groupingSetup");var k=a.p.groupingView,l,m="";for(l=0;l<k.groupField.length;l++)m=m+(k.groupField[l]+" "+k.groupOrder[l]+", ");e[g.sort]=m+e[g.sort]}b.extend(a.p.postData,e);var q=!a.p.scroll?
+1:a.rows.length-1,e=b(a).triggerHandler("jqGridBeforeRequest");if(!(e===false||e==="stop"))if(b.isFunction(a.p.datatype))a.p.datatype.call(a,a.p.postData,"load_"+a.p.id);else{if(b.isFunction(a.p.beforeRequest)){e=a.p.beforeRequest.call(a);e===void 0&&(e=true);if(e===false)return}f=a.p.datatype.toLowerCase();switch(f){case "json":case "jsonp":case "xml":case "script":b.ajax(b.extend({url:a.p.url,type:a.p.mtype,dataType:f,data:b.isFunction(a.p.serializeGridData)?a.p.serializeGridData.call(a,a.p.postData):
+a.p.postData,success:function(e,g,h){if(b.isFunction(a.p.beforeProcessing)&&a.p.beforeProcessing.call(a,e,g,h)===false)O();else{f==="xml"?$(e,a.grid.bDiv,q,c>1,j):aa(e,a.grid.bDiv,q,c>1,j);b(a).triggerHandler("jqGridLoadComplete",[e]);i&&i.call(a,e);b(a).triggerHandler("jqGridAfterLoadComplete",[e]);d&&a.grid.populateVisible();if(a.p.loadonce||a.p.treeGrid)a.p.datatype="local";c===1&&O()}},error:function(d,e,f){b.isFunction(a.p.loadError)&&a.p.loadError.call(a,d,e,f);c===1&&O()},beforeSend:function(c,
+d){var e=true;b.isFunction(a.p.loadBeforeSend)&&(e=a.p.loadBeforeSend.call(a,c,d));e===void 0&&(e=true);if(e===false)return false;ca()}},b.jgrid.ajaxOptions,a.p.ajaxGridOptions));break;case "xmlstring":ca();e=b.jgrid.stringToDoc(a.p.datastr);$(e,a.grid.bDiv);b(a).triggerHandler("jqGridLoadComplete",[e]);h&&a.p.loadComplete.call(a,e);b(a).triggerHandler("jqGridAfterLoadComplete",[e]);a.p.datatype="local";a.p.datastr=null;O();break;case "jsonstring":ca();e=typeof a.p.datastr=="string"?b.jgrid.parse(a.p.datastr):
+a.p.datastr;aa(e,a.grid.bDiv);b(a).triggerHandler("jqGridLoadComplete",[e]);h&&a.p.loadComplete.call(a,e);b(a).triggerHandler("jqGridAfterLoadComplete",[e]);a.p.datatype="local";a.p.datastr=null;O();break;case "local":case "clientside":ca();a.p.datatype="local";e=ma();aa(e,a.grid.bDiv,q,c>1,j);b(a).triggerHandler("jqGridLoadComplete",[e]);i&&i.call(a,e);b(a).triggerHandler("jqGridAfterLoadComplete",[e]);d&&a.grid.populateVisible();O()}}}},da=function(c){b("#cb_"+b.jgrid.jqID(a.p.id),a.grid.hDiv)[a.p.useProp?
+"prop":"attr"]("checked",c);if(a.p.frozenColumns&&a.p.id+"_frozen")b("#cb_"+b.jgrid.jqID(a.p.id),a.grid.fhDiv)[a.p.useProp?"prop":"attr"]("checked",c)};l=function(c,e){var d="",f="<table cellspacing='0' cellpadding='0' border='0' style='table-layout:auto;' class='ui-pg-table'><tbody><tr>",g="",h,j,k,l,m=function(c){var e;b.isFunction(a.p.onPaging)&&(e=a.p.onPaging.call(a,c));a.p.selrow=null;if(a.p.multiselect){a.p.selarrrow=[];da(false)}a.p.savedRow=[];return e=="stop"?false:true},c=c.substr(1),e=
+e+("_"+c);h="pg_"+c;j=c+"_left";k=c+"_center";l=c+"_right";b("#"+b.jgrid.jqID(c)).append("<div id='"+h+"' class='ui-pager-control' role='group'><table cellspacing='0' cellpadding='0' border='0' class='ui-pg-table' style='width:100%;table-layout:fixed;height:100%;' role='row'><tbody><tr><td id='"+j+"' align='left'></td><td id='"+k+"' align='center' style='white-space:pre;'></td><td id='"+l+"' align='right'></td></tr></tbody></table></div>").attr("dir","ltr");if(a.p.rowList.length>0){g="<td dir='"+
+i+"'>";g=g+"<select class='ui-pg-selbox' role='listbox'>";for(j=0;j<a.p.rowList.length;j++)g=g+('<option role="option" value="'+a.p.rowList[j]+'"'+(a.p.rowNum==a.p.rowList[j]?' selected="selected"':"")+">"+a.p.rowList[j]+"</option>");g=g+"</select></td>"}i=="rtl"&&(f=f+g);a.p.pginput===true&&(d="<td dir='"+i+"'>"+b.jgrid.format(a.p.pgtext||"","<input class='ui-pg-input' type='text' size='2' maxlength='7' value='0' role='textbox'/>","<span id='sp_1_"+b.jgrid.jqID(c)+"'></span>")+"</td>");if(a.p.pgbuttons===
+true){j=["first"+e,"prev"+e,"next"+e,"last"+e];i=="rtl"&&j.reverse();f=f+("<td id='"+j[0]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-first'></span></td>");f=f+("<td id='"+j[1]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-prev'></span></td>");f=f+(d!==""?"<td class='ui-pg-button ui-state-disabled' style='width:4px;'><span class='ui-separator'></span></td>"+d+"<td class='ui-pg-button ui-state-disabled' style='width:4px;'><span class='ui-separator'></span></td>":
+"")+("<td id='"+j[2]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-next'></span></td>");f=f+("<td id='"+j[3]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-end'></span></td>")}else d!==""&&(f=f+d);i=="ltr"&&(f=f+g);f=f+"</tr></tbody></table>";a.p.viewrecords===true&&b("td#"+c+"_"+a.p.recordpos,"#"+h).append("<div dir='"+i+"' style='text-align:"+a.p.recordpos+"' class='ui-paging-info'></div>");b("td#"+c+"_"+a.p.pagerpos,"#"+h).append(f);g=b(".ui-jqgrid").css("font-size")||
+"11px";b(document.body).append("<div id='testpg' class='ui-jqgrid ui-widget ui-widget-content' style='font-size:"+g+";visibility:hidden;' ></div>");f=b(f).clone().appendTo("#testpg").width();b("#testpg").remove();if(f>0){d!==""&&(f=f+50);b("td#"+c+"_"+a.p.pagerpos,"#"+h).width(f)}a.p._nvtd=[];a.p._nvtd[0]=f?Math.floor((a.p.width-f)/2):Math.floor(a.p.width/3);a.p._nvtd[1]=0;f=null;b(".ui-pg-selbox","#"+h).bind("change",function(){a.p.page=Math.round(a.p.rowNum*(a.p.page-1)/this.value-0.5)+1;a.p.rowNum=
+this.value;a.p.pager&&b(".ui-pg-selbox",a.p.pager).val(this.value);a.p.toppager&&b(".ui-pg-selbox",a.p.toppager).val(this.value);if(!m("records"))return false;I();return false});if(a.p.pgbuttons===true){b(".ui-pg-button","#"+h).hover(function(){if(b(this).hasClass("ui-state-disabled"))this.style.cursor="default";else{b(this).addClass("ui-state-hover");this.style.cursor="pointer"}},function(){if(!b(this).hasClass("ui-state-disabled")){b(this).removeClass("ui-state-hover");this.style.cursor="default"}});
+b("#first"+b.jgrid.jqID(e)+", #prev"+b.jgrid.jqID(e)+", #next"+b.jgrid.jqID(e)+", #last"+b.jgrid.jqID(e)).click(function(){var b=o(a.p.page,1),c=o(a.p.lastpage,1),d=false,f=true,g=true,h=true,i=true;if(c===0||c===1)i=h=g=f=false;else if(c>1&&b>=1)if(b===1)g=f=false;else{if(b===c)i=h=false}else if(c>1&&b===0){i=h=false;b=c-1}if(this.id==="first"+e&&f){a.p.page=1;d=true}if(this.id==="prev"+e&&g){a.p.page=b-1;d=true}if(this.id==="next"+e&&h){a.p.page=b+1;d=true}if(this.id==="last"+e&&i){a.p.page=c;d=
+true}if(d){if(!m(this.id))return false;I()}return false})}a.p.pginput===true&&b("input.ui-pg-input","#"+h).keypress(function(c){if((c.charCode?c.charCode:c.keyCode?c.keyCode:0)==13){a.p.page=b(this).val()>0?b(this).val():a.p.page;if(!m("user"))return false;I();return false}return this})};var ja=function(c,e,d,f){if(a.p.colModel[e].sortable&&!(a.p.savedRow.length>0)){if(!d){if(a.p.lastsort==e)if(a.p.sortorder=="asc")a.p.sortorder="desc";else{if(a.p.sortorder=="desc")a.p.sortorder="asc"}else a.p.sortorder=
+a.p.colModel[e].firstsortorder||"asc";a.p.page=1}if(f){if(a.p.lastsort==e&&a.p.sortorder==f&&!d)return;a.p.sortorder=f}d=a.grid.headers[a.p.lastsort].el;f=a.grid.headers[e].el;b("span.ui-grid-ico-sort",d).addClass("ui-state-disabled");b(d).attr("aria-selected","false");b("span.ui-icon-"+a.p.sortorder,f).removeClass("ui-state-disabled");b(f).attr("aria-selected","true");if(!a.p.viewsortcols[0]&&a.p.lastsort!=e){b("span.s-ico",d).hide();b("span.s-ico",f).show()}c=c.substring(5+a.p.id.length+1);a.p.sortname=
+a.p.colModel[e].index||c;d=a.p.sortorder;if(b(a).triggerHandler("jqGridSortCol",[c,e,d])==="stop")a.p.lastsort=e;else if(b.isFunction(a.p.onSortCol)&&a.p.onSortCol.call(a,c,e,d)=="stop")a.p.lastsort=e;else{if(a.p.datatype=="local")a.p.deselectAfterSort&&b(a).jqGrid("resetSelection");else{a.p.selrow=null;a.p.multiselect&&da(false);a.p.selarrrow=[];a.p.savedRow=[]}if(a.p.scroll){d=a.grid.bDiv.scrollLeft;N.call(a,true,false);a.grid.hDiv.scrollLeft=d}a.p.subGrid&&a.p.datatype=="local"&&b("td.sgexpanded",
+"#"+b.jgrid.jqID(a.p.id)).each(function(){b(this).trigger("click")});I();a.p.lastsort=e;if(a.p.sortname!=c&&e)a.p.lastsort=e}}},oa=function(c){var e,d={},f=b.jgrid.cellWidth()?0:a.p.cellLayout;for(e=d[0]=d[1]=d[2]=0;e<=c;e++)a.p.colModel[e].hidden===false&&(d[0]=d[0]+(a.p.colModel[e].width+f));a.p.direction=="rtl"&&(d[0]=a.p.width-d[0]);d[0]=d[0]-a.grid.bDiv.scrollLeft;b(a.grid.cDiv).is(":visible")&&(d[1]=d[1]+(b(a.grid.cDiv).height()+parseInt(b(a.grid.cDiv).css("padding-top"),10)+parseInt(b(a.grid.cDiv).css("padding-bottom"),
+10)));if(a.p.toolbar[0]===true&&(a.p.toolbar[1]=="top"||a.p.toolbar[1]=="both"))d[1]=d[1]+(b(a.grid.uDiv).height()+parseInt(b(a.grid.uDiv).css("border-top-width"),10)+parseInt(b(a.grid.uDiv).css("border-bottom-width"),10));a.p.toppager&&(d[1]=d[1]+(b(a.grid.topDiv).height()+parseInt(b(a.grid.topDiv).css("border-bottom-width"),10)));d[2]=d[2]+(b(a.grid.bDiv).height()+b(a.grid.hDiv).height());return d},ka=function(c){var d,e=a.grid.headers,f=b.jgrid.getCellIndex(c);for(d=0;d<e.length;d++)if(c===e[d].el){f=
+d;break}return f};this.p.id=this.id;-1==b.inArray(a.p.multikey,["shiftKey","altKey","ctrlKey"])&&(a.p.multikey=!1);a.p.keyIndex=!1;for(e=0;e<a.p.colModel.length;e++)a.p.colModel[e]=b.extend(!0,{},a.p.cmTemplate,a.p.colModel[e].template||{},a.p.colModel[e]),!1===a.p.keyIndex&&!0===a.p.colModel[e].key&&(a.p.keyIndex=e);a.p.sortorder=a.p.sortorder.toLowerCase();!0===a.p.grouping&&(a.p.scroll=!1,a.p.rownumbers=!1,a.p.treeGrid=!1,a.p.gridview=!0);if(!0===this.p.treeGrid){try{b(this).jqGrid("setTreeGrid")}catch(qa){}"local"!=
+a.p.datatype&&(a.p.localReader={id:"_id_"})}if(this.p.subGrid)try{b(a).jqGrid("setSubGrid")}catch(ra){}this.p.multiselect&&(this.p.colNames.unshift("<input role='checkbox' id='cb_"+this.p.id+"' class='cbox' type='checkbox'/>"),this.p.colModel.unshift({name:"cb",width:b.jgrid.cellWidth()?a.p.multiselectWidth+a.p.cellLayout:a.p.multiselectWidth,sortable:!1,resizable:!1,hidedlg:!0,search:!1,align:"center",fixed:!0}));this.p.rownumbers&&(this.p.colNames.unshift(""),this.p.colModel.unshift({name:"rn",
+width:a.p.rownumWidth,sortable:!1,resizable:!1,hidedlg:!0,search:!1,align:"center",fixed:!0}));a.p.xmlReader=b.extend(!0,{root:"rows",row:"row",page:"rows>page",total:"rows>total",records:"rows>records",repeatitems:!0,cell:"cell",id:"[id]",userdata:"userdata",subgrid:{root:"rows",row:"row",repeatitems:!0,cell:"cell"}},a.p.xmlReader);a.p.jsonReader=b.extend(!0,{root:"rows",page:"page",total:"total",records:"records",repeatitems:!0,cell:"cell",id:"id",userdata:"userdata",subgrid:{root:"rows",repeatitems:!0,
+cell:"cell"}},a.p.jsonReader);a.p.localReader=b.extend(!0,{root:"rows",page:"page",total:"total",records:"records",repeatitems:!1,cell:"cell",id:"id",userdata:"userdata",subgrid:{root:"rows",repeatitems:!0,cell:"cell"}},a.p.localReader);a.p.scroll&&(a.p.pgbuttons=!1,a.p.pginput=!1,a.p.rowList=[]);a.p.data.length&&S();var x="<thead><tr class='ui-jqgrid-labels' role='rowheader'>",la,L,ea,ba,fa,A,n,W;L=W="";if(!0===a.p.shrinkToFit&&!0===a.p.forceFit)for(e=a.p.colModel.length-1;0<=e;e--)if(!a.p.colModel[e].hidden){a.p.colModel[e].resizable=
+!1;break}"horizontal"==a.p.viewsortcols[1]&&(W=" ui-i-asc",L=" ui-i-desc");la=k?"class='ui-th-div-ie'":"";W="<span class='s-ico' style='display:none'><span sort='asc' class='ui-grid-ico-sort ui-icon-asc"+W+" ui-state-disabled ui-icon ui-icon-triangle-1-n ui-sort-"+i+"'></span>"+("<span sort='desc' class='ui-grid-ico-sort ui-icon-desc"+L+" ui-state-disabled ui-icon ui-icon-triangle-1-s ui-sort-"+i+"'></span></span>");for(e=0;e<this.p.colNames.length;e++)L=a.p.headertitles?' title="'+b.jgrid.stripHtml(a.p.colNames[e])+
+'"':"",x+="<th id='"+a.p.id+"_"+a.p.colModel[e].name+"' role='columnheader' class='ui-state-default ui-th-column ui-th-"+i+"'"+L+">",L=a.p.colModel[e].index||a.p.colModel[e].name,x+="<div id='jqgh_"+a.p.id+"_"+a.p.colModel[e].name+"' "+la+">"+a.p.colNames[e],a.p.colModel[e].width=a.p.colModel[e].width?parseInt(a.p.colModel[e].width,10):150,"boolean"!==typeof a.p.colModel[e].title&&(a.p.colModel[e].title=!0),L==a.p.sortname&&(a.p.lastsort=e),x+=W+"</div></th>";W=null;b(this).append(x+"</tr></thead>");
+b("thead tr:first th",this).hover(function(){b(this).addClass("ui-state-hover")},function(){b(this).removeClass("ui-state-hover")});if(this.p.multiselect){var ga=[],X;b("#cb_"+b.jgrid.jqID(a.p.id),this).bind("click",function(){a.p.selarrrow=[];var c=a.p.frozenColumns===true?a.p.id+"_frozen":"";if(this.checked){b(a.rows).each(function(d){if(d>0&&!b(this).hasClass("ui-subgrid")&&!b(this).hasClass("jqgroup")&&!b(this).hasClass("ui-state-disabled")){b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+b.jgrid.jqID(this.id))[a.p.useProp?
+"prop":"attr"]("checked",true);b(this).addClass("ui-state-highlight").attr("aria-selected","true");a.p.selarrrow.push(this.id);a.p.selrow=this.id;if(c){b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+b.jgrid.jqID(this.id),a.grid.fbDiv)[a.p.useProp?"prop":"attr"]("checked",true);b("#"+b.jgrid.jqID(this.id),a.grid.fbDiv).addClass("ui-state-highlight")}}});X=true;ga=[]}else{b(a.rows).each(function(d){if(d>0&&!b(this).hasClass("ui-subgrid")&&!b(this).hasClass("ui-state-disabled")){b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+
+b.jgrid.jqID(this.id))[a.p.useProp?"prop":"attr"]("checked",false);b(this).removeClass("ui-state-highlight").attr("aria-selected","false");ga.push(this.id);if(c){b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+b.jgrid.jqID(this.id),a.grid.fbDiv)[a.p.useProp?"prop":"attr"]("checked",false);b("#"+b.jgrid.jqID(this.id),a.grid.fbDiv).removeClass("ui-state-highlight")}}});a.p.selrow=null;X=false}b(a).triggerHandler("jqGridSelectAll",[X?a.p.selarrrow:ga,X]);b.isFunction(a.p.onSelectAll)&&a.p.onSelectAll.call(a,X?a.p.selarrrow:
+ga,X)})}!0===a.p.autowidth&&(x=b(m).innerWidth(),a.p.width=0<x?x:"nw");(function(){var d=0,e=b.jgrid.cellWidth()?0:o(a.p.cellLayout,0),f=0,g,i=o(a.p.scrollOffset,0),j,k=false,l,m=0,n=0,p;b.each(a.p.colModel,function(){if(typeof this.hidden==="undefined")this.hidden=false;this.widthOrg=j=o(this.width,0);if(this.hidden===false){d=d+(j+e);this.fixed?m=m+(j+e):f++;n++}});if(isNaN(a.p.width))a.p.width=d+(a.p.shrinkToFit===false&&!isNaN(a.p.height)?i:0);c.width=a.p.width;a.p.tblwidth=d;if(a.p.shrinkToFit===
+false&&a.p.forceFit===true)a.p.forceFit=false;if(a.p.shrinkToFit===true&&f>0){l=c.width-e*f-m;if(!isNaN(a.p.height)){l=l-i;k=true}d=0;b.each(a.p.colModel,function(b){if(this.hidden===false&&!this.fixed){this.width=j=Math.round(l*this.width/(a.p.tblwidth-e*f-m));d=d+j;g=b}});p=0;k?c.width-m-(d+e*f)!==i&&(p=c.width-m-(d+e*f)-i):!k&&Math.abs(c.width-m-(d+e*f))!==1&&(p=c.width-m-(d+e*f));a.p.colModel[g].width=a.p.colModel[g].width+p;a.p.tblwidth=d+p+e*f+m;if(a.p.tblwidth>a.p.width){a.p.colModel[g].width=
+a.p.colModel[g].width-(a.p.tblwidth-parseInt(a.p.width,10));a.p.tblwidth=a.p.width}}})();b(m).css("width",c.width+"px").append("<div class='ui-jqgrid-resize-mark' id='rs_m"+a.p.id+"'>&#160;</div>");b(j).css("width",c.width+"px");var x=b("thead:first",a).get(0),R="";a.p.footerrow&&(R+="<table role='grid' style='width:"+a.p.tblwidth+"px' class='ui-jqgrid-ftable' cellspacing='0' cellpadding='0' border='0'><tbody><tr role='row' class='ui-widget-content footrow footrow-"+i+"'>");var j=b("tr:first",x),
+Y="<tr class='jqgfirstrow' role='row' style='height:auto'>";a.p.disableClick=!1;b("th",j).each(function(d){ea=a.p.colModel[d].width;if(typeof a.p.colModel[d].resizable==="undefined")a.p.colModel[d].resizable=true;if(a.p.colModel[d].resizable){ba=document.createElement("span");b(ba).html("&#160;").addClass("ui-jqgrid-resize ui-jqgrid-resize-"+i);b.browser.opera||b(ba).css("cursor","col-resize");b(this).addClass(a.p.resizeclass)}else ba="";b(this).css("width",ea+"px").prepend(ba);var e="";if(a.p.colModel[d].hidden){b(this).css("display",
+"none");e="display:none;"}Y=Y+("<td role='gridcell' style='height:0px;width:"+ea+"px;"+e+"'></td>");c.headers[d]={width:ea,el:this};fa=a.p.colModel[d].sortable;if(typeof fa!=="boolean")fa=a.p.colModel[d].sortable=true;e=a.p.colModel[d].name;e=="cb"||e=="subgrid"||e=="rn"||a.p.viewsortcols[2]&&b(">div",this).addClass("ui-jqgrid-sortable");if(fa)if(a.p.viewsortcols[0]){b("div span.s-ico",this).show();d==a.p.lastsort&&b("div span.ui-icon-"+a.p.sortorder,this).removeClass("ui-state-disabled")}else if(d==
+a.p.lastsort){b("div span.s-ico",this).show();b("div span.ui-icon-"+a.p.sortorder,this).removeClass("ui-state-disabled")}a.p.footerrow&&(R=R+("<td role='gridcell' "+p(d,0,"",null,"",false)+">&#160;</td>"))}).mousedown(function(d){if(b(d.target).closest("th>span.ui-jqgrid-resize").length==1){var e=ka(this);if(a.p.forceFit===true){var f=a.p,g=e,i;for(i=e+1;i<a.p.colModel.length;i++)if(a.p.colModel[i].hidden!==true){g=i;break}f.nv=g-e}c.dragStart(e,d,oa(e));return false}}).click(function(c){if(a.p.disableClick)return a.p.disableClick=
+false;var d="th>div.ui-jqgrid-sortable",e,f;a.p.viewsortcols[2]||(d="th>div>span>span.ui-grid-ico-sort");c=b(c.target).closest(d);if(c.length==1){d=ka(this);if(!a.p.viewsortcols[2]){e=true;f=c.attr("sort")}ja(b("div",this)[0].id,d,e,f);return false}});if(a.p.sortable&&b.fn.sortable)try{b(a).jqGrid("sortableColumns",j)}catch(sa){}a.p.footerrow&&(R+="</tr></tbody></table>");Y+="</tr>";this.appendChild(document.createElement("tbody"));b(this).addClass("ui-jqgrid-btable").append(Y);var Y=null,j=b("<table class='ui-jqgrid-htable' style='width:"+
+a.p.tblwidth+"px' role='grid' aria-labelledby='gbox_"+this.id+"' cellspacing='0' cellpadding='0' border='0'></table>").append(x),D=a.p.caption&&!0===a.p.hiddengrid?!0:!1;e=b("<div class='ui-jqgrid-hbox"+("rtl"==i?"-rtl":"")+"'></div>");x=null;c.hDiv=document.createElement("div");b(c.hDiv).css({width:c.width+"px"}).addClass("ui-state-default ui-jqgrid-hdiv").append(e);b(e).append(j);j=null;D&&b(c.hDiv).hide();a.p.pager&&("string"==typeof a.p.pager?"#"!=a.p.pager.substr(0,1)&&(a.p.pager="#"+a.p.pager):
+a.p.pager="#"+b(a.p.pager).attr("id"),b(a.p.pager).css({width:c.width+"px"}).appendTo(m).addClass("ui-state-default ui-jqgrid-pager ui-corner-bottom"),D&&b(a.p.pager).hide(),l(a.p.pager,""));!1===a.p.cellEdit&&!0===a.p.hoverrows&&b(a).bind("mouseover",function(a){n=b(a.target).closest("tr.jqgrow");b(n).attr("class")!=="ui-subgrid"&&b(n).addClass("ui-state-hover")}).bind("mouseout",function(a){n=b(a.target).closest("tr.jqgrow");b(n).removeClass("ui-state-hover")});var t,E,ha;b(a).before(c.hDiv).click(function(c){A=
+c.target;n=b(A,a.rows).closest("tr.jqgrow");if(b(n).length===0||n[0].className.indexOf("ui-state-disabled")>-1||(b(A,a).closest("table.ui-jqgrid-btable").attr("id")||"").replace("_frozen","")!==a.id)return this;var d=b(A).hasClass("cbox"),e=b(a).triggerHandler("jqGridBeforeSelectRow",[n[0].id,c]);(e=e===false||e==="stop"?false:true)&&b.isFunction(a.p.beforeSelectRow)&&(e=a.p.beforeSelectRow.call(a,n[0].id,c));if(!(A.tagName=="A"||(A.tagName=="INPUT"||A.tagName=="TEXTAREA"||A.tagName=="OPTION"||A.tagName==
+"SELECT")&&!d)&&e===true){t=n[0].id;E=b.jgrid.getCellIndex(A);ha=b(A).closest("td,th").html();b(a).triggerHandler("jqGridCellSelect",[t,E,ha,c]);b.isFunction(a.p.onCellSelect)&&a.p.onCellSelect.call(a,t,E,ha,c);if(a.p.cellEdit===true)if(a.p.multiselect&&d)b(a).jqGrid("setSelection",t,true,c);else{t=n[0].rowIndex;try{b(a).jqGrid("editCell",t,E,true)}catch(f){}}else if(a.p.multikey)if(c[a.p.multikey])b(a).jqGrid("setSelection",t,true,c);else{if(a.p.multiselect&&d){d=b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+
+t).is(":checked");b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+t)[a.p.useProp?"prop":"attr"]("checked",d)}}else{if(a.p.multiselect&&a.p.multiboxonly&&!d){var g=a.p.frozenColumns?a.p.id+"_frozen":"";b(a.p.selarrrow).each(function(c,d){var e=a.rows.namedItem(d);b(e).removeClass("ui-state-highlight");b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+b.jgrid.jqID(d))[a.p.useProp?"prop":"attr"]("checked",false);if(g){b("#"+b.jgrid.jqID(d),"#"+b.jgrid.jqID(g)).removeClass("ui-state-highlight");b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+
+b.jgrid.jqID(d),"#"+b.jgrid.jqID(g))[a.p.useProp?"prop":"attr"]("checked",false)}});a.p.selarrrow=[]}b(a).jqGrid("setSelection",t,true,c)}}}).bind("reloadGrid",function(c,d){if(a.p.treeGrid===true)a.p.datatype=a.p.treedatatype;d&&d.current&&a.grid.selectionPreserver(a);if(a.p.datatype=="local"){b(a).jqGrid("resetSelection");a.p.data.length&&S()}else if(!a.p.treeGrid){a.p.selrow=null;if(a.p.multiselect){a.p.selarrrow=[];da(false)}a.p.savedRow=[]}a.p.scroll&&N.call(a,true,false);if(d&&d.page){var e=
+d.page;if(e>a.p.lastpage)e=a.p.lastpage;e<1&&(e=1);a.p.page=e;a.grid.bDiv.scrollTop=a.grid.prevRowHeight?(e-1)*a.grid.prevRowHeight*a.p.rowNum:0}if(a.grid.prevRowHeight&&a.p.scroll){delete a.p.lastpage;a.grid.populateVisible()}else a.grid.populate();a.p._inlinenav===true&&b(a).jqGrid("showAddEditButtons");return false}).dblclick(function(c){A=c.target;n=b(A,a.rows).closest("tr.jqgrow");if(b(n).length!==0){t=n[0].rowIndex;E=b.jgrid.getCellIndex(A);b(a).triggerHandler("jqGridDblClickRow",[b(n).attr("id"),
+t,E,c]);b.isFunction(this.p.ondblClickRow)&&a.p.ondblClickRow.call(a,b(n).attr("id"),t,E,c)}}).bind("contextmenu",function(c){A=c.target;n=b(A,a.rows).closest("tr.jqgrow");if(b(n).length!==0){a.p.multiselect||b(a).jqGrid("setSelection",n[0].id,true,c);t=n[0].rowIndex;E=b.jgrid.getCellIndex(A);b(a).triggerHandler("jqGridRightClickRow",[b(n).attr("id"),t,E,c]);b.isFunction(this.p.onRightClickRow)&&a.p.onRightClickRow.call(a,b(n).attr("id"),t,E,c)}});c.bDiv=document.createElement("div");k&&"auto"===
+(""+a.p.height).toLowerCase()&&(a.p.height="100%");b(c.bDiv).append(b('<div style="position:relative;'+(k&&8>b.browser.version?"height:0.01%;":"")+'"></div>').append("<div></div>").append(this)).addClass("ui-jqgrid-bdiv").css({height:a.p.height+(isNaN(a.p.height)?"":"px"),width:c.width+"px"}).scroll(c.scrollGrid);b("table:first",c.bDiv).css({width:a.p.tblwidth+"px"});k?(2==b("tbody",this).size()&&b("tbody:gt(0)",this).remove(),a.p.multikey&&b(c.bDiv).bind("selectstart",function(){return false})):
+a.p.multikey&&b(c.bDiv).bind("mousedown",function(){return false});D&&b(c.bDiv).hide();c.cDiv=document.createElement("div");var ia=!0===a.p.hidegrid?b("<a role='link' href='javascript:void(0)'/>").addClass("ui-jqgrid-titlebar-close HeaderButton").hover(function(){ia.addClass("ui-state-hover")},function(){ia.removeClass("ui-state-hover")}).append("<span class='ui-icon ui-icon-circle-triangle-n'></span>").css("rtl"==i?"left":"right","0px"):"";b(c.cDiv).append(ia).append("<span class='ui-jqgrid-title"+
+("rtl"==i?"-rtl":"")+"'>"+a.p.caption+"</span>").addClass("ui-jqgrid-titlebar ui-widget-header ui-corner-top ui-helper-clearfix");b(c.cDiv).insertBefore(c.hDiv);a.p.toolbar[0]&&(c.uDiv=document.createElement("div"),"top"==a.p.toolbar[1]?b(c.uDiv).insertBefore(c.hDiv):"bottom"==a.p.toolbar[1]&&b(c.uDiv).insertAfter(c.hDiv),"both"==a.p.toolbar[1]?(c.ubDiv=document.createElement("div"),b(c.uDiv).insertBefore(c.hDiv).addClass("ui-userdata ui-state-default").attr("id","t_"+this.id),b(c.ubDiv).insertAfter(c.hDiv).addClass("ui-userdata ui-state-default").attr("id",
+"tb_"+this.id),D&&b(c.ubDiv).hide()):b(c.uDiv).width(c.width).addClass("ui-userdata ui-state-default").attr("id","t_"+this.id),D&&b(c.uDiv).hide());a.p.toppager&&(a.p.toppager=b.jgrid.jqID(a.p.id)+"_toppager",c.topDiv=b("<div id='"+a.p.toppager+"'></div>")[0],a.p.toppager="#"+a.p.toppager,b(c.topDiv).insertBefore(c.hDiv).addClass("ui-state-default ui-jqgrid-toppager").width(c.width),l(a.p.toppager,"_t"));a.p.footerrow&&(c.sDiv=b("<div class='ui-jqgrid-sdiv'></div>")[0],e=b("<div class='ui-jqgrid-hbox"+
+("rtl"==i?"-rtl":"")+"'></div>"),b(c.sDiv).append(e).insertAfter(c.hDiv).width(c.width),b(e).append(R),c.footers=b(".ui-jqgrid-ftable",c.sDiv)[0].rows[0].cells,a.p.rownumbers&&(c.footers[0].className="ui-state-default jqgrid-rownum"),D&&b(c.sDiv).hide());e=null;if(a.p.caption){var pa=a.p.datatype;!0===a.p.hidegrid&&(b(".ui-jqgrid-titlebar-close",c.cDiv).click(function(d){var e=b.isFunction(a.p.onHeaderClick),f=".ui-jqgrid-bdiv, .ui-jqgrid-hdiv, .ui-jqgrid-pager, .ui-jqgrid-sdiv",g,i=this;if(a.p.toolbar[0]===
+true){a.p.toolbar[1]=="both"&&(f=f+(", #"+b(c.ubDiv).attr("id")));f=f+(", #"+b(c.uDiv).attr("id"))}g=b(f,"#gview_"+b.jgrid.jqID(a.p.id)).length;a.p.gridstate=="visible"?b(f,"#gbox_"+b.jgrid.jqID(a.p.id)).slideUp("fast",function(){g--;if(g===0){b("span",i).removeClass("ui-icon-circle-triangle-n").addClass("ui-icon-circle-triangle-s");a.p.gridstate="hidden";b("#gbox_"+b.jgrid.jqID(a.p.id)).hasClass("ui-resizable")&&b(".ui-resizable-handle","#gbox_"+b.jgrid.jqID(a.p.id)).hide();b(a).triggerHandler("jqGridHeaderClick",
+[a.p.gridstate,d]);e&&(D||a.p.onHeaderClick.call(a,a.p.gridstate,d))}}):a.p.gridstate=="hidden"&&b(f,"#gbox_"+b.jgrid.jqID(a.p.id)).slideDown("fast",function(){g--;if(g===0){b("span",i).removeClass("ui-icon-circle-triangle-s").addClass("ui-icon-circle-triangle-n");if(D){a.p.datatype=pa;I();D=false}a.p.gridstate="visible";b("#gbox_"+b.jgrid.jqID(a.p.id)).hasClass("ui-resizable")&&b(".ui-resizable-handle","#gbox_"+b.jgrid.jqID(a.p.id)).show();b(a).triggerHandler("jqGridHeaderClick",[a.p.gridstate,d]);
+e&&(D||a.p.onHeaderClick.call(a,a.p.gridstate,d))}});return false}),D&&(a.p.datatype="local",b(".ui-jqgrid-titlebar-close",c.cDiv).trigger("click")))}else b(c.cDiv).hide();b(c.hDiv).after(c.bDiv).mousemove(function(a){if(c.resizing){c.dragMove(a);return false}});b(".ui-jqgrid-labels",c.hDiv).bind("selectstart",function(){return false});b(document).mouseup(function(){if(c.resizing){c.dragEnd();return false}return true});a.formatCol=p;a.sortData=ja;a.updatepager=function(c,d){var e,f,g,h,i,j,k,l="",
+m=a.p.pager?"_"+b.jgrid.jqID(a.p.pager.substr(1)):"",n=a.p.toppager?"_"+a.p.toppager.substr(1):"";g=parseInt(a.p.page,10)-1;g<0&&(g=0);g=g*parseInt(a.p.rowNum,10);i=g+a.p.reccount;if(a.p.scroll){e=b("tbody:first > tr:gt(0)",a.grid.bDiv);g=i-e.length;a.p.reccount=e.length;if(f=e.outerHeight()||a.grid.prevRowHeight){e=g*f;f=parseInt(a.p.records,10)*f;b(">div:first",a.grid.bDiv).css({height:f}).children("div:first").css({height:e,display:e?"":"none"})}a.grid.bDiv.scrollLeft=a.grid.hDiv.scrollLeft}l=
+a.p.pager?a.p.pager:"";if(l=l+(a.p.toppager?l?","+a.p.toppager:a.p.toppager:"")){k=b.jgrid.formatter.integer||{};e=o(a.p.page);f=o(a.p.lastpage);b(".selbox",l)[this.p.useProp?"prop":"attr"]("disabled",false);if(a.p.pginput===true){b(".ui-pg-input",l).val(a.p.page);h=a.p.toppager?"#sp_1"+m+",#sp_1"+n:"#sp_1"+m;b(h).html(b.fmatter?b.fmatter.util.NumberFormat(a.p.lastpage,k):a.p.lastpage)}if(a.p.viewrecords)if(a.p.reccount===0)b(".ui-paging-info",l).html(a.p.emptyrecords);else{h=g+1;j=a.p.records;if(b.fmatter){h=
+b.fmatter.util.NumberFormat(h,k);i=b.fmatter.util.NumberFormat(i,k);j=b.fmatter.util.NumberFormat(j,k)}b(".ui-paging-info",l).html(b.jgrid.format(a.p.recordtext,h,i,j))}if(a.p.pgbuttons===true){e<=0&&(e=f=0);if(e==1||e===0){b("#first"+m+", #prev"+m).addClass("ui-state-disabled").removeClass("ui-state-hover");a.p.toppager&&b("#first_t"+n+", #prev_t"+n).addClass("ui-state-disabled").removeClass("ui-state-hover")}else{b("#first"+m+", #prev"+m).removeClass("ui-state-disabled");a.p.toppager&&b("#first_t"+
+n+", #prev_t"+n).removeClass("ui-state-disabled")}if(e==f||e===0){b("#next"+m+", #last"+m).addClass("ui-state-disabled").removeClass("ui-state-hover");a.p.toppager&&b("#next_t"+n+", #last_t"+n).addClass("ui-state-disabled").removeClass("ui-state-hover")}else{b("#next"+m+", #last"+m).removeClass("ui-state-disabled");a.p.toppager&&b("#next_t"+n+", #last_t"+n).removeClass("ui-state-disabled")}}}c===true&&a.p.rownumbers===true&&b("td.jqgrid-rownum",a.rows).each(function(a){b(this).html(g+1+a)});d&&a.p.jqgdnd&&
+b(a).jqGrid("gridDnD","updateDnD");b(a).triggerHandler("jqGridGridComplete");b.isFunction(a.p.gridComplete)&&a.p.gridComplete.call(a);b(a).triggerHandler("jqGridAfterGridComplete")};a.refreshIndex=S;a.setHeadCheckBox=da;a.constructTr=J;a.formatter=function(a,b,c,d,e){return u(a,b,c,d,e)};b.extend(c,{populate:I,emptyRows:N});this.grid=c;a.addXmlData=function(b){$(b,a.grid.bDiv)};a.addJSONData=function(b){aa(b,a.grid.bDiv)};this.grid.cols=this.rows[0].cells;I();a.p.hiddengrid=!1;b(window).unload(function(){a=
+null})}}}})};b.jgrid.extend({getGridParam:function(b){var e=this[0];return!e||!e.grid?void 0:b?"undefined"!=typeof e.p[b]?e.p[b]:null:e.p},setGridParam:function(f){return this.each(function(){this.grid&&"object"===typeof f&&b.extend(!0,this.p,f)})},getDataIDs:function(){var f=[],e=0,c,d=0;this.each(function(){if((c=this.rows.length)&&0<c)for(;e<c;)b(this.rows[e]).hasClass("jqgrow")&&(f[d]=this.rows[e].id,d++),e++});return f},setSelection:function(f,e,c){return this.each(function(){var d,a,h,g,i,j;
+if(void 0!==f&&(e=!1===e?!1:!0,(a=this.rows.namedItem(f+""))&&a.className&&!(-1<a.className.indexOf("ui-state-disabled"))))(!0===this.p.scrollrows&&(h=this.rows.namedItem(f).rowIndex,0<=h&&(d=b(this.grid.bDiv)[0].clientHeight,g=b(this.grid.bDiv)[0].scrollTop,i=this.rows[h].offsetTop,h=this.rows[h].clientHeight,i+h>=d+g?b(this.grid.bDiv)[0].scrollTop=i-(d+g)+h+g:i<d+g&&i<g&&(b(this.grid.bDiv)[0].scrollTop=i))),!0===this.p.frozenColumns&&(j=this.p.id+"_frozen"),this.p.multiselect)?(this.setHeadCheckBox(!1),
+this.p.selrow=a.id,g=b.inArray(this.p.selrow,this.p.selarrrow),-1===g?("ui-subgrid"!==a.className&&b(a).addClass("ui-state-highlight").attr("aria-selected","true"),d=!0,this.p.selarrrow.push(this.p.selrow)):("ui-subgrid"!==a.className&&b(a).removeClass("ui-state-highlight").attr("aria-selected","false"),d=!1,this.p.selarrrow.splice(g,1),i=this.p.selarrrow[0],this.p.selrow=void 0===i?null:i),b("#jqg_"+b.jgrid.jqID(this.p.id)+"_"+b.jgrid.jqID(a.id))[this.p.useProp?"prop":"attr"]("checked",d),j&&(-1===
+g?b("#"+b.jgrid.jqID(f),"#"+b.jgrid.jqID(j)).addClass("ui-state-highlight"):b("#"+b.jgrid.jqID(f),"#"+b.jgrid.jqID(j)).removeClass("ui-state-highlight"),b("#jqg_"+b.jgrid.jqID(this.p.id)+"_"+b.jgrid.jqID(f),"#"+b.jgrid.jqID(j))[this.p.useProp?"prop":"attr"]("checked",d)),b(this).triggerHandler("jqGridSelectRow",[a.id,d,c]),this.p.onSelectRow&&e&&this.p.onSelectRow.call(this,a.id,d,c)):"ui-subgrid"!==a.className&&(this.p.selrow!=a.id?(b(this.rows.namedItem(this.p.selrow)).removeClass("ui-state-highlight").attr({"aria-selected":"false",
+tabindex:"-1"}),b(a).addClass("ui-state-highlight").attr({"aria-selected":"true",tabindex:"0"}),j&&(b("#"+b.jgrid.jqID(this.p.selrow),"#"+b.jgrid.jqID(j)).removeClass("ui-state-highlight"),b("#"+b.jgrid.jqID(f),"#"+b.jgrid.jqID(j)).addClass("ui-state-highlight")),d=!0):d=!1,this.p.selrow=a.id,b(this).triggerHandler("jqGridSelectRow",[a.id,d,c]),this.p.onSelectRow&&e&&this.p.onSelectRow.call(this,a.id,d,c))})},resetSelection:function(f){return this.each(function(){var e=this,c,d,a;!0===e.p.frozenColumns&&
+(a=e.p.id+"_frozen");if("undefined"!==typeof f){d=f===e.p.selrow?e.p.selrow:f;b("#"+b.jgrid.jqID(e.p.id)+" tbody:first tr#"+b.jgrid.jqID(d)).removeClass("ui-state-highlight").attr("aria-selected","false");a&&b("#"+b.jgrid.jqID(d),"#"+b.jgrid.jqID(a)).removeClass("ui-state-highlight");if(e.p.multiselect){b("#jqg_"+b.jgrid.jqID(e.p.id)+"_"+b.jgrid.jqID(d),"#"+b.jgrid.jqID(e.p.id))[e.p.useProp?"prop":"attr"]("checked",!1);if(a)b("#jqg_"+b.jgrid.jqID(e.p.id)+"_"+b.jgrid.jqID(d),"#"+b.jgrid.jqID(a))[e.p.useProp?
+"prop":"attr"]("checked",!1);e.setHeadCheckBox(!1)}d=null}else e.p.multiselect?(b(e.p.selarrrow).each(function(d,f){c=e.rows.namedItem(f);b(c).removeClass("ui-state-highlight").attr("aria-selected","false");b("#jqg_"+b.jgrid.jqID(e.p.id)+"_"+b.jgrid.jqID(f))[e.p.useProp?"prop":"attr"]("checked",!1);a&&(b("#"+b.jgrid.jqID(f),"#"+b.jgrid.jqID(a)).removeClass("ui-state-highlight"),b("#jqg_"+b.jgrid.jqID(e.p.id)+"_"+b.jgrid.jqID(f),"#"+b.jgrid.jqID(a))[e.p.useProp?"prop":"attr"]("checked",!1))}),e.setHeadCheckBox(!1),
+e.p.selarrrow=[]):e.p.selrow&&(b("#"+b.jgrid.jqID(e.p.id)+" tbody:first tr#"+b.jgrid.jqID(e.p.selrow)).removeClass("ui-state-highlight").attr("aria-selected","false"),a&&b("#"+b.jgrid.jqID(e.p.selrow),"#"+b.jgrid.jqID(a)).removeClass("ui-state-highlight"),e.p.selrow=null);!0===e.p.cellEdit&&0<=parseInt(e.p.iCol,10)&&0<=parseInt(e.p.iRow,10)&&(b("td:eq("+e.p.iCol+")",e.rows[e.p.iRow]).removeClass("edit-cell ui-state-highlight"),b(e.rows[e.p.iRow]).removeClass("selected-row ui-state-hover"));e.p.savedRow=
+[]})},getRowData:function(f){var e={},c,d=!1,a,h=0;this.each(function(){var g=this,i,j;if("undefined"==typeof f)d=!0,c=[],a=g.rows.length;else{j=g.rows.namedItem(f);if(!j)return e;a=2}for(;h<a;)d&&(j=g.rows[h]),b(j).hasClass("jqgrow")&&(b('td[role="gridcell"]',j).each(function(a){i=g.p.colModel[a].name;if("cb"!==i&&"subgrid"!==i&&"rn"!==i)if(!0===g.p.treeGrid&&i==g.p.ExpandColumn)e[i]=b.jgrid.htmlDecode(b("span:first",this).html());else try{e[i]=b.unformat.call(g,this,{rowId:j.id,colModel:g.p.colModel[a]},
+a)}catch(c){e[i]=b.jgrid.htmlDecode(b(this).html())}}),d&&(c.push(e),e={})),h++});return c?c:e},delRowData:function(f){var e=!1,c,d;this.each(function(){if(c=this.rows.namedItem(f)){if(b(c).remove(),this.p.records--,this.p.reccount--,this.updatepager(!0,!1),e=!0,this.p.multiselect&&(d=b.inArray(f,this.p.selarrrow),-1!=d&&this.p.selarrrow.splice(d,1)),f==this.p.selrow)this.p.selrow=null}else return!1;if("local"==this.p.datatype){var a=this.p._index[b.jgrid.stripPref(this.p.idPrefix,f)];"undefined"!=
+typeof a&&(this.p.data.splice(a,1),this.refreshIndex())}if(!0===this.p.altRows&&e){var h=this.p.altclass;b(this.rows).each(function(a){1==a%2?b(this).addClass(h):b(this).removeClass(h)})}});return e},setRowData:function(f,e,c){var d,a=!0,h;this.each(function(){if(!this.grid)return!1;var g=this,i,j,l=typeof c,k={};j=g.rows.namedItem(f);if(!j)return!1;if(e)try{if(b(this.p.colModel).each(function(a){d=this.name;void 0!==e[d]&&(k[d]=this.formatter&&"string"===typeof this.formatter&&"date"==this.formatter?
+b.unformat.date.call(g,e[d],this):e[d],i=g.formatter(f,e[d],a,e,"edit"),h=this.title?{title:b.jgrid.stripHtml(i)}:{},!0===g.p.treeGrid&&d==g.p.ExpandColumn?b("td:eq("+a+") > span:first",j).html(i).attr(h):b("td:eq("+a+")",j).html(i).attr(h))}),"local"==g.p.datatype){var m=b.jgrid.stripPref(g.p.idPrefix,f),o=g.p._index[m];if(g.p.treeGrid)for(var p in g.p.treeReader)k.hasOwnProperty(g.p.treeReader[p])&&delete k[g.p.treeReader[p]];"undefined"!=typeof o&&(g.p.data[o]=b.extend(!0,g.p.data[o],k));k=null}}catch(v){a=
+!1}a&&("string"===l?b(j).addClass(c):"object"===l&&b(j).css(c),b(g).triggerHandler("jqGridAfterGridComplete"))});return a},addRowData:function(f,e,c,d){c||(c="last");var a=!1,h,g,i,j,l,k,m,o,p="",v,u,M,F,Z,U;e&&(b.isArray(e)?(v=!0,c="last",u=f):(e=[e],v=!1),this.each(function(){var V=e.length;l=this.p.rownumbers===true?1:0;i=this.p.multiselect===true?1:0;j=this.p.subGrid===true?1:0;if(!v)if(typeof f!="undefined")f=f+"";else{f=b.jgrid.randId();if(this.p.keyIndex!==false){u=this.p.colModel[this.p.keyIndex+
+i+j+l].name;typeof e[0][u]!="undefined"&&(f=e[0][u])}}M=this.p.altclass;for(var N=0,S="",J={},$=b.isFunction(this.p.afterInsertRow)?true:false;N<V;){F=e[N];g=[];if(v){try{f=F[u]}catch(aa){f=b.jgrid.randId()}S=this.p.altRows===true?(this.rows.length-1)%2===0?M:"":""}U=f;f=this.p.idPrefix+f;if(l){p=this.formatCol(0,1,"",null,f,true);g[g.length]='<td role="gridcell" class="ui-state-default jqgrid-rownum" '+p+">0</td>"}if(i){o='<input role="checkbox" type="checkbox" id="jqg_'+this.p.id+"_"+f+'" class="cbox"/>';
+p=this.formatCol(l,1,"",null,f,true);g[g.length]='<td role="gridcell" '+p+">"+o+"</td>"}j&&(g[g.length]=b(this).jqGrid("addSubGridCell",i+l,1));for(m=i+j+l;m<this.p.colModel.length;m++){Z=this.p.colModel[m];h=Z.name;J[h]=F[h];o=this.formatter(f,b.jgrid.getAccessor(F,h),m,F);p=this.formatCol(m,1,o,F,f,true);g[g.length]='<td role="gridcell" '+p+">"+o+"</td>"}g.unshift(this.constructTr(f,false,S,J,J));g[g.length]="</tr>";if(this.rows.length===0)b("table:first",this.grid.bDiv).append(g.join(""));else switch(c){case "last":b(this.rows[this.rows.length-
+1]).after(g.join(""));k=this.rows.length-1;break;case "first":b(this.rows[0]).after(g.join(""));k=1;break;case "after":(k=this.rows.namedItem(d))&&(b(this.rows[k.rowIndex+1]).hasClass("ui-subgrid")?b(this.rows[k.rowIndex+1]).after(g):b(k).after(g.join("")));k++;break;case "before":if(k=this.rows.namedItem(d)){b(k).before(g.join(""));k=k.rowIndex}k--}this.p.subGrid===true&&b(this).jqGrid("addSubGrid",i+l,k);this.p.records++;this.p.reccount++;b(this).triggerHandler("jqGridAfterInsertRow",[f,F,F]);$&&
+this.p.afterInsertRow.call(this,f,F,F);N++;if(this.p.datatype=="local"){J[this.p.localReader.id]=U;this.p._index[U]=this.p.data.length;this.p.data.push(J);J={}}}this.p.altRows===true&&!v&&(c=="last"?(this.rows.length-1)%2==1&&b(this.rows[this.rows.length-1]).addClass(M):b(this.rows).each(function(a){a%2==1?b(this).addClass(M):b(this).removeClass(M)}));this.updatepager(true,true);a=true}));return a},footerData:function(f,e,c){function d(a){for(var b in a)if(a.hasOwnProperty(b))return!1;return!0}var a,
+h=!1,g={},i;"undefined"==typeof f&&(f="get");"boolean"!=typeof c&&(c=!0);f=f.toLowerCase();this.each(function(){var j=this,l;if(!j.grid||!j.p.footerrow||"set"==f&&d(e))return!1;h=!0;b(this.p.colModel).each(function(d){a=this.name;"set"==f?void 0!==e[a]&&(l=c?j.formatter("",e[a],d,e,"edit"):e[a],i=this.title?{title:b.jgrid.stripHtml(l)}:{},b("tr.footrow td:eq("+d+")",j.grid.sDiv).html(l).attr(i),h=!0):"get"==f&&(g[a]=b("tr.footrow td:eq("+d+")",j.grid.sDiv).html())})});return"get"==f?g:h},showHideCol:function(f,
+e){return this.each(function(){var c=this,d=!1,a=b.jgrid.cellWidth()?0:c.p.cellLayout,h;if(c.grid){"string"===typeof f&&(f=[f]);e="none"!=e?"":"none";var g=""===e?!0:!1,i=c.p.groupHeader&&("object"===typeof c.p.groupHeader||b.isFunction(c.p.groupHeader));i&&b(c).jqGrid("destroyGroupHeader",!1);b(this.p.colModel).each(function(i){if(-1!==b.inArray(this.name,f)&&this.hidden===g){if(!0===c.p.frozenColumns&&!0===this.frozen)return!0;b("tr",c.grid.hDiv).each(function(){b(this.cells[i]).css("display",e)});
+b(c.rows).each(function(){b(this).hasClass("jqgroup")||b(this.cells[i]).css("display",e)});c.p.footerrow&&b("tr.footrow td:eq("+i+")",c.grid.sDiv).css("display",e);h=parseInt(this.width,10);c.p.tblwidth="none"===e?c.p.tblwidth-(h+a):c.p.tblwidth+(h+a);this.hidden=!g;d=!0;b(c).triggerHandler("jqGridShowHideCol",[g,this.name,i])}});!0===d&&(!0===c.p.shrinkToFit&&!isNaN(c.p.height)&&(c.p.tblwidth+=parseInt(c.p.scrollOffset,10)),b(c).jqGrid("setGridWidth",!0===c.p.shrinkToFit?c.p.tblwidth:c.p.width));
+i&&b(c).jqGrid("setGroupHeaders",c.p.groupHeader)}})},hideCol:function(f){return this.each(function(){b(this).jqGrid("showHideCol",f,"none")})},showCol:function(f){return this.each(function(){b(this).jqGrid("showHideCol",f,"")})},remapColumns:function(f,e,c){function d(a){var c;c=a.length?b.makeArray(a):b.extend({},a);b.each(f,function(b){a[b]=c[this]})}function a(a,c){b(">tr"+(c||""),a).each(function(){var a=this,c=b.makeArray(a.cells);b.each(f,function(){var b=c[this];b&&a.appendChild(b)})})}var h=
+this.get(0);d(h.p.colModel);d(h.p.colNames);d(h.grid.headers);a(b("thead:first",h.grid.hDiv),c&&":not(.ui-jqgrid-labels)");e&&a(b("#"+b.jgrid.jqID(h.p.id)+" tbody:first"),".jqgfirstrow, tr.jqgrow, tr.jqfoot");h.p.footerrow&&a(b("tbody:first",h.grid.sDiv));h.p.remapColumns&&(h.p.remapColumns.length?d(h.p.remapColumns):h.p.remapColumns=b.makeArray(f));h.p.lastsort=b.inArray(h.p.lastsort,f);h.p.treeGrid&&(h.p.expColInd=b.inArray(h.p.expColInd,f));b(h).triggerHandler("jqGridRemapColumns",[f,e,c])},setGridWidth:function(f,
+e){return this.each(function(){if(this.grid){var c=this,d,a=0,h=b.jgrid.cellWidth()?0:c.p.cellLayout,g,i=0,j=!1,l=c.p.scrollOffset,k,m=0,o=0,p;"boolean"!=typeof e&&(e=c.p.shrinkToFit);if(!isNaN(f)){f=parseInt(f,10);c.grid.width=c.p.width=f;b("#gbox_"+b.jgrid.jqID(c.p.id)).css("width",f+"px");b("#gview_"+b.jgrid.jqID(c.p.id)).css("width",f+"px");b(c.grid.bDiv).css("width",f+"px");b(c.grid.hDiv).css("width",f+"px");c.p.pager&&b(c.p.pager).css("width",f+"px");c.p.toppager&&b(c.p.toppager).css("width",
+f+"px");!0===c.p.toolbar[0]&&(b(c.grid.uDiv).css("width",f+"px"),"both"==c.p.toolbar[1]&&b(c.grid.ubDiv).css("width",f+"px"));c.p.footerrow&&b(c.grid.sDiv).css("width",f+"px");!1===e&&!0===c.p.forceFit&&(c.p.forceFit=!1);if(!0===e){b.each(c.p.colModel,function(){if(this.hidden===false){d=this.widthOrg;a=a+(d+h);this.fixed?m=m+(d+h):i++;o++}});if(0===i)return;c.p.tblwidth=a;k=f-h*i-m;if(!isNaN(c.p.height)&&(b(c.grid.bDiv)[0].clientHeight<b(c.grid.bDiv)[0].scrollHeight||1===c.rows.length))j=!0,k-=l;
+var a=0,v=0<c.grid.cols.length;b.each(c.p.colModel,function(b){if(this.hidden===false&&!this.fixed){d=this.widthOrg;d=Math.round(k*d/(c.p.tblwidth-h*i-m));if(!(d<0)){this.width=d;a=a+d;c.grid.headers[b].width=d;c.grid.headers[b].el.style.width=d+"px";if(c.p.footerrow)c.grid.footers[b].style.width=d+"px";if(v)c.grid.cols[b].style.width=d+"px";g=b}}});if(!g)return;p=0;j?f-m-(a+h*i)!==l&&(p=f-m-(a+h*i)-l):1!==Math.abs(f-m-(a+h*i))&&(p=f-m-(a+h*i));c.p.colModel[g].width+=p;c.p.tblwidth=a+p+h*i+m;c.p.tblwidth>
+f?(j=c.p.tblwidth-parseInt(f,10),c.p.tblwidth=f,d=c.p.colModel[g].width-=j):d=c.p.colModel[g].width;c.grid.headers[g].width=d;c.grid.headers[g].el.style.width=d+"px";v&&(c.grid.cols[g].style.width=d+"px");c.p.footerrow&&(c.grid.footers[g].style.width=d+"px")}c.p.tblwidth&&(b("table:first",c.grid.bDiv).css("width",c.p.tblwidth+"px"),b("table:first",c.grid.hDiv).css("width",c.p.tblwidth+"px"),c.grid.hDiv.scrollLeft=c.grid.bDiv.scrollLeft,c.p.footerrow&&b("table:first",c.grid.sDiv).css("width",c.p.tblwidth+
+"px"))}}})},setGridHeight:function(f){return this.each(function(){if(this.grid){var e=b(this.grid.bDiv);e.css({height:f+(isNaN(f)?"":"px")});!0===this.p.frozenColumns&&b("#"+b.jgrid.jqID(this.p.id)+"_frozen").parent().height(e.height()-16);this.p.height=f;this.p.scroll&&this.grid.populateVisible()}})},setCaption:function(f){return this.each(function(){this.p.caption=f;b("span.ui-jqgrid-title, span.ui-jqgrid-title-rtl",this.grid.cDiv).html(f);b(this.grid.cDiv).show()})},setLabel:function(f,e,c,d){return this.each(function(){var a=
+-1;if(this.grid&&"undefined"!=typeof f&&(b(this.p.colModel).each(function(b){if(this.name==f)return a=b,!1}),0<=a)){var h=b("tr.ui-jqgrid-labels th:eq("+a+")",this.grid.hDiv);if(e){var g=b(".s-ico",h);b("[id^=jqgh_]",h).empty().html(e).append(g);this.p.colNames[a]=e}c&&("string"===typeof c?b(h).addClass(c):b(h).css(c));"object"===typeof d&&b(h).attr(d)}})},setCell:function(f,e,c,d,a,h){return this.each(function(){var g=-1,i,j;if(this.grid&&(isNaN(e)?b(this.p.colModel).each(function(a){if(this.name==
+e)return g=a,!1}):g=parseInt(e,10),0<=g&&(i=this.rows.namedItem(f)))){var l=b("td:eq("+g+")",i);if(""!==c||!0===h)i=this.formatter(f,c,g,i,"edit"),j=this.p.colModel[g].title?{title:b.jgrid.stripHtml(i)}:{},this.p.treeGrid&&0<b(".tree-wrap",b(l)).length?b("span",b(l)).html(i).attr(j):b(l).html(i).attr(j),"local"==this.p.datatype&&(i=this.p.colModel[g],c=i.formatter&&"string"===typeof i.formatter&&"date"==i.formatter?b.unformat.date.call(this,c,i):c,j=this.p._index[f],"undefined"!=typeof j&&(this.p.data[j][i.name]=
+c));"string"===typeof d?b(l).addClass(d):d&&b(l).css(d);"object"===typeof a&&b(l).attr(a)}})},getCell:function(f,e){var c=!1;this.each(function(){var d=-1;if(this.grid&&(isNaN(e)?b(this.p.colModel).each(function(a){if(this.name===e)return d=a,!1}):d=parseInt(e,10),0<=d)){var a=this.rows.namedItem(f);if(a)try{c=b.unformat.call(this,b("td:eq("+d+")",a),{rowId:a.id,colModel:this.p.colModel[d]},d)}catch(h){c=b.jgrid.htmlDecode(b("td:eq("+d+")",a).html())}}});return c},getCol:function(f,e,c){var d=[],
+a,h=0,g,i,j,e="boolean"!=typeof e?!1:e;"undefined"==typeof c&&(c=!1);this.each(function(){var l=-1;if(this.grid&&(isNaN(f)?b(this.p.colModel).each(function(a){if(this.name===f)return l=a,!1}):l=parseInt(f,10),0<=l)){var k=this.rows.length,m=0;if(k&&0<k){for(;m<k;){if(b(this.rows[m]).hasClass("jqgrow")){try{a=b.unformat.call(this,b(this.rows[m].cells[l]),{rowId:this.rows[m].id,colModel:this.p.colModel[l]},l)}catch(o){a=b.jgrid.htmlDecode(this.rows[m].cells[l].innerHTML)}c?(j=parseFloat(a),h+=j,0===
+m?i=g=j:(g=Math.min(g,j),i=Math.max(i,j))):e?d.push({id:this.rows[m].id,value:a}):d.push(a)}m++}if(c)switch(c.toLowerCase()){case "sum":d=h;break;case "avg":d=h/k;break;case "count":d=k;break;case "min":d=g;break;case "max":d=i}}}});return d},clearGridData:function(f){return this.each(function(){if(this.grid){"boolean"!=typeof f&&(f=!1);if(this.p.deepempty)b("#"+b.jgrid.jqID(this.p.id)+" tbody:first tr:gt(0)").remove();else{var e=b("#"+b.jgrid.jqID(this.p.id)+" tbody:first tr:first")[0];b("#"+b.jgrid.jqID(this.p.id)+
+" tbody:first").empty().append(e)}this.p.footerrow&&f&&b(".ui-jqgrid-ftable td",this.grid.sDiv).html("&#160;");this.p.selrow=null;this.p.selarrrow=[];this.p.savedRow=[];this.p.records=0;this.p.page=1;this.p.lastpage=0;this.p.reccount=0;this.p.data=[];this.p._index={};this.updatepager(!0,!1)}})},getInd:function(b,e){var c=!1,d;this.each(function(){(d=this.rows.namedItem(b))&&(c=!0===e?d:d.rowIndex)});return c},bindKeys:function(f){var e=b.extend({onEnter:null,onSpace:null,onLeftKey:null,onRightKey:null,
+scrollingRows:!0},f||{});return this.each(function(){var c=this;b("body").is("[role]")||b("body").attr("role","application");c.p.scrollrows=e.scrollingRows;b(c).keydown(function(d){var a=b(c).find("tr[tabindex=0]")[0],f,g,i,j=c.p.treeReader.expanded_field;if(a)if(i=c.p._index[a.id],37===d.keyCode||38===d.keyCode||39===d.keyCode||40===d.keyCode){if(38===d.keyCode){g=a.previousSibling;f="";if(g)if(b(g).is(":hidden"))for(;g;){if(g=g.previousSibling,!b(g).is(":hidden")&&b(g).hasClass("jqgrow")){f=g.id;
+break}}else f=g.id;b(c).jqGrid("setSelection",f,!0,d)}if(40===d.keyCode){g=a.nextSibling;f="";if(g)if(b(g).is(":hidden"))for(;g;){if(g=g.nextSibling,!b(g).is(":hidden")&&b(g).hasClass("jqgrow")){f=g.id;break}}else f=g.id;b(c).jqGrid("setSelection",f,!0,d)}37===d.keyCode&&(c.p.treeGrid&&c.p.data[i][j]&&b(a).find("div.treeclick").trigger("click"),b(c).triggerHandler("jqGridKeyLeft",[c.p.selrow]),b.isFunction(e.onLeftKey)&&e.onLeftKey.call(c,c.p.selrow));39===d.keyCode&&(c.p.treeGrid&&!c.p.data[i][j]&&
+b(a).find("div.treeclick").trigger("click"),b(c).triggerHandler("jqGridKeyRight",[c.p.selrow]),b.isFunction(e.onRightKey)&&e.onRightKey.call(c,c.p.selrow))}else 13===d.keyCode?(b(c).triggerHandler("jqGridKeyEnter",[c.p.selrow]),b.isFunction(e.onEnter)&&e.onEnter.call(c,c.p.selrow)):32===d.keyCode&&(b(c).triggerHandler("jqGridKeySpace",[c.p.selrow]),b.isFunction(e.onSpace)&&e.onSpace.call(c,c.p.selrow))})})},unbindKeys:function(){return this.each(function(){b(this).unbind("keydown")})},getLocalRow:function(b){var e=
+!1,c;this.each(function(){"undefined"!==typeof b&&(c=this.p._index[b],0<=c&&(e=this.p.data[c]))});return e}})})(jQuery);
+(function(c){c.fmatter={};c.extend(c.fmatter,{isBoolean:function(a){return"boolean"===typeof a},isObject:function(a){return a&&("object"===typeof a||c.isFunction(a))||!1},isString:function(a){return"string"===typeof a},isNumber:function(a){return"number"===typeof a&&isFinite(a)},isNull:function(a){return null===a},isUndefined:function(a){return"undefined"===typeof a},isValue:function(a){return this.isObject(a)||this.isString(a)||this.isNumber(a)||this.isBoolean(a)},isEmpty:function(a){if(!this.isString(a)&&
+this.isValue(a))return!1;if(!this.isValue(a))return!0;a=c.trim(a).replace(/\&nbsp\;/ig,"").replace(/\&#160\;/ig,"");return""===a}});c.fn.fmatter=function(a,b,f,d,e){var g=b,f=c.extend({},c.jgrid.formatter,f);try{g=c.fn.fmatter[a].call(this,b,f,d,e)}catch(h){}return g};c.fmatter.util={NumberFormat:function(a,b){c.fmatter.isNumber(a)||(a*=1);if(c.fmatter.isNumber(a)){var f=0>a,d=a+"",e=b.decimalSeparator?b.decimalSeparator:".",g;if(c.fmatter.isNumber(b.decimalPlaces)){var h=b.decimalPlaces,d=Math.pow(10,
+h),d=Math.round(a*d)/d+"";g=d.lastIndexOf(".");if(0<h){0>g?(d+=e,g=d.length-1):"."!==e&&(d=d.replace(".",e));for(;d.length-1-g<h;)d+="0"}}if(b.thousandsSeparator){h=b.thousandsSeparator;g=d.lastIndexOf(e);g=-1<g?g:d.length;for(var e=d.substring(g),i=-1,j=g;0<j;j--){i++;if(0===i%3&&j!==g&&(!f||1<j))e=h+e;e=d.charAt(j-1)+e}d=e}d=b.prefix?b.prefix+d:d;return d=b.suffix?d+b.suffix:d}return a},DateFormat:function(a,b,f,d){var e=/^\/Date\((([-+])?[0-9]+)(([-+])([0-9]{2})([0-9]{2}))?\)\/$/,g="string"===
+typeof b?b.match(e):null,e=function(a,b){a=""+a;for(b=parseInt(b,10)||2;a.length<b;)a="0"+a;return a},h={m:1,d:1,y:1970,h:0,i:0,s:0,u:0},i=0,j,k=["i18n"];k.i18n={dayNames:d.dayNames,monthNames:d.monthNames};a in d.masks&&(a=d.masks[a]);if(!isNaN(b-0)&&"u"==(""+a).toLowerCase())i=new Date(1E3*parseFloat(b));else if(b.constructor===Date)i=b;else if(null!==g)i=new Date(parseInt(g[1],10)),g[3]&&(a=60*Number(g[5])+Number(g[6]),a*="-"==g[4]?1:-1,a-=i.getTimezoneOffset(),i.setTime(Number(Number(i)+6E4*a)));
+else{b=(""+b).split(/[\\\/:_;.,\t\T\s-]/);a=a.split(/[\\\/:_;.,\t\T\s-]/);g=0;for(j=a.length;g<j;g++)"M"==a[g]&&(i=c.inArray(b[g],k.i18n.monthNames),-1!==i&&12>i&&(b[g]=i+1)),"F"==a[g]&&(i=c.inArray(b[g],k.i18n.monthNames),-1!==i&&11<i&&(b[g]=i+1-12)),b[g]&&(h[a[g].toLowerCase()]=parseInt(b[g],10));h.f&&(h.m=h.f);if(0===h.m&&0===h.y&&0===h.d)return"&#160;";h.m=parseInt(h.m,10)-1;i=h.y;70<=i&&99>=i?h.y=1900+h.y:0<=i&&69>=i&&(h.y=2E3+h.y);i=new Date(h.y,h.m,h.d,h.h,h.i,h.s,h.u)}f in d.masks?f=d.masks[f]:
+f||(f="Y-m-d");a=i.getHours();b=i.getMinutes();h=i.getDate();g=i.getMonth()+1;j=i.getTimezoneOffset();var l=i.getSeconds(),r=i.getMilliseconds(),n=i.getDay(),m=i.getFullYear(),o=(n+6)%7+1,p=(new Date(m,g-1,h)-new Date(m,0,1))/864E5,q={d:e(h),D:k.i18n.dayNames[n],j:h,l:k.i18n.dayNames[n+7],N:o,S:d.S(h),w:n,z:p,W:5>o?Math.floor((p+o-1)/7)+1:Math.floor((p+o-1)/7)||(4>((new Date(m-1,0,1)).getDay()+6)%7?53:52),F:k.i18n.monthNames[g-1+12],m:e(g),M:k.i18n.monthNames[g-1],n:g,t:"?",L:"?",o:"?",Y:m,y:(""+
+m).substring(2),a:12>a?d.AmPm[0]:d.AmPm[1],A:12>a?d.AmPm[2]:d.AmPm[3],B:"?",g:a%12||12,G:a,h:e(a%12||12),H:e(a),i:e(b),s:e(l),u:r,e:"?",I:"?",O:(0<j?"-":"+")+e(100*Math.floor(Math.abs(j)/60)+Math.abs(j)%60,4),P:"?",T:((""+i).match(/\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g)||[""]).pop().replace(/[^-+\dA-Z]/g,""),Z:"?",c:"?",r:"?",U:Math.floor(i/1E3)};return f.replace(/\\.|[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]/g,
+function(a){return a in q?q[a]:a.substring(1)})}};c.fn.fmatter.defaultFormat=function(a,b){return c.fmatter.isValue(a)&&""!==a?a:b.defaultValue?b.defaultValue:"&#160;"};c.fn.fmatter.email=function(a,b){return c.fmatter.isEmpty(a)?c.fn.fmatter.defaultFormat(a,b):'<a href="mailto:'+a+'">'+a+"</a>"};c.fn.fmatter.checkbox=function(a,b){var f=c.extend({},b.checkbox),d;void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));d=!0===f.disabled?'disabled="disabled"':
+"";if(c.fmatter.isEmpty(a)||c.fmatter.isUndefined(a))a=c.fn.fmatter.defaultFormat(a,f);a=(a+"").toLowerCase();return'<input type="checkbox" '+(0>a.search(/(false|0|no|off)/i)?" checked='checked' ":"")+' value="'+a+'" offval="no" '+d+"/>"};c.fn.fmatter.link=function(a,b){var f={target:b.target},d="";void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));f.target&&(d="target="+f.target);return!c.fmatter.isEmpty(a)?"<a "+d+' href="'+a+'">'+
+a+"</a>":c.fn.fmatter.defaultFormat(a,b)};c.fn.fmatter.showlink=function(a,b){var f={baseLinkUrl:b.baseLinkUrl,showAction:b.showAction,addParam:b.addParam||"",target:b.target,idName:b.idName},d="";void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));f.target&&(d="target="+f.target);f=f.baseLinkUrl+f.showAction+"?"+f.idName+"="+b.rowId+f.addParam;return c.fmatter.isString(a)||c.fmatter.isNumber(a)?"<a "+d+' href="'+f+'">'+a+"</a>":c.fn.fmatter.defaultFormat(a,
+b)};c.fn.fmatter.integer=function(a,b){var f=c.extend({},b.integer);void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));return c.fmatter.isEmpty(a)?f.defaultValue:c.fmatter.util.NumberFormat(a,f)};c.fn.fmatter.number=function(a,b){var f=c.extend({},b.number);void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));return c.fmatter.isEmpty(a)?f.defaultValue:c.fmatter.util.NumberFormat(a,
+f)};c.fn.fmatter.currency=function(a,b){var f=c.extend({},b.currency);void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));return c.fmatter.isEmpty(a)?f.defaultValue:c.fmatter.util.NumberFormat(a,f)};c.fn.fmatter.date=function(a,b,f,d){f=c.extend({},b.date);void 0!==b.colModel&&!c.fmatter.isUndefined(b.colModel.formatoptions)&&(f=c.extend({},f,b.colModel.formatoptions));return!f.reformatAfterEdit&&"edit"==d||c.fmatter.isEmpty(a)?c.fn.fmatter.defaultFormat(a,
+b):c.fmatter.util.DateFormat(f.srcformat,a,f.newformat,f)};c.fn.fmatter.select=function(a,b){var a=a+"",f=!1,d=[],e,g;c.fmatter.isUndefined(b.colModel.formatoptions)?c.fmatter.isUndefined(b.colModel.editoptions)||(f=b.colModel.editoptions.value,e=void 0===b.colModel.editoptions.separator?":":b.colModel.editoptions.separator,g=void 0===b.colModel.editoptions.delimiter?";":b.colModel.editoptions.delimiter):(f=b.colModel.formatoptions.value,e=void 0===b.colModel.formatoptions.separator?":":b.colModel.formatoptions.separator,
+g=void 0===b.colModel.formatoptions.delimiter?";":b.colModel.formatoptions.delimiter);if(f){var h=!0===b.colModel.editoptions.multiple?!0:!1,i=[];h&&(i=a.split(","),i=c.map(i,function(a){return c.trim(a)}));if(c.fmatter.isString(f))for(var j=f.split(g),k=0,l=0;l<j.length;l++)if(g=j[l].split(e),2<g.length&&(g[1]=c.map(g,function(a,b){if(b>0)return a}).join(e)),h)-1<c.inArray(g[0],i)&&(d[k]=g[1],k++);else{if(c.trim(g[0])==c.trim(a)){d[0]=g[1];break}}else c.fmatter.isObject(f)&&(h?d=c.map(i,function(a){return f[a]}):
+d[0]=f[a]||"")}a=d.join(", ");return""===a?c.fn.fmatter.defaultFormat(a,b):a};c.fn.fmatter.rowactions=function(a,b,f,d){var e={keys:!1,onEdit:null,onSuccess:null,afterSave:null,onError:null,afterRestore:null,extraparam:{},url:null,restoreAfterError:!0,mtype:"POST",delOptions:{},editOptions:{}},a=c.jgrid.jqID(a),b=c.jgrid.jqID(b),d=c("#"+b)[0].p.colModel[d];c.fmatter.isUndefined(d.formatoptions)||(e=c.extend(e,d.formatoptions));c.fmatter.isUndefined(c("#"+b)[0].p.editOptions)||(e.editOptions=c("#"+
+b)[0].p.editOptions);c.fmatter.isUndefined(c("#"+b)[0].p.delOptions)||(e.delOptions=c("#"+b)[0].p.delOptions);var g=c("#"+b)[0],d=function(d){c.isFunction(e.afterRestore)&&e.afterRestore.call(g,d);c("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+b+".ui-jqgrid-btable:first").show();c("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+b+".ui-jqgrid-btable:first").hide()};if(c("#"+a,"#"+b).hasClass("jqgrid-new-row")){var h=g.p.prmNames;e.extraparam[h.oper]=h.addoper}h={keys:e.keys,
+oneditfunc:e.onEdit,successfunc:e.onSuccess,url:e.url,extraparam:e.extraparam,aftersavefunc:function(d,f){c.isFunction(e.afterSave)&&e.afterSave.call(g,d,f);c("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+b+".ui-jqgrid-btable:first").show();c("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+b+".ui-jqgrid-btable:first").hide()},errorfunc:e.onError,afterrestorefunc:d,restoreAfterError:e.restoreAfterError,mtype:e.mtype};switch(f){case "edit":c("#"+b).jqGrid("editRow",
+a,h);c("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+b+".ui-jqgrid-btable:first").hide();c("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+b+".ui-jqgrid-btable:first").show();c(g).triggerHandler("jqGridAfterGridComplete");break;case "save":c("#"+b).jqGrid("saveRow",a,h)&&(c("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+b+".ui-jqgrid-btable:first").show(),c("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+b+".ui-jqgrid-btable:first").hide(),
+c(g).triggerHandler("jqGridAfterGridComplete"));break;case "cancel":c("#"+b).jqGrid("restoreRow",a,d);c("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+b+".ui-jqgrid-btable:first").show();c("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+b+".ui-jqgrid-btable:first").hide();c(g).triggerHandler("jqGridAfterGridComplete");break;case "del":c("#"+b).jqGrid("delGridRow",a,e.delOptions);break;case "formedit":c("#"+b).jqGrid("setSelection",a),c("#"+b).jqGrid("editGridRow",a,
+e.editOptions)}};c.fn.fmatter.actions=function(a,b){var f={keys:!1,editbutton:!0,delbutton:!0,editformbutton:!1};c.fmatter.isUndefined(b.colModel.formatoptions)||(f=c.extend(f,b.colModel.formatoptions));var d=b.rowId,e="",g;if("undefined"==typeof d||c.fmatter.isEmpty(d))return"";f.editformbutton?(g="onclick=jQuery.fn.fmatter.rowactions('"+d+"','"+b.gid+"','formedit',"+b.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ",e=e+"<div title='"+
+c.jgrid.nav.edittitle+"' style='float:left;cursor:pointer;' class='ui-pg-div ui-inline-edit' "+g+"><span class='ui-icon ui-icon-pencil'></span></div>"):f.editbutton&&(g="onclick=jQuery.fn.fmatter.rowactions('"+d+"','"+b.gid+"','edit',"+b.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover') ",e=e+"<div title='"+c.jgrid.nav.edittitle+"' style='float:left;cursor:pointer;' class='ui-pg-div ui-inline-edit' "+g+"><span class='ui-icon ui-icon-pencil'></span></div>");
+f.delbutton&&(g="onclick=jQuery.fn.fmatter.rowactions('"+d+"','"+b.gid+"','del',"+b.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ",e=e+"<div title='"+c.jgrid.nav.deltitle+"' style='float:left;margin-left:5px;' class='ui-pg-div ui-inline-del' "+g+"><span class='ui-icon ui-icon-trash'></span></div>");g="onclick=jQuery.fn.fmatter.rowactions('"+d+"','"+b.gid+"','save',"+b.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ";
+e=e+"<div title='"+c.jgrid.edit.bSubmit+"' style='float:left;display:none' class='ui-pg-div ui-inline-save' "+g+"><span class='ui-icon ui-icon-disk'></span></div>";g="onclick=jQuery.fn.fmatter.rowactions('"+d+"','"+b.gid+"','cancel',"+b.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ";e=e+"<div title='"+c.jgrid.edit.bCancel+"' style='float:left;display:none;margin-left:5px;' class='ui-pg-div ui-inline-cancel' "+g+"><span class='ui-icon ui-icon-cancel'></span></div>";
+return"<div style='margin-left:8px;'>"+e+"</div>"};c.unformat=function(a,b,f,d){var e,g=b.colModel.formatter,h=b.colModel.formatoptions||{},i=/([\.\*\_\'\(\)\{\}\+\?\\])/g,j=b.colModel.unformat||c.fn.fmatter[g]&&c.fn.fmatter[g].unformat;if("undefined"!==typeof j&&c.isFunction(j))e=j.call(this,c(a).text(),b,a);else if(!c.fmatter.isUndefined(g)&&c.fmatter.isString(g))switch(e=c.jgrid.formatter||{},g){case "integer":h=c.extend({},e.integer,h);b=h.thousandsSeparator.replace(i,"\\$1");b=RegExp(b,"g");
+e=c(a).text().replace(b,"");break;case "number":h=c.extend({},e.number,h);b=h.thousandsSeparator.replace(i,"\\$1");b=RegExp(b,"g");e=c(a).text().replace(b,"").replace(h.decimalSeparator,".");break;case "currency":h=c.extend({},e.currency,h);b=h.thousandsSeparator.replace(i,"\\$1");b=RegExp(b,"g");e=c(a).text();h.prefix&&h.prefix.length&&(e=e.substr(h.prefix.length));h.suffix&&h.suffix.length&&(e=e.substr(0,e.length-h.suffix.length));e=e.replace(b,"").replace(h.decimalSeparator,".");break;case "checkbox":h=
+b.colModel.editoptions?b.colModel.editoptions.value.split(":"):["Yes","No"];e=c("input",a).is(":checked")?h[0]:h[1];break;case "select":e=c.unformat.select(a,b,f,d);break;case "actions":return"";default:e=c(a).text()}return void 0!==e?e:!0===d?c(a).text():c.jgrid.htmlDecode(c(a).html())};c.unformat.select=function(a,b,f,d){f=[];a=c(a).text();if(!0===d)return a;var d=c.extend({},!c.fmatter.isUndefined(b.colModel.formatoptions)?b.colModel.formatoptions:b.colModel.editoptions),b=void 0===d.separator?
+":":d.separator,e=void 0===d.delimiter?";":d.delimiter;if(d.value){var g=d.value,d=!0===d.multiple?!0:!1,h=[];d&&(h=a.split(","),h=c.map(h,function(a){return c.trim(a)}));if(c.fmatter.isString(g))for(var i=g.split(e),j=0,k=0;k<i.length;k++)if(e=i[k].split(b),2<e.length&&(e[1]=c.map(e,function(a,b){if(b>0)return a}).join(b)),d)-1<c.inArray(e[1],h)&&(f[j]=e[0],j++);else{if(c.trim(e[1])==c.trim(a)){f[0]=e[0];break}}else if(c.fmatter.isObject(g)||c.isArray(g))d||(h[0]=a),f=c.map(h,function(a){var b;c.each(g,
+function(c,d){if(d==a){b=c;return false}});if(typeof b!="undefined")return b});return f.join(", ")}return a||""};c.unformat.date=function(a,b){var f=c.jgrid.formatter.date||{};c.fmatter.isUndefined(b.formatoptions)||(f=c.extend({},f,b.formatoptions));return!c.fmatter.isEmpty(a)?c.fmatter.util.DateFormat(f.newformat,a,f.srcformat,f):c.fn.fmatter.defaultFormat(a,b)}})(jQuery);
+(function(a){a.jgrid.extend({getColProp:function(a){var d={},c=this[0];if(!c.grid)return!1;for(var c=c.p.colModel,e=0;e<c.length;e++)if(c[e].name==a){d=c[e];break}return d},setColProp:function(b,d){return this.each(function(){if(this.grid&&d)for(var c=this.p.colModel,e=0;e<c.length;e++)if(c[e].name==b){a.extend(this.p.colModel[e],d);break}})},sortGrid:function(a,d,c){return this.each(function(){var e=-1;if(this.grid){a||(a=this.p.sortname);for(var h=0;h<this.p.colModel.length;h++)if(this.p.colModel[h].index==
+a||this.p.colModel[h].name==a){e=h;break}-1!=e&&(h=this.p.colModel[e].sortable,"boolean"!==typeof h&&(h=!0),"boolean"!==typeof d&&(d=!1),h&&this.sortData("jqgh_"+this.p.id+"_"+a,e,d,c))}})},GridDestroy:function(){return this.each(function(){if(this.grid){this.p.pager&&a(this.p.pager).remove();try{a("#gbox_"+a.jgrid.jqID(this.id)).remove()}catch(b){}}})},GridUnload:function(){return this.each(function(){if(this.grid){var b=a(this).attr("id"),d=a(this).attr("class");this.p.pager&&a(this.p.pager).empty().removeClass("ui-state-default ui-jqgrid-pager corner-bottom");
+var c=document.createElement("table");a(c).attr({id:b});c.className=d;b=a.jgrid.jqID(this.id);a(c).removeClass("ui-jqgrid-btable");1===a(this.p.pager).parents("#gbox_"+b).length?(a(c).insertBefore("#gbox_"+b).show(),a(this.p.pager).insertBefore("#gbox_"+b)):a(c).insertBefore("#gbox_"+b).show();a("#gbox_"+b).remove()}})},setGridState:function(b){return this.each(function(){this.grid&&("hidden"==b?(a(".ui-jqgrid-bdiv, .ui-jqgrid-hdiv","#gview_"+a.jgrid.jqID(this.p.id)).slideUp("fast"),this.p.pager&&
+a(this.p.pager).slideUp("fast"),this.p.toppager&&a(this.p.toppager).slideUp("fast"),!0===this.p.toolbar[0]&&("both"==this.p.toolbar[1]&&a(this.grid.ubDiv).slideUp("fast"),a(this.grid.uDiv).slideUp("fast")),this.p.footerrow&&a(".ui-jqgrid-sdiv","#gbox_"+a.jgrid.jqID(this.p.id)).slideUp("fast"),a(".ui-jqgrid-titlebar-close span",this.grid.cDiv).removeClass("ui-icon-circle-triangle-n").addClass("ui-icon-circle-triangle-s"),this.p.gridstate="hidden"):"visible"==b&&(a(".ui-jqgrid-hdiv, .ui-jqgrid-bdiv",
+"#gview_"+a.jgrid.jqID(this.p.id)).slideDown("fast"),this.p.pager&&a(this.p.pager).slideDown("fast"),this.p.toppager&&a(this.p.toppager).slideDown("fast"),!0===this.p.toolbar[0]&&("both"==this.p.toolbar[1]&&a(this.grid.ubDiv).slideDown("fast"),a(this.grid.uDiv).slideDown("fast")),this.p.footerrow&&a(".ui-jqgrid-sdiv","#gbox_"+a.jgrid.jqID(this.p.id)).slideDown("fast"),a(".ui-jqgrid-titlebar-close span",this.grid.cDiv).removeClass("ui-icon-circle-triangle-s").addClass("ui-icon-circle-triangle-n"),
+this.p.gridstate="visible"))})},filterToolbar:function(b){b=a.extend({autosearch:!0,searchOnEnter:!0,beforeSearch:null,afterSearch:null,beforeClear:null,afterClear:null,searchurl:"",stringResult:!1,groupOp:"AND",defaultSearch:"bw"},b||{});return this.each(function(){function d(b,c){var d=a(b);d[0]&&jQuery.each(c,function(){void 0!==this.data?d.bind(this.type,this.data,this.fn):d.bind(this.type,this.fn)})}var c=this;if(!this.ftoolbar){var e=function(){var d={},j=0,g,f,h={},m;a.each(c.p.colModel,function(){f=
+this.index||this.name;m=this.searchoptions&&this.searchoptions.sopt?this.searchoptions.sopt[0]:"select"==this.stype?"eq":b.defaultSearch;if(g=a("#gs_"+a.jgrid.jqID(this.name),!0===this.frozen&&!0===c.p.frozenColumns?c.grid.fhDiv:c.grid.hDiv).val())d[f]=g,h[f]=m,j++;else try{delete c.p.postData[f]}catch(e){}});var e=0<j?!0:!1;if(!0===b.stringResult||"local"==c.p.datatype){var k='{"groupOp":"'+b.groupOp+'","rules":[',l=0;a.each(d,function(a,b){0<l&&(k+=",");k+='{"field":"'+a+'",';k+='"op":"'+h[a]+'",';
+k+='"data":"'+(b+"").replace(/\\/g,"\\\\").replace(/\"/g,'\\"')+'"}';l++});k+="]}";a.extend(c.p.postData,{filters:k});a.each(["searchField","searchString","searchOper"],function(a,b){c.p.postData.hasOwnProperty(b)&&delete c.p.postData[b]})}else a.extend(c.p.postData,d);var p;c.p.searchurl&&(p=c.p.url,a(c).jqGrid("setGridParam",{url:c.p.searchurl}));var r="stop"===a(c).triggerHandler("jqGridToolbarBeforeSearch")?!0:!1;!r&&a.isFunction(b.beforeSearch)&&(r=b.beforeSearch.call(c));r||a(c).jqGrid("setGridParam",
+{search:e}).trigger("reloadGrid",[{page:1}]);p&&a(c).jqGrid("setGridParam",{url:p});a(c).triggerHandler("jqGridToolbarAfterSearch");a.isFunction(b.afterSearch)&&b.afterSearch.call(c)},h=a("<tr class='ui-search-toolbar' role='rowheader'></tr>"),g;a.each(c.p.colModel,function(){var i=this,j,q,f,n;q=a("<th role='columnheader' class='ui-state-default ui-th-column ui-th-"+c.p.direction+"'></th>");j=a("<div style='width:100%;position:relative;height:100%;padding-right:0.3em;'></div>");!0===this.hidden&&
+a(q).css("display","none");this.search=!1===this.search?!1:!0;"undefined"==typeof this.stype&&(this.stype="text");f=a.extend({},this.searchoptions||{});if(this.search)switch(this.stype){case "select":if(n=this.surl||f.dataUrl)a.ajax(a.extend({url:n,dataType:"html",success:function(c){if(f.buildSelect!==void 0)(c=f.buildSelect(c))&&a(j).append(c);else a(j).append(c);f.defaultValue!==void 0&&a("select",j).val(f.defaultValue);a("select",j).attr({name:i.index||i.name,id:"gs_"+i.name});f.attr&&a("select",
+j).attr(f.attr);a("select",j).css({width:"100%"});f.dataInit!==void 0&&f.dataInit(a("select",j)[0]);f.dataEvents!==void 0&&d(a("select",j)[0],f.dataEvents);b.autosearch===true&&a("select",j).change(function(){e();return false});c=null}},a.jgrid.ajaxOptions,c.p.ajaxSelectOptions||{}));else{var m,o,k;i.searchoptions?(m=void 0===i.searchoptions.value?"":i.searchoptions.value,o=void 0===i.searchoptions.separator?":":i.searchoptions.separator,k=void 0===i.searchoptions.delimiter?";":i.searchoptions.delimiter):
+i.editoptions&&(m=void 0===i.editoptions.value?"":i.editoptions.value,o=void 0===i.editoptions.separator?":":i.editoptions.separator,k=void 0===i.editoptions.delimiter?";":i.editoptions.delimiter);if(m){n=document.createElement("select");n.style.width="100%";a(n).attr({name:i.index||i.name,id:"gs_"+i.name});var l;if("string"===typeof m){m=m.split(k);for(var p=0;p<m.length;p++)l=m[p].split(o),k=document.createElement("option"),k.value=l[0],k.innerHTML=l[1],n.appendChild(k)}else if("object"===typeof m)for(l in m)m.hasOwnProperty(l)&&
+(k=document.createElement("option"),k.value=l,k.innerHTML=m[l],n.appendChild(k));void 0!==f.defaultValue&&a(n).val(f.defaultValue);f.attr&&a(n).attr(f.attr);void 0!==f.dataInit&&f.dataInit(n);void 0!==f.dataEvents&&d(n,f.dataEvents);a(j).append(n);!0===b.autosearch&&a(n).change(function(){e();return false})}}break;case "text":o=void 0!==f.defaultValue?f.defaultValue:"",a(j).append("<input type='text' style='width:95%;padding:0px;' name='"+(i.index||i.name)+"' id='gs_"+i.name+"' value='"+o+"'/>"),
+f.attr&&a("input",j).attr(f.attr),void 0!==f.dataInit&&f.dataInit(a("input",j)[0]),void 0!==f.dataEvents&&d(a("input",j)[0],f.dataEvents),!0===b.autosearch&&(b.searchOnEnter?a("input",j).keypress(function(a){if((a.charCode?a.charCode:a.keyCode?a.keyCode:0)==13){e();return false}return this}):a("input",j).keydown(function(a){switch(a.which){case 13:return false;case 9:case 16:case 37:case 38:case 39:case 40:case 27:break;default:g&&clearTimeout(g);g=setTimeout(function(){e()},500)}}))}a(q).append(j);
+a(h).append(q)});a("table thead",c.grid.hDiv).append(h);this.ftoolbar=!0;this.triggerToolbar=e;this.clearToolbar=function(d){var j={},g=0,f,d="boolean"!=typeof d?!0:d;a.each(c.p.colModel,function(){var b;this.searchoptions&&void 0!==this.searchoptions.defaultValue&&(b=this.searchoptions.defaultValue);f=this.index||this.name;switch(this.stype){case "select":a("#gs_"+a.jgrid.jqID(this.name)+" option",!0===this.frozen&&!0===c.p.frozenColumns?c.grid.fhDiv:c.grid.hDiv).each(function(c){if(c===0)this.selected=
+true;if(a(this).val()==b){this.selected=true;return false}});if(void 0!==b)j[f]=b,g++;else try{delete c.p.postData[f]}catch(d){}break;case "text":if(a("#gs_"+a.jgrid.jqID(this.name),!0===this.frozen&&!0===c.p.frozenColumns?c.grid.fhDiv:c.grid.hDiv).val(b),void 0!==b)j[f]=b,g++;else try{delete c.p.postData[f]}catch(e){}}});var h=0<g?!0:!1;if(!0===b.stringResult||"local"==c.p.datatype){var e='{"groupOp":"'+b.groupOp+'","rules":[',o=0;a.each(j,function(a,b){0<o&&(e+=",");e+='{"field":"'+a+'",';e+='"op":"eq",';
+e+='"data":"'+(b+"").replace(/\\/g,"\\\\").replace(/\"/g,'\\"')+'"}';o++});e+="]}";a.extend(c.p.postData,{filters:e});a.each(["searchField","searchString","searchOper"],function(a,b){c.p.postData.hasOwnProperty(b)&&delete c.p.postData[b]})}else a.extend(c.p.postData,j);var k;c.p.searchurl&&(k=c.p.url,a(c).jqGrid("setGridParam",{url:c.p.searchurl}));var l="stop"===a(c).triggerHandler("jqGridToolbarBeforeClear")?!0:!1;!l&&a.isFunction(b.beforeClear)&&(l=b.beforeClear.call(c));l||d&&a(c).jqGrid("setGridParam",
+{search:h}).trigger("reloadGrid",[{page:1}]);k&&a(c).jqGrid("setGridParam",{url:k});a(c).triggerHandler("jqGridToolbarAfterClear");a.isFunction(b.afterClear)&&b.afterClear()};this.toggleToolbar=function(){var b=a("tr.ui-search-toolbar",c.grid.hDiv),d=!0===c.p.frozenColumns?a("tr.ui-search-toolbar",c.grid.fhDiv):!1;"none"==b.css("display")?(b.show(),d&&d.show()):(b.hide(),d&&d.hide())}}})},destroyGroupHeader:function(b){"undefined"==typeof b&&(b=!0);return this.each(function(){var d,c,e,h,g,i;c=this.grid;
+var j=a("table.ui-jqgrid-htable thead",c.hDiv),q=this.p.colModel;if(c){a(this).unbind(".setGroupHeaders");d=a("<tr>",{role:"rowheader"}).addClass("ui-jqgrid-labels");h=c.headers;c=0;for(e=h.length;c<e;c++){g=q[c].hidden?"none":"";g=a(h[c].el).width(h[c].width).css("display",g);try{g.removeAttr("rowSpan")}catch(f){g.attr("rowSpan",1)}d.append(g);i=g.children("span.ui-jqgrid-resize");0<i.length&&(i[0].style.height="");g.children("div")[0].style.top=""}a(j).children("tr.ui-jqgrid-labels").remove();a(j).prepend(d);
+!0===b&&a(this).jqGrid("setGridParam",{groupHeader:null})}})},setGroupHeaders:function(b){b=a.extend({useColSpanStyle:!1,groupHeaders:[]},b||{});return this.each(function(){this.p.groupHeader=b;var d,c,e=0,h,g,i,j,q,f=this.p.colModel,n=f.length,m=this.grid.headers,o=a("table.ui-jqgrid-htable",this.grid.hDiv),k=o.children("thead").children("tr.ui-jqgrid-labels:last").addClass("jqg-second-row-header");h=o.children("thead");var l=o.find(".jqg-first-row-header");null===l.html()?l=a("<tr>",{role:"row",
+"aria-hidden":"true"}).addClass("jqg-first-row-header").css("height","auto"):l.empty();var p,r=function(a,b){for(var c=0,d=b.length;c<d;c++)if(b[c].startColumnName===a)return c;return-1};a(this).prepend(h);h=a("<tr>",{role:"rowheader"}).addClass("ui-jqgrid-labels jqg-third-row-header");for(d=0;d<n;d++)if(i=m[d].el,j=a(i),c=f[d],g={height:"0px",width:m[d].width+"px",display:c.hidden?"none":""},a("<th>",{role:"gridcell"}).css(g).addClass("ui-first-th-"+this.p.direction).appendTo(l),i.style.width="",
+g=r(c.name,b.groupHeaders),0<=g){g=b.groupHeaders[g];e=g.numberOfColumns;q=g.titleText;for(g=c=0;g<e&&d+g<n;g++)f[d+g].hidden||c++;g=a("<th>").attr({role:"columnheader"}).addClass("ui-state-default ui-th-column-header ui-th-"+this.p.direction).css({height:"22px","border-top":"0px none"}).html(q);0<c&&g.attr("colspan",""+c);this.p.headertitles&&g.attr("title",g.text());0===c&&g.hide();j.before(g);h.append(i);e-=1}else 0===e?b.useColSpanStyle?j.attr("rowspan","2"):(a("<th>",{role:"columnheader"}).addClass("ui-state-default ui-th-column-header ui-th-"+
+this.p.direction).css({display:c.hidden?"none":"","border-top":"0px none"}).insertBefore(j),h.append(i)):(h.append(i),e--);f=a(this).children("thead");f.prepend(l);h.insertAfter(k);o.append(f);b.useColSpanStyle&&(o.find("span.ui-jqgrid-resize").each(function(){var b=a(this).parent();b.is(":visible")&&(this.style.cssText="height: "+b.height()+"px !important; cursor: col-resize;")}),o.find("div.ui-jqgrid-sortable").each(function(){var b=a(this),c=b.parent();c.is(":visible")&&c.is(":has(span.ui-jqgrid-resize)")&&
+b.css("top",(c.height()-b.outerHeight())/2+"px")}));p=f.find("tr.jqg-first-row-header");a(this).bind("jqGridResizeStop.setGroupHeaders",function(a,b,c){p.find("th").eq(c).width(b)})})},setFrozenColumns:function(){return this.each(function(){if(this.grid){var b=this,d=b.p.colModel,c=0,e=d.length,h=-1,g=!1;if(!(!0===b.p.subGrid||!0===b.p.treeGrid||!0===b.p.cellEdit||b.p.sortable||b.p.scroll||b.p.grouping)){b.p.rownumbers&&c++;for(b.p.multiselect&&c++;c<e;){if(!0===d[c].frozen)g=!0,h=c;else break;c++}if(0<=
+h&&g){d=b.p.caption?a(b.grid.cDiv).outerHeight():0;c=a(".ui-jqgrid-htable","#gview_"+a.jgrid.jqID(b.p.id)).height();b.p.toppager&&(d+=a(b.grid.topDiv).outerHeight());!0===b.p.toolbar[0]&&"bottom"!=b.p.toolbar[1]&&(d+=a(b.grid.uDiv).outerHeight());b.grid.fhDiv=a('<div style="position:absolute;left:0px;top:'+d+"px;height:"+c+'px;" class="frozen-div ui-state-default ui-jqgrid-hdiv"></div>');b.grid.fbDiv=a('<div style="position:absolute;left:0px;top:'+(parseInt(d,10)+parseInt(c,10)+1)+'px;overflow-y:hidden" class="frozen-bdiv ui-jqgrid-bdiv"></div>');
+a("#gview_"+a.jgrid.jqID(b.p.id)).append(b.grid.fhDiv);d=a(".ui-jqgrid-htable","#gview_"+a.jgrid.jqID(b.p.id)).clone(!0);if(b.p.groupHeader){a("tr.jqg-first-row-header, tr.jqg-third-row-header",d).each(function(){a("th:gt("+h+")",this).remove()});var i=-1,j=-1;a("tr.jqg-second-row-header th",d).each(function(){var b=parseInt(a(this).attr("colspan"),10);b&&(i+=b,j++);if(i===h)return!1});i!==h&&(j=h);a("tr.jqg-second-row-header",d).each(function(){a("th:gt("+j+")",this).remove()})}else a("tr",d).each(function(){a("th:gt("+
+h+")",this).remove()});a(d).width(1);a(b.grid.fhDiv).append(d).mousemove(function(a){if(b.grid.resizing)return b.grid.dragMove(a),!1});a(b).bind("jqGridResizeStop.setFrozenColumns",function(c,d,e){c=a(".ui-jqgrid-htable",b.grid.fhDiv);a("th:eq("+e+")",c).width(d);c=a(".ui-jqgrid-btable",b.grid.fbDiv);a("tr:first td:eq("+e+")",c).width(d)});a(b).bind("jqGridOnSortCol.setFrozenColumns",function(c,d){var e=a("tr.ui-jqgrid-labels:last th:eq("+b.p.lastsort+")",b.grid.fhDiv),g=a("tr.ui-jqgrid-labels:last th:eq("+
+d+")",b.grid.fhDiv);a("span.ui-grid-ico-sort",e).addClass("ui-state-disabled");a(e).attr("aria-selected","false");a("span.ui-icon-"+b.p.sortorder,g).removeClass("ui-state-disabled");a(g).attr("aria-selected","true");!b.p.viewsortcols[0]&&b.p.lastsort!=d&&(a("span.s-ico",e).hide(),a("span.s-ico",g).show())});a("#gview_"+a.jgrid.jqID(b.p.id)).append(b.grid.fbDiv);jQuery(b.grid.bDiv).scroll(function(){jQuery(b.grid.fbDiv).scrollTop(jQuery(this).scrollTop())});!0===b.p.hoverrows&&a("#"+a.jgrid.jqID(b.p.id)).unbind("mouseover").unbind("mouseout");
+a(b).bind("jqGridAfterGridComplete.setFrozenColumns",function(){a("#"+a.jgrid.jqID(b.p.id)+"_frozen").remove();jQuery(b.grid.fbDiv).height(jQuery(b.grid.bDiv).height()-16);var c=a("#"+a.jgrid.jqID(b.p.id)).clone(!0);a("tr",c).each(function(){a("td:gt("+h+")",this).remove()});a(c).width(1).attr("id",b.p.id+"_frozen");a(b.grid.fbDiv).append(c);!0===b.p.hoverrows&&(a("tr.jqgrow",c).hover(function(){a(this).addClass("ui-state-hover");a("#"+a.jgrid.jqID(this.id),"#"+a.jgrid.jqID(b.p.id)).addClass("ui-state-hover")},
+function(){a(this).removeClass("ui-state-hover");a("#"+a.jgrid.jqID(this.id),"#"+a.jgrid.jqID(b.p.id)).removeClass("ui-state-hover")}),a("tr.jqgrow","#"+a.jgrid.jqID(b.p.id)).hover(function(){a(this).addClass("ui-state-hover");a("#"+a.jgrid.jqID(this.id),"#"+a.jgrid.jqID(b.p.id)+"_frozen").addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover");a("#"+a.jgrid.jqID(this.id),"#"+a.jgrid.jqID(b.p.id)+"_frozen").removeClass("ui-state-hover")}));c=null});b.p.frozenColumns=!0}}}})},
+destroyFrozenColumns:function(){return this.each(function(){if(this.grid&&!0===this.p.frozenColumns){a(this.grid.fhDiv).remove();a(this.grid.fbDiv).remove();this.grid.fhDiv=null;this.grid.fbDiv=null;a(this).unbind(".setFrozenColumns");if(!0===this.p.hoverrows){var b;a("#"+a.jgrid.jqID(this.p.id)).bind("mouseover",function(d){b=a(d.target).closest("tr.jqgrow");"ui-subgrid"!==a(b).attr("class")&&a(b).addClass("ui-state-hover")}).bind("mouseout",function(d){b=a(d.target).closest("tr.jqgrow");a(b).removeClass("ui-state-hover")})}this.p.frozenColumns=
+!1}})}})})(jQuery);
+(function(a){a.extend(a.jgrid,{showModal:function(a){a.w.show()},closeModal:function(a){a.w.hide().attr("aria-hidden","true");a.o&&a.o.remove()},hideModal:function(d,b){b=a.extend({jqm:!0,gb:""},b||{});if(b.onClose){var c=b.onClose(d);if("boolean"==typeof c&&!c)return}if(a.fn.jqm&&!0===b.jqm)a(d).attr("aria-hidden","true").jqmHide();else{if(""!==b.gb)try{a(".jqgrid-overlay:first",b.gb).hide()}catch(f){}a(d).hide().attr("aria-hidden","true")}},findPos:function(a){var b=0,c=0;if(a.offsetParent){do b+=
+a.offsetLeft,c+=a.offsetTop;while(a=a.offsetParent)}return[b,c]},createModal:function(d,b,c,f,g,h,i){var e=document.createElement("div"),l,j=this,i=a.extend({},i||{});l="rtl"==a(c.gbox).attr("dir")?!0:!1;e.className="ui-widget ui-widget-content ui-corner-all ui-jqdialog";e.id=d.themodal;var k=document.createElement("div");k.className="ui-jqdialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix";k.id=d.modalhead;a(k).append("<span class='ui-jqdialog-title'>"+c.caption+"</span>");var n=a("<a href='javascript:void(0)' class='ui-jqdialog-titlebar-close ui-corner-all'></a>").hover(function(){n.addClass("ui-state-hover")},
+function(){n.removeClass("ui-state-hover")}).append("<span class='ui-icon ui-icon-closethick'></span>");a(k).append(n);l?(e.dir="rtl",a(".ui-jqdialog-title",k).css("float","right"),a(".ui-jqdialog-titlebar-close",k).css("left","0.3em")):(e.dir="ltr",a(".ui-jqdialog-title",k).css("float","left"),a(".ui-jqdialog-titlebar-close",k).css("right","0.3em"));var m=document.createElement("div");a(m).addClass("ui-jqdialog-content ui-widget-content").attr("id",d.modalcontent);a(m).append(b);e.appendChild(m);
+a(e).prepend(k);!0===h?a("body").append(e):"string"==typeof h?a(h).append(e):a(e).insertBefore(f);a(e).css(i);"undefined"===typeof c.jqModal&&(c.jqModal=!0);b={};if(a.fn.jqm&&!0===c.jqModal)0===c.left&&(0===c.top&&c.overlay)&&(i=[],i=a.jgrid.findPos(g),c.left=i[0]+4,c.top=i[1]+4),b.top=c.top+"px",b.left=c.left;else if(0!==c.left||0!==c.top)b.left=c.left,b.top=c.top+"px";a("a.ui-jqdialog-titlebar-close",k).click(function(){var b=a("#"+a.jgrid.jqID(d.themodal)).data("onClose")||c.onClose,e=a("#"+a.jgrid.jqID(d.themodal)).data("gbox")||
+c.gbox;j.hideModal("#"+a.jgrid.jqID(d.themodal),{gb:e,jqm:c.jqModal,onClose:b});return false});if(0===c.width||!c.width)c.width=300;if(0===c.height||!c.height)c.height=200;c.zIndex||(f=a(f).parents("*[role=dialog]").filter(":first").css("z-index"),c.zIndex=f?parseInt(f,10)+2:950);f=0;l&&(b.left&&!h)&&(f=a(c.gbox).width()-(!isNaN(c.width)?parseInt(c.width,10):0)-8,b.left=parseInt(b.left,10)+parseInt(f,10));b.left&&(b.left+="px");a(e).css(a.extend({width:isNaN(c.width)?"auto":c.width+"px",height:isNaN(c.height)?
+"auto":c.height+"px",zIndex:c.zIndex,overflow:"hidden"},b)).attr({tabIndex:"-1",role:"dialog","aria-labelledby":d.modalhead,"aria-hidden":"true"});"undefined"==typeof c.drag&&(c.drag=!0);"undefined"==typeof c.resize&&(c.resize=!0);if(c.drag)if(a(k).css("cursor","move"),a.fn.jqDrag)a(e).jqDrag(k);else try{a(e).draggable({handle:a("#"+a.jgrid.jqID(k.id))})}catch(o){}if(c.resize)if(a.fn.jqResize)a(e).append("<div class='jqResize ui-resizable-handle ui-resizable-se ui-icon ui-icon-gripsmall-diagonal-se ui-icon-grip-diagonal-se'></div>"),
+a("#"+a.jgrid.jqID(d.themodal)).jqResize(".jqResize",d.scrollelm?"#"+a.jgrid.jqID(d.scrollelm):!1);else try{a(e).resizable({handles:"se, sw",alsoResize:d.scrollelm?"#"+a.jgrid.jqID(d.scrollelm):!1})}catch(p){}!0===c.closeOnEscape&&a(e).keydown(function(b){if(b.which==27){b=a("#"+a.jgrid.jqID(d.themodal)).data("onClose")||c.onClose;j.hideModal(this,{gb:c.gbox,jqm:c.jqModal,onClose:b})}})},viewModal:function(d,b){b=a.extend({toTop:!0,overlay:10,modal:!1,overlayClass:"ui-widget-overlay",onShow:a.jgrid.showModal,
+onHide:a.jgrid.closeModal,gbox:"",jqm:!0,jqM:!0},b||{});if(a.fn.jqm&&!0===b.jqm)b.jqM?a(d).attr("aria-hidden","false").jqm(b).jqmShow():a(d).attr("aria-hidden","false").jqmShow();else{""!==b.gbox&&(a(".jqgrid-overlay:first",b.gbox).show(),a(d).data("gbox",b.gbox));a(d).show().attr("aria-hidden","false");try{a(":input:visible",d)[0].focus()}catch(c){}}},info_dialog:function(d,b,c,f){var g={width:290,height:"auto",dataheight:"auto",drag:!0,resize:!1,caption:"<b>"+d+"</b>",left:250,top:170,zIndex:1E3,
+jqModal:!0,modal:!1,closeOnEscape:!0,align:"center",buttonalign:"center",buttons:[]};a.extend(g,f||{});var h=g.jqModal,i=this;a.fn.jqm&&!h&&(h=!1);d="";if(0<g.buttons.length)for(f=0;f<g.buttons.length;f++)"undefined"==typeof g.buttons[f].id&&(g.buttons[f].id="info_button_"+f),d+="<a href='javascript:void(0)' id='"+g.buttons[f].id+"' class='fm-button ui-state-default ui-corner-all'>"+g.buttons[f].text+"</a>";f=isNaN(g.dataheight)?g.dataheight:g.dataheight+"px";b="<div id='info_id'>"+("<div id='infocnt' style='margin:0px;padding-bottom:1em;width:100%;overflow:auto;position:relative;height:"+
+f+";"+("text-align:"+g.align+";")+"'>"+b+"</div>");b+=c?"<div class='ui-widget-content ui-helper-clearfix' style='text-align:"+g.buttonalign+";padding-bottom:0.8em;padding-top:0.5em;background-image: none;border-width: 1px 0 0 0;'><a href='javascript:void(0)' id='closedialog' class='fm-button ui-state-default ui-corner-all'>"+c+"</a>"+d+"</div>":""!==d?"<div class='ui-widget-content ui-helper-clearfix' style='text-align:"+g.buttonalign+";padding-bottom:0.8em;padding-top:0.5em;background-image: none;border-width: 1px 0 0 0;'>"+
+d+"</div>":"";b+="</div>";try{"false"==a("#info_dialog").attr("aria-hidden")&&a.jgrid.hideModal("#info_dialog",{jqm:h}),a("#info_dialog").remove()}catch(e){}a.jgrid.createModal({themodal:"info_dialog",modalhead:"info_head",modalcontent:"info_content",scrollelm:"infocnt"},b,g,"","",!0);d&&a.each(g.buttons,function(b){a("#"+a.jgrid.jqID(this.id),"#info_id").bind("click",function(){g.buttons[b].onClick.call(a("#info_dialog"));return!1})});a("#closedialog","#info_id").click(function(){i.hideModal("#info_dialog",
+{jqm:h});return!1});a(".fm-button","#info_dialog").hover(function(){a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")});a.isFunction(g.beforeOpen)&&g.beforeOpen();a.jgrid.viewModal("#info_dialog",{onHide:function(a){a.w.hide().remove();a.o&&a.o.remove()},modal:g.modal,jqm:h});a.isFunction(g.afterOpen)&&g.afterOpen();try{a("#info_dialog").focus()}catch(l){}},createEl:function(d,b,c,f,g){function h(b,d){a.isFunction(d.dataInit)&&d.dataInit.call(l,b);d.dataEvents&&
+a.each(d.dataEvents,function(){void 0!==this.data?a(b).bind(this.type,this.data,this.fn):a(b).bind(this.type,this.fn)});return d}function i(b,d,c){var e="dataInit dataEvents dataUrl buildSelect sopt searchhidden defaultValue attr".split(" ");"undefined"!=typeof c&&a.isArray(c)&&a.merge(e,c);a.each(d,function(d,c){-1===a.inArray(d,e)&&a(b).attr(d,c)});d.hasOwnProperty("id")||a(b).attr("id",a.jgrid.randId())}var e="",l=this;switch(d){case "textarea":e=document.createElement("textarea");f?b.cols||a(e).css({width:"98%"}):
+b.cols||(b.cols=20);b.rows||(b.rows=2);if("&nbsp;"==c||"&#160;"==c||1==c.length&&160==c.charCodeAt(0))c="";e.value=c;i(e,b);b=h(e,b);a(e).attr({role:"textbox",multiline:"true"});break;case "checkbox":e=document.createElement("input");e.type="checkbox";b.value?(d=b.value.split(":"),c===d[0]&&(e.checked=!0,e.defaultChecked=!0),e.value=d[0],a(e).attr("offval",d[1])):(d=c.toLowerCase(),0>d.search(/(false|0|no|off|undefined)/i)&&""!==d?(e.checked=!0,e.defaultChecked=!0,e.value=c):e.value="on",a(e).attr("offval",
+"off"));i(e,b,["value"]);b=h(e,b);a(e).attr("role","checkbox");break;case "select":e=document.createElement("select");e.setAttribute("role","select");f=[];!0===b.multiple?(d=!0,e.multiple="multiple",a(e).attr("aria-multiselectable","true")):d=!1;if("undefined"!=typeof b.dataUrl)a.ajax(a.extend({url:b.dataUrl,type:"GET",dataType:"html",context:{elem:e,options:b,vl:c},success:function(d){var b=[],c=this.elem,e=this.vl,f=a.extend({},this.options),g=f.multiple===true;a.isFunction(f.buildSelect)&&(d=f.buildSelect.call(l,
+d));if(d=a(d).html()){a(c).append(d);i(c,f);f=h(c,f);if(typeof f.size==="undefined")f.size=g?3:1;if(g){b=e.split(",");b=a.map(b,function(b){return a.trim(b)})}else b[0]=a.trim(e);setTimeout(function(){a("option",c).each(function(d){if(d===0&&c.multiple)this.selected=false;a(this).attr("role","option");if(a.inArray(a.trim(a(this).text()),b)>-1||a.inArray(a.trim(a(this).val()),b)>-1)this.selected="selected"})},0)}}},g||{}));else if(b.value){var j;"undefined"===typeof b.size&&(b.size=d?3:1);d&&(f=c.split(","),
+f=a.map(f,function(b){return a.trim(b)}));"function"===typeof b.value&&(b.value=b.value());var k,n,m=void 0===b.separator?":":b.separator,g=void 0===b.delimiter?";":b.delimiter;if("string"===typeof b.value){k=b.value.split(g);for(j=0;j<k.length;j++){n=k[j].split(m);2<n.length&&(n[1]=a.map(n,function(a,b){if(b>0)return a}).join(m));g=document.createElement("option");g.setAttribute("role","option");g.value=n[0];g.innerHTML=n[1];e.appendChild(g);if(!d&&(a.trim(n[0])==a.trim(c)||a.trim(n[1])==a.trim(c)))g.selected=
+"selected";if(d&&(-1<a.inArray(a.trim(n[1]),f)||-1<a.inArray(a.trim(n[0]),f)))g.selected="selected"}}else if("object"===typeof b.value)for(j in m=b.value,m)if(m.hasOwnProperty(j)){g=document.createElement("option");g.setAttribute("role","option");g.value=j;g.innerHTML=m[j];e.appendChild(g);if(!d&&(a.trim(j)==a.trim(c)||a.trim(m[j])==a.trim(c)))g.selected="selected";if(d&&(-1<a.inArray(a.trim(m[j]),f)||-1<a.inArray(a.trim(j),f)))g.selected="selected"}i(e,b,["value"]);b=h(e,b)}break;case "text":case "password":case "button":j=
+"button"==d?"button":"textbox";e=document.createElement("input");e.type=d;e.value=c;i(e,b);b=h(e,b);"button"!=d&&(f?b.size||a(e).css({width:"98%"}):b.size||(b.size=20));a(e).attr("role",j);break;case "image":case "file":e=document.createElement("input");e.type=d;i(e,b);b=h(e,b);break;case "custom":e=document.createElement("span");try{if(a.isFunction(b.custom_element))if(m=b.custom_element.call(l,c,b))m=a(m).addClass("customelement").attr({id:b.id,name:b.name}),a(e).empty().append(m);else throw"e2";
+else throw"e1";}catch(o){"e1"==o&&a.jgrid.info_dialog(a.jgrid.errors.errcap,"function 'custom_element' "+a.jgrid.edit.msg.nodefined,a.jgrid.edit.bClose),"e2"==o?a.jgrid.info_dialog(a.jgrid.errors.errcap,"function 'custom_element' "+a.jgrid.edit.msg.novalue,a.jgrid.edit.bClose):a.jgrid.info_dialog(a.jgrid.errors.errcap,"string"===typeof o?o:o.message,a.jgrid.edit.bClose)}}return e},checkDate:function(a,b){var c={},f,a=a.toLowerCase();f=-1!=a.indexOf("/")?"/":-1!=a.indexOf("-")?"-":-1!=a.indexOf(".")?
+".":"/";a=a.split(f);b=b.split(f);if(3!=b.length)return!1;f=-1;for(var g,h=-1,i=-1,e=0;e<a.length;e++)g=isNaN(b[e])?0:parseInt(b[e],10),c[a[e]]=g,g=a[e],-1!=g.indexOf("y")&&(f=e),-1!=g.indexOf("m")&&(i=e),-1!=g.indexOf("d")&&(h=e);g="y"==a[f]||"yyyy"==a[f]?4:"yy"==a[f]?2:-1;var e=function(a){for(var b=1;b<=a;b++){this[b]=31;if(4==b||6==b||9==b||11==b)this[b]=30;2==b&&(this[b]=29)}return this}(12),l;if(-1===f)return!1;l=c[a[f]].toString();2==g&&1==l.length&&(g=1);if(l.length!=g||0===c[a[f]]&&"00"!=
+b[f]||-1===i)return!1;l=c[a[i]].toString();if(1>l.length||(1>c[a[i]]||12<c[a[i]])||-1===h)return!1;l=c[a[h]].toString();return 1>l.length||1>c[a[h]]||31<c[a[h]]||2==c[a[i]]&&c[a[h]]>(0===c[a[f]]%4&&(0!==c[a[f]]%100||0===c[a[f]]%400)?29:28)||c[a[h]]>e[c[a[i]]]?!1:!0},isEmpty:function(a){return a.match(/^\s+$/)||""===a?!0:!1},checkTime:function(d){var b=/^(\d{1,2}):(\d{2})([ap]m)?$/;if(!a.jgrid.isEmpty(d))if(d=d.match(b)){if(d[3]){if(1>d[1]||12<d[1])return!1}else if(23<d[1])return!1;if(59<d[2])return!1}else return!1;
+return!0},checkValues:function(d,b,c,f,g){var h,i;if("undefined"===typeof f)if("string"==typeof b){f=0;for(g=c.p.colModel.length;f<g;f++)if(c.p.colModel[f].name==b){h=c.p.colModel[f].editrules;b=f;try{i=c.p.colModel[f].formoptions.label}catch(e){}break}}else 0<=b&&(h=c.p.colModel[b].editrules);else h=f,i=void 0===g?"_":g;if(h){i||(i=c.p.colNames[b]);if(!0===h.required&&a.jgrid.isEmpty(d))return[!1,i+": "+a.jgrid.edit.msg.required,""];f=!1===h.required?!1:!0;if(!0===h.number&&!(!1===f&&a.jgrid.isEmpty(d))&&
+isNaN(d))return[!1,i+": "+a.jgrid.edit.msg.number,""];if("undefined"!=typeof h.minValue&&!isNaN(h.minValue)&&parseFloat(d)<parseFloat(h.minValue))return[!1,i+": "+a.jgrid.edit.msg.minValue+" "+h.minValue,""];if("undefined"!=typeof h.maxValue&&!isNaN(h.maxValue)&&parseFloat(d)>parseFloat(h.maxValue))return[!1,i+": "+a.jgrid.edit.msg.maxValue+" "+h.maxValue,""];if(!0===h.email&&!(!1===f&&a.jgrid.isEmpty(d))&&(g=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i,
+!g.test(d)))return[!1,i+": "+a.jgrid.edit.msg.email,""];if(!0===h.integer&&!(!1===f&&a.jgrid.isEmpty(d))&&(isNaN(d)||0!==d%1||-1!=d.indexOf(".")))return[!1,i+": "+a.jgrid.edit.msg.integer,""];if(!0===h.date&&!(!1===f&&a.jgrid.isEmpty(d))&&(b=c.p.colModel[b].formatoptions&&c.p.colModel[b].formatoptions.newformat?c.p.colModel[b].formatoptions.newformat:c.p.colModel[b].datefmt||"Y-m-d",!a.jgrid.checkDate(b,d)))return[!1,i+": "+a.jgrid.edit.msg.date+" - "+b,""];if(!0===h.time&&!(!1===f&&a.jgrid.isEmpty(d))&&
+!a.jgrid.checkTime(d))return[!1,i+": "+a.jgrid.edit.msg.date+" - hh:mm (am/pm)",""];if(!0===h.url&&!(!1===f&&a.jgrid.isEmpty(d))&&(g=/^(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i,!g.test(d)))return[!1,i+": "+a.jgrid.edit.msg.url,""];if(!0===h.custom&&!(!1===f&&a.jgrid.isEmpty(d)))return a.isFunction(h.custom_func)?(d=h.custom_func.call(c,d,i),a.isArray(d)?d:[!1,a.jgrid.edit.msg.customarray,""]):[!1,a.jgrid.edit.msg.customfcheck,
+""]}return[!0,"",""]}})})(jQuery);
+(function(a){var c={};a.jgrid.extend({searchGrid:function(c){c=a.extend({recreateFilter:!1,drag:!0,sField:"searchField",sValue:"searchString",sOper:"searchOper",sFilter:"filters",loadDefaults:!0,beforeShowSearch:null,afterShowSearch:null,onInitializeSearch:null,afterRedraw:null,afterChange:null,closeAfterSearch:!1,closeAfterReset:!1,closeOnEscape:!1,searchOnEnter:!1,multipleSearch:!1,multipleGroup:!1,top:0,left:0,jqModal:!0,modal:!1,resize:!0,width:450,height:"auto",dataheight:"auto",showQuery:!1,
+errorcheck:!0,sopt:null,stringResult:void 0,onClose:null,onSearch:null,onReset:null,toTop:!0,overlay:30,columns:[],tmplNames:null,tmplFilters:null,tmplLabel:" Template: ",showOnLoad:!1,layer:null},a.jgrid.search,c||{});return this.each(function(){function d(b){r=a(e).triggerHandler("jqGridFilterBeforeShow",[b]);"undefined"===typeof r&&(r=!0);r&&a.isFunction(c.beforeShowSearch)&&(r=c.beforeShowSearch.call(e,b));r&&(a.jgrid.viewModal("#"+a.jgrid.jqID(t.themodal),{gbox:"#gbox_"+a.jgrid.jqID(l),jqm:c.jqModal,
+modal:c.modal,overlay:c.overlay,toTop:c.toTop}),a(e).triggerHandler("jqGridFilterAfterShow",[b]),a.isFunction(c.afterShowSearch)&&c.afterShowSearch.call(e,b))}var e=this;if(e.grid){var l="fbox_"+e.p.id,r=!0,t={themodal:"searchmod"+l,modalhead:"searchhd"+l,modalcontent:"searchcnt"+l,scrollelm:l},s=e.p.postData[c.sFilter];"string"===typeof s&&(s=a.jgrid.parse(s));!0===c.recreateFilter&&a("#"+a.jgrid.jqID(t.themodal)).remove();if(null!==a("#"+a.jgrid.jqID(t.themodal)).html())d(a("#fbox_"+a.jgrid.jqID(+e.p.id)));
+else{var p=a("<div><div id='"+l+"' class='searchFilter' style='overflow:auto'></div></div>").insertBefore("#gview_"+a.jgrid.jqID(e.p.id)),g="left",f="";"rtl"==e.p.direction&&(g="right",f=" style='text-align:left'",p.attr("dir","rtl"));var n=a.extend([],e.p.colModel),w="<a href='javascript:void(0)' id='"+l+"_search' class='fm-button ui-state-default ui-corner-all fm-button-icon-right ui-reset'><span class='ui-icon ui-icon-search'></span>"+c.Find+"</a>",b="<a href='javascript:void(0)' id='"+l+"_reset' class='fm-button ui-state-default ui-corner-all fm-button-icon-left ui-search'><span class='ui-icon ui-icon-arrowreturnthick-1-w'></span>"+
+c.Reset+"</a>",m="",h="",k,j=!1,o=-1;c.showQuery&&(m="<a href='javascript:void(0)' id='"+l+"_query' class='fm-button ui-state-default ui-corner-all fm-button-icon-left'><span class='ui-icon ui-icon-comment'></span>Query</a>");c.columns.length?n=c.columns:a.each(n,function(a,b){if(!b.label)b.label=e.p.colNames[a];if(!j){var c=typeof b.search==="undefined"?true:b.search,d=b.hidden===true;if(b.searchoptions&&b.searchoptions.searchhidden===true&&c||c&&!d){j=true;k=b.index||b.name;o=a}}});if(!s&&k||!1===
+c.multipleSearch){var y="eq";0<=o&&n[o].searchoptions&&n[o].searchoptions.sopt?y=n[o].searchoptions.sopt[0]:c.sopt&&c.sopt.length&&(y=c.sopt[0]);s={groupOp:"AND",rules:[{field:k,op:y,data:""}]}}j=!1;c.tmplNames&&c.tmplNames.length&&(j=!0,h=c.tmplLabel,h+="<select class='ui-template'>",h+="<option value='default'>Default</option>",a.each(c.tmplNames,function(a,b){h=h+("<option value='"+a+"'>"+b+"</option>")}),h+="</select>");g="<table class='EditTable' style='border:0px none;margin-top:5px' id='"+
+l+"_2'><tbody><tr><td colspan='2'><hr class='ui-widget-content' style='margin:1px'/></td></tr><tr><td class='EditButton' style='text-align:"+g+"'>"+b+h+"</td><td class='EditButton' "+f+">"+m+w+"</td></tr></tbody></table>";l=a.jgrid.jqID(l);a("#"+l).jqFilter({columns:n,filter:c.loadDefaults?s:null,showQuery:c.showQuery,errorcheck:c.errorcheck,sopt:c.sopt,groupButton:c.multipleGroup,ruleButtons:c.multipleSearch,afterRedraw:c.afterRedraw,_gridsopt:a.jgrid.search.odata,ajaxSelectOptions:e.p.ajaxSelectOptions,
+groupOps:c.groupOps,onChange:function(){this.p.showQuery&&a(".query",this).html(this.toUserFriendlyString());a.isFunction(c.afterChange)&&c.afterChange.call(e,a("#"+l),c)},direction:e.p.direction});p.append(g);j&&(c.tmplFilters&&c.tmplFilters.length)&&a(".ui-template",p).bind("change",function(){var b=a(this).val();b=="default"?a("#"+l).jqFilter("addFilter",s):a("#"+l).jqFilter("addFilter",c.tmplFilters[parseInt(b,10)]);return false});!0===c.multipleGroup&&(c.multipleSearch=!0);a(e).triggerHandler("jqGridFilterInitialize",
+[a("#"+l)]);a.isFunction(c.onInitializeSearch)&&c.onInitializeSearch.call(e,a("#"+l));c.gbox="#gbox_"+l;c.layer?a.jgrid.createModal(t,p,c,"#gview_"+a.jgrid.jqID(e.p.id),a("#gbox_"+a.jgrid.jqID(e.p.id))[0],"#"+a.jgrid.jqID(c.layer),{position:"relative"}):a.jgrid.createModal(t,p,c,"#gview_"+a.jgrid.jqID(e.p.id),a("#gbox_"+a.jgrid.jqID(e.p.id))[0]);(c.searchOnEnter||c.closeOnEscape)&&a("#"+a.jgrid.jqID(t.themodal)).keydown(function(b){var d=a(b.target);if(c.searchOnEnter&&b.which===13&&!d.hasClass("add-group")&&
+!d.hasClass("add-rule")&&!d.hasClass("delete-group")&&!d.hasClass("delete-rule")&&(!d.hasClass("fm-button")||!d.is("[id$=_query]"))){a("#"+l+"_search").focus().click();return false}if(c.closeOnEscape&&b.which===27){a("#"+a.jgrid.jqID(t.modalhead)).find(".ui-jqdialog-titlebar-close").focus().click();return false}});m&&a("#"+l+"_query").bind("click",function(){a(".queryresult",p).toggle();return false});void 0===c.stringResult&&(c.stringResult=c.multipleSearch);a("#"+l+"_search").bind("click",function(){var b=
+a("#"+l),d={},h,q=b.jqFilter("filterData");if(c.errorcheck){b[0].hideError();c.showQuery||b.jqFilter("toSQLString");if(b[0].p.error){b[0].showError();return false}}if(c.stringResult){try{h=xmlJsonClass.toJson(q,"","",false)}catch(f){try{h=JSON.stringify(q)}catch(g){}}if(typeof h==="string"){d[c.sFilter]=h;a.each([c.sField,c.sValue,c.sOper],function(){d[this]=""})}}else if(c.multipleSearch){d[c.sFilter]=q;a.each([c.sField,c.sValue,c.sOper],function(){d[this]=""})}else{d[c.sField]=q.rules[0].field;
+d[c.sValue]=q.rules[0].data;d[c.sOper]=q.rules[0].op;d[c.sFilter]=""}e.p.search=true;a.extend(e.p.postData,d);a(e).triggerHandler("jqGridFilterSearch");a.isFunction(c.onSearch)&&c.onSearch.call(e);a(e).trigger("reloadGrid",[{page:1}]);c.closeAfterSearch&&a.jgrid.hideModal("#"+a.jgrid.jqID(t.themodal),{gb:"#gbox_"+a.jgrid.jqID(e.p.id),jqm:c.jqModal,onClose:c.onClose});return false});a("#"+l+"_reset").bind("click",function(){var b={},d=a("#"+l);e.p.search=false;c.multipleSearch===false?b[c.sField]=
+b[c.sValue]=b[c.sOper]="":b[c.sFilter]="";d[0].resetFilter();j&&a(".ui-template",p).val("default");a.extend(e.p.postData,b);a(e).triggerHandler("jqGridFilterReset");a.isFunction(c.onReset)&&c.onReset.call(e);a(e).trigger("reloadGrid",[{page:1}]);return false});d(a("#"+l));a(".fm-button:not(.ui-state-disabled)",p).hover(function(){a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")})}}})},editGridRow:function(u,d){d=a.extend({top:0,left:0,width:300,height:"auto",dataheight:"auto",
+modal:!1,overlay:30,drag:!0,resize:!0,url:null,mtype:"POST",clearAfterAdd:!0,closeAfterEdit:!1,reloadAfterSubmit:!0,onInitializeForm:null,beforeInitData:null,beforeShowForm:null,afterShowForm:null,beforeSubmit:null,afterSubmit:null,onclickSubmit:null,afterComplete:null,onclickPgButtons:null,afterclickPgButtons:null,editData:{},recreateForm:!1,jqModal:!0,closeOnEscape:!1,addedrow:"first",topinfo:"",bottominfo:"",saveicon:[],closeicon:[],savekey:[!1,13],navkeys:[!1,38,40],checkOnSubmit:!1,checkOnUpdate:!1,
+_savedData:{},processing:!1,onClose:null,ajaxEditOptions:{},serializeEditData:null,viewPagerButtons:!0},a.jgrid.edit,d||{});c[a(this)[0].p.id]=d;return this.each(function(){function e(){a(j+" > tbody > tr > td > .FormElement").each(function(){var d=a(".customelement",this);if(d.length){var c=a(d[0]).attr("name");a.each(b.p.colModel,function(){if(this.name===c&&this.editoptions&&a.isFunction(this.editoptions.custom_value)){try{if(i[c]=this.editoptions.custom_value.call(b,a("#"+a.jgrid.jqID(c),j),"get"),
+void 0===i[c])throw"e1";}catch(d){"e1"===d?a.jgrid.info_dialog(jQuery.jgrid.errors.errcap,"function 'custom_value' "+a.jgrid.edit.msg.novalue,jQuery.jgrid.edit.bClose):a.jgrid.info_dialog(jQuery.jgrid.errors.errcap,d.message,jQuery.jgrid.edit.bClose)}return!0}})}else{switch(a(this).get(0).type){case "checkbox":a(this).is(":checked")?i[this.name]=a(this).val():(d=a(this).attr("offval"),i[this.name]=d);break;case "select-one":i[this.name]=a("option:selected",this).val();B[this.name]=a("option:selected",
+this).text();break;case "select-multiple":i[this.name]=a(this).val();i[this.name]=i[this.name]?i[this.name].join(","):"";var e=[];a("option:selected",this).each(function(b,d){e[b]=a(d).text()});B[this.name]=e.join(",");break;case "password":case "text":case "textarea":case "button":i[this.name]=a(this).val()}b.p.autoencode&&(i[this.name]=a.jgrid.htmlEncode(i[this.name]))}});return!0}function l(d,e,h,q){var i,f,g,k=0,j,o,l,p=[],n=!1,u="",m;for(m=1;m<=q;m++)u+="<td class='CaptionTD'>&#160;</td><td class='DataTD'>&#160;</td>";
+"_empty"!=d&&(n=a(e).jqGrid("getInd",d));a(e.p.colModel).each(function(m){i=this.name;o=(f=this.editrules&&!0===this.editrules.edithidden?!1:!0===this.hidden?!0:!1)?"style='display:none'":"";if("cb"!==i&&"subgrid"!==i&&!0===this.editable&&"rn"!==i){if(!1===n)j="";else if(i==e.p.ExpandColumn&&!0===e.p.treeGrid)j=a("td:eq("+m+")",e.rows[n]).text();else{try{j=a.unformat.call(e,a("td:eq("+m+")",e.rows[n]),{rowId:d,colModel:this},m)}catch(r){j=this.edittype&&"textarea"==this.edittype?a("td:eq("+m+")",
+e.rows[n]).text():a("td:eq("+m+")",e.rows[n]).html()}if(!j||"&nbsp;"==j||"&#160;"==j||1==j.length&&160==j.charCodeAt(0))j=""}var v=a.extend({},this.editoptions||{},{id:i,name:i}),s=a.extend({},{elmprefix:"",elmsuffix:"",rowabove:!1,rowcontent:""},this.formoptions||{}),t=parseInt(s.rowpos,10)||k+1,y=parseInt(2*(parseInt(s.colpos,10)||1),10);"_empty"==d&&v.defaultValue&&(j=a.isFunction(v.defaultValue)?v.defaultValue.call(b):v.defaultValue);this.edittype||(this.edittype="text");b.p.autoencode&&(j=a.jgrid.htmlDecode(j));
+l=a.jgrid.createEl.call(b,this.edittype,v,j,!1,a.extend({},a.jgrid.ajaxOptions,e.p.ajaxSelectOptions||{}));""===j&&"checkbox"==this.edittype&&(j=a(l).attr("offval"));""===j&&"select"==this.edittype&&(j=a("option:eq(0)",l).text());if(c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate)c[b.p.id]._savedData[i]=j;a(l).addClass("FormElement");("text"==this.edittype||"textarea"==this.edittype)&&a(l).addClass("ui-widget-content ui-corner-all");g=a(h).find("tr[rowpos="+t+"]");s.rowabove&&(v=a("<tr><td class='contentinfo' colspan='"+
+2*q+"'>"+s.rowcontent+"</td></tr>"),a(h).append(v),v[0].rp=t);0===g.length&&(g=a("<tr "+o+" rowpos='"+t+"'></tr>").addClass("FormData").attr("id","tr_"+i),a(g).append(u),a(h).append(g),g[0].rp=t);a("td:eq("+(y-2)+")",g[0]).html("undefined"===typeof s.label?e.p.colNames[m]:s.label);a("td:eq("+(y-1)+")",g[0]).append(s.elmprefix).append(l).append(s.elmsuffix);p[k]=m;k++}});if(0<k&&(m=a("<tr class='FormData' style='display:none'><td class='CaptionTD'></td><td colspan='"+(2*q-1)+"' class='DataTD'><input class='FormElement' id='id_g' type='text' name='"+
+e.p.id+"_id' value='"+d+"'/></td></tr>"),m[0].rp=k+999,a(h).append(m),c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate))c[b.p.id]._savedData[e.p.id+"_id"]=d;return p}function r(d,e,h){var i,q=0,g,f,k,o,l;if(c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate)c[b.p.id]._savedData={},c[b.p.id]._savedData[e.p.id+"_id"]=d;var m=e.p.colModel;if("_empty"==d)a(m).each(function(){i=this.name;k=a.extend({},this.editoptions||{});if((f=a("#"+a.jgrid.jqID(i),"#"+h))&&f.length&&null!==f[0])if(o="",k.defaultValue?
+(o=a.isFunction(k.defaultValue)?k.defaultValue.call(b):k.defaultValue,"checkbox"==f[0].type?(l=o.toLowerCase(),0>l.search(/(false|0|no|off|undefined)/i)&&""!==l?(f[0].checked=!0,f[0].defaultChecked=!0,f[0].value=o):(f[0].checked=!1,f[0].defaultChecked=!1)):f.val(o)):"checkbox"==f[0].type?(f[0].checked=!1,f[0].defaultChecked=!1,o=a(f).attr("offval")):f[0].type&&"select"==f[0].type.substr(0,6)?f[0].selectedIndex=0:f.val(o),!0===c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate)c[b.p.id]._savedData[i]=
+o}),a("#id_g","#"+h).val(d);else{var n=a(e).jqGrid("getInd",d,!0);n&&(a('td[role="gridcell"]',n).each(function(f){i=m[f].name;if("cb"!==i&&"subgrid"!==i&&"rn"!==i&&!0===m[f].editable){if(i==e.p.ExpandColumn&&!0===e.p.treeGrid)g=a(this).text();else try{g=a.unformat.call(e,a(this),{rowId:d,colModel:m[f]},f)}catch(j){g="textarea"==m[f].edittype?a(this).text():a(this).html()}b.p.autoencode&&(g=a.jgrid.htmlDecode(g));if(!0===c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate)c[b.p.id]._savedData[i]=g;i=
+a.jgrid.jqID(i);switch(m[f].edittype){case "password":case "text":case "button":case "image":case "textarea":if("&nbsp;"==g||"&#160;"==g||1==g.length&&160==g.charCodeAt(0))g="";a("#"+i,"#"+h).val(g);break;case "select":var k=g.split(","),k=a.map(k,function(b){return a.trim(b)});a("#"+i+" option","#"+h).each(function(){this.selected=!m[f].editoptions.multiple&&(a.trim(g)==a.trim(a(this).text())||k[0]==a.trim(a(this).text())||k[0]==a.trim(a(this).val()))?!0:m[f].editoptions.multiple?-1<a.inArray(a.trim(a(this).text()),
+k)||-1<a.inArray(a.trim(a(this).val()),k)?!0:!1:!1});break;case "checkbox":g+="";m[f].editoptions&&m[f].editoptions.value?m[f].editoptions.value.split(":")[0]==g?(a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("checked",!0),a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("defaultChecked",!0)):(a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("checked",!1),a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("defaultChecked",!1)):(g=g.toLowerCase(),0>g.search(/(false|0|no|off|undefined)/i)&&""!==g?(a("#"+i,"#"+h)[b.p.useProp?
+"prop":"attr"]("checked",!0),a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("defaultChecked",!0)):(a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("checked",!1),a("#"+i,"#"+h)[b.p.useProp?"prop":"attr"]("defaultChecked",!1)));break;case "custom":try{if(m[f].editoptions&&a.isFunction(m[f].editoptions.custom_value))m[f].editoptions.custom_value.call(b,a("#"+i,"#"+h),"set",g);else throw"e1";}catch(o){"e1"==o?a.jgrid.info_dialog(jQuery.jgrid.errors.errcap,"function 'custom_value' "+a.jgrid.edit.msg.nodefined,jQuery.jgrid.edit.bClose):
+a.jgrid.info_dialog(jQuery.jgrid.errors.errcap,o.message,jQuery.jgrid.edit.bClose)}}q++}}),0<q&&a("#id_g",j).val(d))}}function t(){a.each(b.p.colModel,function(a,b){b.editoptions&&!0===b.editoptions.NullIfEmpty&&i.hasOwnProperty(b.name)&&""===i[b.name]&&(i[b.name]="null")})}function s(){var e,f=[!0,"",""],g={},q=b.p.prmNames,k,l,n,p,v,u=a(b).triggerHandler("jqGridAddEditBeforeCheckValues",[a("#"+h),z]);u&&"object"===typeof u&&(i=u);a.isFunction(c[b.p.id].beforeCheckValues)&&(u=c[b.p.id].beforeCheckValues.call(b,
+i,a("#"+h),"_empty"==i[b.p.id+"_id"]?q.addoper:q.editoper))&&"object"===typeof u&&(i=u);for(n in i)if(i.hasOwnProperty(n)&&(f=a.jgrid.checkValues.call(b,i[n],n,b),!1===f[0]))break;t();f[0]&&(g=a(b).triggerHandler("jqGridAddEditClickSubmit",[c[b.p.id],i,z]),void 0===g&&a.isFunction(c[b.p.id].onclickSubmit)&&(g=c[b.p.id].onclickSubmit.call(b,c[b.p.id],i)||{}),f=a(b).triggerHandler("jqGridAddEditBeforeSubmit",[i,a("#"+h),z]),void 0===f&&(f=[!0,"",""]),f[0]&&a.isFunction(c[b.p.id].beforeSubmit)&&(f=c[b.p.id].beforeSubmit.call(b,
+i,a("#"+h))));if(f[0]&&!c[b.p.id].processing){c[b.p.id].processing=!0;a("#sData",j+"_2").addClass("ui-state-active");l=q.oper;k=q.id;i[l]="_empty"==a.trim(i[b.p.id+"_id"])?q.addoper:q.editoper;i[l]!=q.addoper?i[k]=i[b.p.id+"_id"]:void 0===i[k]&&(i[k]=i[b.p.id+"_id"]);delete i[b.p.id+"_id"];i=a.extend(i,c[b.p.id].editData,g);if(!0===b.p.treeGrid)for(v in i[l]==q.addoper&&(p=a(b).jqGrid("getGridParam","selrow"),i["adjacency"==b.p.treeGridModel?b.p.treeReader.parent_id_field:"parent_id"]=p),b.p.treeReader)b.p.treeReader.hasOwnProperty(v)&&
+(g=b.p.treeReader[v],i.hasOwnProperty(g)&&!(i[l]==q.addoper&&"parent_id_field"===v)&&delete i[g]);i[k]=a.jgrid.stripPref(b.p.idPrefix,i[k]);v=a.extend({url:c[b.p.id].url?c[b.p.id].url:a(b).jqGrid("getGridParam","editurl"),type:c[b.p.id].mtype,data:a.isFunction(c[b.p.id].serializeEditData)?c[b.p.id].serializeEditData.call(b,i):i,complete:function(g,n){i[k]=b.p.idPrefix+i[k];if(n!="success"){f[0]=false;f[1]=a(b).triggerHandler("jqGridAddEditErrorTextFormat",[g,z]);f[1]=a.isFunction(c[b.p.id].errorTextFormat)?
+c[b.p.id].errorTextFormat.call(b,g):n+" Status: '"+g.statusText+"'. Error code: "+g.status}else{f=a(b).triggerHandler("jqGridAddEditAfterSubmit",[g,i,z]);f===void 0&&(f=[true,"",""]);f[0]&&a.isFunction(c[b.p.id].afterSubmit)&&(f=c[b.p.id].afterSubmit.call(b,g,i))}if(f[0]===false){a("#FormError>td",j).html(f[1]);a("#FormError",j).show()}else{a.each(b.p.colModel,function(){if(B[this.name]&&this.formatter&&this.formatter=="select")try{delete B[this.name]}catch(a){}});i=a.extend(i,B);b.p.autoencode&&
+a.each(i,function(b,d){i[b]=a.jgrid.htmlDecode(d)});if(i[l]==q.addoper){f[2]||(f[2]=a.jgrid.randId());i[k]=f[2];if(c[b.p.id].closeAfterAdd){if(c[b.p.id].reloadAfterSubmit)a(b).trigger("reloadGrid");else if(b.p.treeGrid===true)a(b).jqGrid("addChildNode",f[2],p,i);else{a(b).jqGrid("addRowData",f[2],i,d.addedrow);a(b).jqGrid("setSelection",f[2])}a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose})}else if(c[b.p.id].clearAfterAdd){c[b.p.id].reloadAfterSubmit?
+a(b).trigger("reloadGrid"):b.p.treeGrid===true?a(b).jqGrid("addChildNode",f[2],p,i):a(b).jqGrid("addRowData",f[2],i,d.addedrow);r("_empty",b,h)}else c[b.p.id].reloadAfterSubmit?a(b).trigger("reloadGrid"):b.p.treeGrid===true?a(b).jqGrid("addChildNode",f[2],p,i):a(b).jqGrid("addRowData",f[2],i,d.addedrow)}else{if(c[b.p.id].reloadAfterSubmit){a(b).trigger("reloadGrid");c[b.p.id].closeAfterEdit||setTimeout(function(){a(b).jqGrid("setSelection",i[k])},1E3)}else b.p.treeGrid===true?a(b).jqGrid("setTreeRow",
+i[k],i):a(b).jqGrid("setRowData",i[k],i);c[b.p.id].closeAfterEdit&&a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose})}if(a.isFunction(c[b.p.id].afterComplete)){e=g;setTimeout(function(){a(b).triggerHandler("jqGridAddEditAfterComplete",[e,i,a("#"+h),z]);c[b.p.id].afterComplete.call(b,e,i,a("#"+h));e=null},500)}if(c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate){a("#"+h).data("disabled",false);if(c[b.p.id]._savedData[b.p.id+"_id"]!=
+"_empty")for(var v in c[b.p.id]._savedData)i[v]&&(c[b.p.id]._savedData[v]=i[v])}}c[b.p.id].processing=false;a("#sData",j+"_2").removeClass("ui-state-active");try{a(":input:visible","#"+h)[0].focus()}catch(u){}}},a.jgrid.ajaxOptions,c[b.p.id].ajaxEditOptions);!v.url&&!c[b.p.id].useDataProxy&&(a.isFunction(b.p.dataProxy)?c[b.p.id].useDataProxy=!0:(f[0]=!1,f[1]+=" "+a.jgrid.errors.nourl));f[0]&&(c[b.p.id].useDataProxy?(g=b.p.dataProxy.call(b,v,"set_"+b.p.id),"undefined"==typeof g&&(g=[!0,""]),!1===g[0]?
+(f[0]=!1,f[1]=g[1]||"Error deleting the selected row!"):(v.data.oper==q.addoper&&c[b.p.id].closeAfterAdd&&a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose}),v.data.oper==q.editoper&&c[b.p.id].closeAfterEdit&&a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose}))):a.ajax(v))}!1===f[0]&&(a("#FormError>td",j).html(f[1]),a("#FormError",j).show())}function p(a,b){var d=!1,
+c;for(c in a)if(a[c]!=b[c]){d=!0;break}return d}function g(){var d=!0;a("#FormError",j).hide();if(c[b.p.id].checkOnUpdate&&(i={},B={},e(),F=a.extend({},i,B),M=p(F,c[b.p.id]._savedData)))a("#"+h).data("disabled",!0),a(".confirm","#"+o.themodal).show(),d=!1;return d}function f(){if("_empty"!==u&&"undefined"!==typeof b.p.savedRow&&0<b.p.savedRow.length&&a.isFunction(a.fn.jqGrid.restoreRow))for(var d=0;d<b.p.savedRow.length;d++)if(b.p.savedRow[d].id==u){a(b).jqGrid("restoreRow",u);break}}function n(b,
+d){0===b?a("#pData",j+"_2").addClass("ui-state-disabled"):a("#pData",j+"_2").removeClass("ui-state-disabled");b==d?a("#nData",j+"_2").addClass("ui-state-disabled"):a("#nData",j+"_2").removeClass("ui-state-disabled")}function w(){var d=a(b).jqGrid("getDataIDs"),c=a("#id_g",j).val();return[a.inArray(c,d),d]}var b=this;if(b.grid&&u){var m=b.p.id,h="FrmGrid_"+m,k="TblGrid_"+m,j="#"+a.jgrid.jqID(k),o={themodal:"editmod"+m,modalhead:"edithd"+m,modalcontent:"editcnt"+m,scrollelm:h},y=a.isFunction(c[b.p.id].beforeShowForm)?
+c[b.p.id].beforeShowForm:!1,A=a.isFunction(c[b.p.id].afterShowForm)?c[b.p.id].afterShowForm:!1,x=a.isFunction(c[b.p.id].beforeInitData)?c[b.p.id].beforeInitData:!1,E=a.isFunction(c[b.p.id].onInitializeForm)?c[b.p.id].onInitializeForm:!1,q=!0,v=1,H=0,i,B,F,M,z,h=a.jgrid.jqID(h);"new"===u?(u="_empty",z="add",d.caption=c[b.p.id].addCaption):(d.caption=c[b.p.id].editCaption,z="edit");!0===d.recreateForm&&null!==a("#"+a.jgrid.jqID(o.themodal)).html()&&a("#"+a.jgrid.jqID(o.themodal)).remove();var I=!0;
+d.checkOnUpdate&&(d.jqModal&&!d.modal)&&(I=!1);if(null!==a("#"+a.jgrid.jqID(o.themodal)).html()){q=a(b).triggerHandler("jqGridAddEditBeforeInitData",[a("#"+a.jgrid.jqID(h))]);"undefined"==typeof q&&(q=!0);q&&x&&(q=x.call(b,a("#"+h)));if(!1===q)return;f();a(".ui-jqdialog-title","#"+a.jgrid.jqID(o.modalhead)).html(d.caption);a("#FormError",j).hide();c[b.p.id].topinfo?(a(".topinfo",j).html(c[b.p.id].topinfo),a(".tinfo",j).show()):a(".tinfo",j).hide();c[b.p.id].bottominfo?(a(".bottominfo",j+"_2").html(c[b.p.id].bottominfo),
+a(".binfo",j+"_2").show()):a(".binfo",j+"_2").hide();r(u,b,h);"_empty"==u||!c[b.p.id].viewPagerButtons?a("#pData, #nData",j+"_2").hide():a("#pData, #nData",j+"_2").show();!0===c[b.p.id].processing&&(c[b.p.id].processing=!1,a("#sData",j+"_2").removeClass("ui-state-active"));!0===a("#"+h).data("disabled")&&(a(".confirm","#"+a.jgrid.jqID(o.themodal)).hide(),a("#"+h).data("disabled",!1));a(b).triggerHandler("jqGridAddEditBeforeShowForm",[a("#"+h),z]);y&&y.call(b,a("#"+h));a("#"+a.jgrid.jqID(o.themodal)).data("onClose",
+c[b.p.id].onClose);a.jgrid.viewModal("#"+a.jgrid.jqID(o.themodal),{gbox:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,jqM:!1,overlay:d.overlay,modal:d.modal});I||a(".jqmOverlay").click(function(){if(!g())return false;a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose});return false});a(b).triggerHandler("jqGridAddEditAfterShowForm",[a("#"+h),z]);A&&A.call(b,a("#"+h))}else{var G=isNaN(d.dataheight)?d.dataheight:d.dataheight+"px",G=a("<form name='FormPost' id='"+
+h+"' class='FormGrid' onSubmit='return false;' style='width:100%;overflow:auto;position:relative;height:"+G+";'></form>").data("disabled",!1),C=a("<table id='"+k+"' class='EditTable' cellspacing='0' cellpadding='0' border='0'><tbody></tbody></table>"),q=a(b).triggerHandler("jqGridAddEditBeforeInitData",[a("#"+h),z]);"undefined"==typeof q&&(q=!0);q&&x&&(q=x.call(b,a("#"+h)));if(!1===q)return;f();a(b.p.colModel).each(function(){var a=this.formoptions;v=Math.max(v,a?a.colpos||0:0);H=Math.max(H,a?a.rowpos||
+0:0)});a(G).append(C);x=a("<tr id='FormError' style='display:none'><td class='ui-state-error' colspan='"+2*v+"'></td></tr>");x[0].rp=0;a(C).append(x);x=a("<tr style='display:none' class='tinfo'><td class='topinfo' colspan='"+2*v+"'>"+c[b.p.id].topinfo+"</td></tr>");x[0].rp=0;a(C).append(x);var q=(x="rtl"==b.p.direction?!0:!1)?"nData":"pData",D=x?"pData":"nData";l(u,b,C,v);var q="<a href='javascript:void(0)' id='"+q+"' class='fm-button ui-state-default ui-corner-left'><span class='ui-icon ui-icon-triangle-1-w'></span></a>",
+D="<a href='javascript:void(0)' id='"+D+"' class='fm-button ui-state-default ui-corner-right'><span class='ui-icon ui-icon-triangle-1-e'></span></a>",J="<a href='javascript:void(0)' id='sData' class='fm-button ui-state-default ui-corner-all'>"+d.bSubmit+"</a>",K="<a href='javascript:void(0)' id='cData' class='fm-button ui-state-default ui-corner-all'>"+d.bCancel+"</a>",k="<table border='0' cellspacing='0' cellpadding='0' class='EditTable' id='"+k+"_2'><tbody><tr><td colspan='2'><hr class='ui-widget-content' style='margin:1px'/></td></tr><tr id='Act_Buttons'><td class='navButton'>"+
+(x?D+q:q+D)+"</td><td class='EditButton'>"+J+K+"</td></tr>"+("<tr style='display:none' class='binfo'><td class='bottominfo' colspan='2'>"+c[b.p.id].bottominfo+"</td></tr>"),k=k+"</tbody></table>";if(0<H){var L=[];a.each(a(C)[0].rows,function(a,b){L[a]=b});L.sort(function(a,b){return a.rp>b.rp?1:a.rp<b.rp?-1:0});a.each(L,function(b,d){a("tbody",C).append(d)})}d.gbox="#gbox_"+a.jgrid.jqID(m);var N=!1;!0===d.closeOnEscape&&(d.closeOnEscape=!1,N=!0);k=a("<span></span>").append(G).append(k);a.jgrid.createModal(o,
+k,d,"#gview_"+a.jgrid.jqID(b.p.id),a("#gbox_"+a.jgrid.jqID(b.p.id))[0]);x&&(a("#pData, #nData",j+"_2").css("float","right"),a(".EditButton",j+"_2").css("text-align","left"));c[b.p.id].topinfo&&a(".tinfo",j).show();c[b.p.id].bottominfo&&a(".binfo",j+"_2").show();k=k=null;a("#"+a.jgrid.jqID(o.themodal)).keydown(function(e){var f=e.target;if(a("#"+h).data("disabled")===true)return false;if(c[b.p.id].savekey[0]===true&&e.which==c[b.p.id].savekey[1]&&f.tagName!="TEXTAREA"){a("#sData",j+"_2").trigger("click");
+return false}if(e.which===27){if(!g())return false;N&&a.jgrid.hideModal(this,{gb:d.gbox,jqm:d.jqModal,onClose:c[b.p.id].onClose});return false}if(c[b.p.id].navkeys[0]===true){if(a("#id_g",j).val()=="_empty")return true;if(e.which==c[b.p.id].navkeys[1]){a("#pData",j+"_2").trigger("click");return false}if(e.which==c[b.p.id].navkeys[2]){a("#nData",j+"_2").trigger("click");return false}}});d.checkOnUpdate&&(a("a.ui-jqdialog-titlebar-close span","#"+a.jgrid.jqID(o.themodal)).removeClass("jqmClose"),a("a.ui-jqdialog-titlebar-close",
+"#"+a.jgrid.jqID(o.themodal)).unbind("click").click(function(){if(!g())return false;a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose});return false}));d.saveicon=a.extend([!0,"left","ui-icon-disk"],d.saveicon);d.closeicon=a.extend([!0,"left","ui-icon-close"],d.closeicon);!0===d.saveicon[0]&&a("#sData",j+"_2").addClass("right"==d.saveicon[1]?"fm-button-icon-right":"fm-button-icon-left").append("<span class='ui-icon "+d.saveicon[2]+
+"'></span>");!0===d.closeicon[0]&&a("#cData",j+"_2").addClass("right"==d.closeicon[1]?"fm-button-icon-right":"fm-button-icon-left").append("<span class='ui-icon "+d.closeicon[2]+"'></span>");if(c[b.p.id].checkOnSubmit||c[b.p.id].checkOnUpdate)J="<a href='javascript:void(0)' id='sNew' class='fm-button ui-state-default ui-corner-all' style='z-index:1002'>"+d.bYes+"</a>",D="<a href='javascript:void(0)' id='nNew' class='fm-button ui-state-default ui-corner-all' style='z-index:1002'>"+d.bNo+"</a>",K="<a href='javascript:void(0)' id='cNew' class='fm-button ui-state-default ui-corner-all' style='z-index:1002'>"+
+d.bExit+"</a>",k=d.zIndex||999,k++,a("<div class='ui-widget-overlay jqgrid-overlay confirm' style='z-index:"+k+";display:none;'>&#160;"+(a.browser.msie&&6==a.browser.version?'<iframe style="display:block;position:absolute;z-index:-1;filter:Alpha(Opacity=\'0\');" src="javascript:false;"></iframe>':"")+"</div><div class='confirm ui-widget-content ui-jqconfirm' style='z-index:"+(k+1)+"'>"+d.saveData+"<br/><br/>"+J+D+K+"</div>").insertAfter("#"+h),a("#sNew","#"+a.jgrid.jqID(o.themodal)).click(function(){s();
+a("#"+h).data("disabled",false);a(".confirm","#"+a.jgrid.jqID(o.themodal)).hide();return false}),a("#nNew","#"+a.jgrid.jqID(o.themodal)).click(function(){a(".confirm","#"+a.jgrid.jqID(o.themodal)).hide();a("#"+h).data("disabled",false);setTimeout(function(){a(":input","#"+h)[0].focus()},0);return false}),a("#cNew","#"+a.jgrid.jqID(o.themodal)).click(function(){a(".confirm","#"+a.jgrid.jqID(o.themodal)).hide();a("#"+h).data("disabled",false);a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+
+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose});return false});a(b).triggerHandler("jqGridAddEditInitializeForm",[a("#"+h),z]);E&&E.call(b,a("#"+h));"_empty"==u||!c[b.p.id].viewPagerButtons?a("#pData,#nData",j+"_2").hide():a("#pData,#nData",j+"_2").show();a(b).triggerHandler("jqGridAddEditBeforeShowForm",[a("#"+h),z]);y&&y.call(b,a("#"+h));a("#"+a.jgrid.jqID(o.themodal)).data("onClose",c[b.p.id].onClose);a.jgrid.viewModal("#"+a.jgrid.jqID(o.themodal),{gbox:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,
+overlay:d.overlay,modal:d.modal});I||a(".jqmOverlay").click(function(){if(!g())return false;a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose});return false});a(b).triggerHandler("jqGridAddEditAfterShowForm",[a("#"+h),z]);A&&A.call(b,a("#"+h));a(".fm-button","#"+a.jgrid.jqID(o.themodal)).hover(function(){a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")});a("#sData",j+"_2").click(function(){i={};B=
+{};a("#FormError",j).hide();e();if(i[b.p.id+"_id"]=="_empty")s();else if(d.checkOnSubmit===true){F=a.extend({},i,B);if(M=p(F,c[b.p.id]._savedData)){a("#"+h).data("disabled",true);a(".confirm","#"+a.jgrid.jqID(o.themodal)).show()}else s()}else s();return false});a("#cData",j+"_2").click(function(){if(!g())return false;a.jgrid.hideModal("#"+a.jgrid.jqID(o.themodal),{gb:"#gbox_"+a.jgrid.jqID(m),jqm:d.jqModal,onClose:c[b.p.id].onClose});return false});a("#nData",j+"_2").click(function(){if(!g())return false;
+a("#FormError",j).hide();var c=w();c[0]=parseInt(c[0],10);if(c[0]!=-1&&c[1][c[0]+1]){a(b).triggerHandler("jqGridAddEditClickPgButtons",["next",a("#"+h),c[1][c[0]]]);a.isFunction(d.onclickPgButtons)&&d.onclickPgButtons.call(b,"next",a("#"+h),c[1][c[0]]);r(c[1][c[0]+1],b,h);a(b).jqGrid("setSelection",c[1][c[0]+1]);a(b).triggerHandler("jqGridAddEditAfterClickPgButtons",["next",a("#"+h),c[1][c[0]]]);a.isFunction(d.afterclickPgButtons)&&d.afterclickPgButtons.call(b,"next",a("#"+h),c[1][c[0]+1]);n(c[0]+
+1,c[1].length-1)}return false});a("#pData",j+"_2").click(function(){if(!g())return false;a("#FormError",j).hide();var c=w();if(c[0]!=-1&&c[1][c[0]-1]){a(b).triggerHandler("jqGridAddEditClickPgButtons",["prev",a("#"+h),c[1][c[0]]]);a.isFunction(d.onclickPgButtons)&&d.onclickPgButtons.call(b,"prev",a("#"+h),c[1][c[0]]);r(c[1][c[0]-1],b,h);a(b).jqGrid("setSelection",c[1][c[0]-1]);a(b).triggerHandler("jqGridAddEditAfterClickPgButtons",["prev",a("#"+h),c[1][c[0]]]);a.isFunction(d.afterclickPgButtons)&&
+d.afterclickPgButtons.call(b,"prev",a("#"+h),c[1][c[0]-1]);n(c[0]-1,c[1].length-1)}return false})}y=w();n(y[0],y[1].length-1)}})},viewGridRow:function(c,d){d=a.extend({top:0,left:0,width:0,height:"auto",dataheight:"auto",modal:!1,overlay:30,drag:!0,resize:!0,jqModal:!0,closeOnEscape:!1,labelswidth:"30%",closeicon:[],navkeys:[!1,38,40],onClose:null,beforeShowForm:null,beforeInitData:null,viewPagerButtons:!0},a.jgrid.view,d||{});return this.each(function(){function e(){(!0===d.closeOnEscape||!0===d.navkeys[0])&&
+setTimeout(function(){a(".ui-jqdialog-titlebar-close","#"+a.jgrid.jqID(m.modalhead)).focus()},0)}function l(b,c,e,f){for(var g,h,k,j=0,o,m,l=[],n=!1,p="<td class='CaptionTD form-view-label ui-widget-content' width='"+d.labelswidth+"'>&#160;</td><td class='DataTD form-view-data ui-helper-reset ui-widget-content'>&#160;</td>",u="",s=["integer","number","currency"],r=0,t=0,y,x,w,A=1;A<=f;A++)u+=1==A?p:"<td class='CaptionTD form-view-label ui-widget-content'>&#160;</td><td class='DataTD form-view-data ui-widget-content'>&#160;</td>";
+a(c.p.colModel).each(function(){h=this.editrules&&!0===this.editrules.edithidden?!1:!0===this.hidden?!0:!1;!h&&"right"===this.align&&(this.formatter&&-1!==a.inArray(this.formatter,s)?r=Math.max(r,parseInt(this.width,10)):t=Math.max(t,parseInt(this.width,10)))});y=0!==r?r:0!==t?t:0;n=a(c).jqGrid("getInd",b);a(c.p.colModel).each(function(b){g=this.name;x=!1;m=(h=this.editrules&&!0===this.editrules.edithidden?!1:!0===this.hidden?!0:!1)?"style='display:none'":"";w="boolean"!=typeof this.viewable?!0:this.viewable;
+if("cb"!==g&&"subgrid"!==g&&"rn"!==g&&w){o=!1===n?"":g==c.p.ExpandColumn&&!0===c.p.treeGrid?a("td:eq("+b+")",c.rows[n]).text():a("td:eq("+b+")",c.rows[n]).html();x="right"===this.align&&0!==y?!0:!1;a.extend({},this.editoptions||{},{id:g,name:g});var d=a.extend({},{rowabove:!1,rowcontent:""},this.formoptions||{}),q=parseInt(d.rowpos,10)||j+1,p=parseInt(2*(parseInt(d.colpos,10)||1),10);if(d.rowabove){var r=a("<tr><td class='contentinfo' colspan='"+2*f+"'>"+d.rowcontent+"</td></tr>");a(e).append(r);
+r[0].rp=q}k=a(e).find("tr[rowpos="+q+"]");0===k.length&&(k=a("<tr "+m+" rowpos='"+q+"'></tr>").addClass("FormData").attr("id","trv_"+g),a(k).append(u),a(e).append(k),k[0].rp=q);a("td:eq("+(p-2)+")",k[0]).html("<b>"+("undefined"===typeof d.label?c.p.colNames[b]:d.label)+"</b>");a("td:eq("+(p-1)+")",k[0]).append("<span>"+o+"</span>").attr("id","v_"+g);x&&a("td:eq("+(p-1)+") span",k[0]).css({"text-align":"right",width:y+"px"});l[j]=b;j++}});0<j&&(b=a("<tr class='FormData' style='display:none'><td class='CaptionTD'></td><td colspan='"+
+(2*f-1)+"' class='DataTD'><input class='FormElement' id='id_g' type='text' name='id' value='"+b+"'/></td></tr>"),b[0].rp=j+99,a(e).append(b));return l}function r(b,c){var d,e,f=0,g,h;if(h=a(c).jqGrid("getInd",b,!0))a("td",h).each(function(b){d=c.p.colModel[b].name;e=c.p.colModel[b].editrules&&!0===c.p.colModel[b].editrules.edithidden?!1:!0===c.p.colModel[b].hidden?!0:!1;"cb"!==d&&("subgrid"!==d&&"rn"!==d)&&(g=d==c.p.ExpandColumn&&!0===c.p.treeGrid?a(this).text():a(this).html(),a.extend({},c.p.colModel[b].editoptions||
+{}),d=a.jgrid.jqID("v_"+d),a("#"+d+" span","#"+n).html(g),e&&a("#"+d,"#"+n).parents("tr:first").hide(),f++)}),0<f&&a("#id_g","#"+n).val(b)}function t(b,c){0===b?a("#pData","#"+n+"_2").addClass("ui-state-disabled"):a("#pData","#"+n+"_2").removeClass("ui-state-disabled");b==c?a("#nData","#"+n+"_2").addClass("ui-state-disabled"):a("#nData","#"+n+"_2").removeClass("ui-state-disabled")}function s(){var b=a(p).jqGrid("getDataIDs"),c=a("#id_g","#"+n).val();return[a.inArray(c,b),b]}var p=this;if(p.grid&&
+c){var g=p.p.id,f="ViewGrid_"+a.jgrid.jqID(g),n="ViewTbl_"+a.jgrid.jqID(g),w="ViewGrid_"+g,b="ViewTbl_"+g,m={themodal:"viewmod"+g,modalhead:"viewhd"+g,modalcontent:"viewcnt"+g,scrollelm:f},h=a.isFunction(d.beforeInitData)?d.beforeInitData:!1,k=!0,j=1,o=0;if(null!==a("#"+a.jgrid.jqID(m.themodal)).html()){h&&(k=h.call(p,a("#"+f)),"undefined"==typeof k&&(k=!0));if(!1===k)return;a(".ui-jqdialog-title","#"+a.jgrid.jqID(m.modalhead)).html(d.caption);a("#FormError","#"+n).hide();r(c,p);a.isFunction(d.beforeShowForm)&&
+d.beforeShowForm.call(p,a("#"+f));a.jgrid.viewModal("#"+a.jgrid.jqID(m.themodal),{gbox:"#gbox_"+a.jgrid.jqID(g),jqm:d.jqModal,jqM:!1,overlay:d.overlay,modal:d.modal});e()}else{var y=isNaN(d.dataheight)?d.dataheight:d.dataheight+"px",w=a("<form name='FormPost' id='"+w+"' class='FormGrid' style='width:100%;overflow:auto;position:relative;height:"+y+";'></form>"),A=a("<table id='"+b+"' class='EditTable' cellspacing='1' cellpadding='2' border='0' style='table-layout:fixed'><tbody></tbody></table>");h&&
+(k=h.call(p,a("#"+f)),"undefined"==typeof k&&(k=!0));if(!1===k)return;a(p.p.colModel).each(function(){var a=this.formoptions;j=Math.max(j,a?a.colpos||0:0);o=Math.max(o,a?a.rowpos||0:0)});a(w).append(A);l(c,p,A,j);b="rtl"==p.p.direction?!0:!1;h="<a href='javascript:void(0)' id='"+(b?"nData":"pData")+"' class='fm-button ui-state-default ui-corner-left'><span class='ui-icon ui-icon-triangle-1-w'></span></a>";k="<a href='javascript:void(0)' id='"+(b?"pData":"nData")+"' class='fm-button ui-state-default ui-corner-right'><span class='ui-icon ui-icon-triangle-1-e'></span></a>";
+y="<a href='javascript:void(0)' id='cData' class='fm-button ui-state-default ui-corner-all'>"+d.bClose+"</a>";if(0<o){var x=[];a.each(a(A)[0].rows,function(a,b){x[a]=b});x.sort(function(a,b){return a.rp>b.rp?1:a.rp<b.rp?-1:0});a.each(x,function(b,c){a("tbody",A).append(c)})}d.gbox="#gbox_"+a.jgrid.jqID(g);var E=!1;!0===d.closeOnEscape&&(d.closeOnEscape=!1,E=!0);w=a("<span></span>").append(w).append("<table border='0' class='EditTable' id='"+n+"_2'><tbody><tr id='Act_Buttons'><td class='navButton' width='"+
+d.labelswidth+"'>"+(b?k+h:h+k)+"</td><td class='EditButton'>"+y+"</td></tr></tbody></table>");a.jgrid.createModal(m,w,d,"#gview_"+a.jgrid.jqID(p.p.id),a("#gview_"+a.jgrid.jqID(p.p.id))[0]);b&&(a("#pData, #nData","#"+n+"_2").css("float","right"),a(".EditButton","#"+n+"_2").css("text-align","left"));d.viewPagerButtons||a("#pData, #nData","#"+n+"_2").hide();w=null;a("#"+m.themodal).keydown(function(b){if(b.which===27){E&&a.jgrid.hideModal(this,{gb:d.gbox,jqm:d.jqModal,onClose:d.onClose});return false}if(d.navkeys[0]===
+true){if(b.which===d.navkeys[1]){a("#pData","#"+n+"_2").trigger("click");return false}if(b.which===d.navkeys[2]){a("#nData","#"+n+"_2").trigger("click");return false}}});d.closeicon=a.extend([!0,"left","ui-icon-close"],d.closeicon);!0===d.closeicon[0]&&a("#cData","#"+n+"_2").addClass("right"==d.closeicon[1]?"fm-button-icon-right":"fm-button-icon-left").append("<span class='ui-icon "+d.closeicon[2]+"'></span>");a.isFunction(d.beforeShowForm)&&d.beforeShowForm.call(p,a("#"+f));a.jgrid.viewModal("#"+
+a.jgrid.jqID(m.themodal),{gbox:"#gbox_"+a.jgrid.jqID(g),jqm:d.jqModal,modal:d.modal});a(".fm-button:not(.ui-state-disabled)","#"+n+"_2").hover(function(){a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")});e();a("#cData","#"+n+"_2").click(function(){a.jgrid.hideModal("#"+a.jgrid.jqID(m.themodal),{gb:"#gbox_"+a.jgrid.jqID(g),jqm:d.jqModal,onClose:d.onClose});return false});a("#nData","#"+n+"_2").click(function(){a("#FormError","#"+n).hide();var b=s();b[0]=parseInt(b[0],
+10);if(b[0]!=-1&&b[1][b[0]+1]){a.isFunction(d.onclickPgButtons)&&d.onclickPgButtons.call(p,"next",a("#"+f),b[1][b[0]]);r(b[1][b[0]+1],p);a(p).jqGrid("setSelection",b[1][b[0]+1]);a.isFunction(d.afterclickPgButtons)&&d.afterclickPgButtons.call(p,"next",a("#"+f),b[1][b[0]+1]);t(b[0]+1,b[1].length-1)}e();return false});a("#pData","#"+n+"_2").click(function(){a("#FormError","#"+n).hide();var b=s();if(b[0]!=-1&&b[1][b[0]-1]){a.isFunction(d.onclickPgButtons)&&d.onclickPgButtons.call(p,"prev",a("#"+f),b[1][b[0]]);
+r(b[1][b[0]-1],p);a(p).jqGrid("setSelection",b[1][b[0]-1]);a.isFunction(d.afterclickPgButtons)&&d.afterclickPgButtons.call(p,"prev",a("#"+f),b[1][b[0]-1]);t(b[0]-1,b[1].length-1)}e();return false})}w=s();t(w[0],w[1].length-1)}})},delGridRow:function(u,d){d=a.extend({top:0,left:0,width:240,height:"auto",dataheight:"auto",modal:!1,overlay:30,drag:!0,resize:!0,url:"",mtype:"POST",reloadAfterSubmit:!0,beforeShowForm:null,beforeInitData:null,afterShowForm:null,beforeSubmit:null,onclickSubmit:null,afterSubmit:null,
+jqModal:!0,closeOnEscape:!1,delData:{},delicon:[],cancelicon:[],onClose:null,ajaxDelOptions:{},processing:!1,serializeDelData:null,useDataProxy:!1},a.jgrid.del,d||{});c[a(this)[0].p.id]=d;return this.each(function(){var e=this;if(e.grid&&u){var l=a.isFunction(c[e.p.id].beforeShowForm),r=a.isFunction(c[e.p.id].afterShowForm),t=a.isFunction(c[e.p.id].beforeInitData)?c[e.p.id].beforeInitData:!1,s=e.p.id,p={},g=!0,f="DelTbl_"+a.jgrid.jqID(s),n,w,b,m,h="DelTbl_"+s,k={themodal:"delmod"+s,modalhead:"delhd"+
+s,modalcontent:"delcnt"+s,scrollelm:f};jQuery.isArray(u)&&(u=u.join());if(null!==a("#"+a.jgrid.jqID(k.themodal)).html()){t&&(g=t.call(e,a("#"+f)),"undefined"==typeof g&&(g=!0));if(!1===g)return;a("#DelData>td","#"+f).text(u);a("#DelError","#"+f).hide();!0===c[e.p.id].processing&&(c[e.p.id].processing=!1,a("#dData","#"+f).removeClass("ui-state-active"));l&&c[e.p.id].beforeShowForm.call(e,a("#"+f));a.jgrid.viewModal("#"+a.jgrid.jqID(k.themodal),{gbox:"#gbox_"+a.jgrid.jqID(s),jqm:c[e.p.id].jqModal,jqM:!1,
+overlay:c[e.p.id].overlay,modal:c[e.p.id].modal})}else{var j=isNaN(c[e.p.id].dataheight)?c[e.p.id].dataheight:c[e.p.id].dataheight+"px",h="<div id='"+h+"' class='formdata' style='width:100%;overflow:auto;position:relative;height:"+j+";'><table class='DelTable'><tbody><tr id='DelError' style='display:none'><td class='ui-state-error'></td></tr>"+("<tr id='DelData' style='display:none'><td >"+u+"</td></tr>"),h=h+('<tr><td class="delmsg" style="white-space:pre;">'+c[e.p.id].msg+"</td></tr><tr><td >&#160;</td></tr>"),
+h=h+"</tbody></table></div>"+("<table cellspacing='0' cellpadding='0' border='0' class='EditTable' id='"+f+"_2'><tbody><tr><td><hr class='ui-widget-content' style='margin:1px'/></td></tr><tr><td class='DelButton EditButton'>"+("<a href='javascript:void(0)' id='dData' class='fm-button ui-state-default ui-corner-all'>"+d.bSubmit+"</a>")+"&#160;"+("<a href='javascript:void(0)' id='eData' class='fm-button ui-state-default ui-corner-all'>"+d.bCancel+"</a>")+"</td></tr></tbody></table>");d.gbox="#gbox_"+
+a.jgrid.jqID(s);a.jgrid.createModal(k,h,d,"#gview_"+a.jgrid.jqID(e.p.id),a("#gview_"+a.jgrid.jqID(e.p.id))[0]);t&&(g=t.call(e,a("#"+f)),"undefined"==typeof g&&(g=!0));if(!1===g)return;a(".fm-button","#"+f+"_2").hover(function(){a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")});d.delicon=a.extend([!0,"left","ui-icon-scissors"],c[e.p.id].delicon);d.cancelicon=a.extend([!0,"left","ui-icon-cancel"],c[e.p.id].cancelicon);!0===d.delicon[0]&&a("#dData","#"+f+"_2").addClass("right"==
+d.delicon[1]?"fm-button-icon-right":"fm-button-icon-left").append("<span class='ui-icon "+d.delicon[2]+"'></span>");!0===d.cancelicon[0]&&a("#eData","#"+f+"_2").addClass("right"==d.cancelicon[1]?"fm-button-icon-right":"fm-button-icon-left").append("<span class='ui-icon "+d.cancelicon[2]+"'></span>");a("#dData","#"+f+"_2").click(function(){var g=[true,""];p={};var h=a("#DelData>td","#"+f).text();a.isFunction(c[e.p.id].onclickSubmit)&&(p=c[e.p.id].onclickSubmit.call(e,c[e.p.id],h)||{});a.isFunction(c[e.p.id].beforeSubmit)&&
+(g=c[e.p.id].beforeSubmit.call(e,h));if(g[0]&&!c[e.p.id].processing){c[e.p.id].processing=true;b=e.p.prmNames;n=a.extend({},c[e.p.id].delData,p);m=b.oper;n[m]=b.deloper;w=b.id;h=(""+h).split(",");if(!h.length)return false;for(var j in h)h.hasOwnProperty(j)&&(h[j]=a.jgrid.stripPref(e.p.idPrefix,h[j]));n[w]=h.join();a(this).addClass("ui-state-active");j=a.extend({url:c[e.p.id].url?c[e.p.id].url:a(e).jqGrid("getGridParam","editurl"),type:c[e.p.id].mtype,data:a.isFunction(c[e.p.id].serializeDelData)?
+c[e.p.id].serializeDelData.call(e,n):n,complete:function(b,j){if(j!="success"){g[0]=false;g[1]=a.isFunction(c[e.p.id].errorTextFormat)?c[e.p.id].errorTextFormat.call(e,b):j+" Status: '"+b.statusText+"'. Error code: "+b.status}else a.isFunction(c[e.p.id].afterSubmit)&&(g=c[e.p.id].afterSubmit.call(e,b,n));if(g[0]===false){a("#DelError>td","#"+f).html(g[1]);a("#DelError","#"+f).show()}else{if(c[e.p.id].reloadAfterSubmit&&e.p.datatype!="local")a(e).trigger("reloadGrid");else{if(e.p.treeGrid===true)try{a(e).jqGrid("delTreeNode",
+e.p.idPrefix+h[0])}catch(m){}else for(var l=0;l<h.length;l++)a(e).jqGrid("delRowData",e.p.idPrefix+h[l]);e.p.selrow=null;e.p.selarrrow=[]}a.isFunction(c[e.p.id].afterComplete)&&setTimeout(function(){c[e.p.id].afterComplete.call(e,b,h)},500)}c[e.p.id].processing=false;a("#dData","#"+f+"_2").removeClass("ui-state-active");g[0]&&a.jgrid.hideModal("#"+a.jgrid.jqID(k.themodal),{gb:"#gbox_"+a.jgrid.jqID(s),jqm:d.jqModal,onClose:c[e.p.id].onClose})}},a.jgrid.ajaxOptions,c[e.p.id].ajaxDelOptions);if(!j.url&&
+!c[e.p.id].useDataProxy)if(a.isFunction(e.p.dataProxy))c[e.p.id].useDataProxy=true;else{g[0]=false;g[1]=g[1]+(" "+a.jgrid.errors.nourl)}if(g[0])if(c[e.p.id].useDataProxy){j=e.p.dataProxy.call(e,j,"del_"+e.p.id);typeof j=="undefined"&&(j=[true,""]);if(j[0]===false){g[0]=false;g[1]=j[1]||"Error deleting the selected row!"}else a.jgrid.hideModal("#"+a.jgrid.jqID(k.themodal),{gb:"#gbox_"+a.jgrid.jqID(s),jqm:d.jqModal,onClose:c[e.p.id].onClose})}else a.ajax(j)}if(g[0]===false){a("#DelError>td","#"+f).html(g[1]);
+a("#DelError","#"+f).show()}return false});a("#eData","#"+f+"_2").click(function(){a.jgrid.hideModal("#"+a.jgrid.jqID(k.themodal),{gb:"#gbox_"+a.jgrid.jqID(s),jqm:c[e.p.id].jqModal,onClose:c[e.p.id].onClose});return false});l&&c[e.p.id].beforeShowForm.call(e,a("#"+f));a.jgrid.viewModal("#"+a.jgrid.jqID(k.themodal),{gbox:"#gbox_"+a.jgrid.jqID(s),jqm:c[e.p.id].jqModal,overlay:c[e.p.id].overlay,modal:c[e.p.id].modal})}r&&c[e.p.id].afterShowForm.call(e,a("#"+f));!0===c[e.p.id].closeOnEscape&&setTimeout(function(){a(".ui-jqdialog-titlebar-close",
+"#"+a.jgrid.jqID(k.modalhead)).focus()},0)}})},navGrid:function(c,d,e,l,r,t,s){d=a.extend({edit:!0,editicon:"ui-icon-pencil",add:!0,addicon:"ui-icon-plus",del:!0,delicon:"ui-icon-trash",search:!0,searchicon:"ui-icon-search",refresh:!0,refreshicon:"ui-icon-refresh",refreshstate:"firstpage",view:!1,viewicon:"ui-icon-document",position:"left",closeOnEscape:!0,beforeRefresh:null,afterRefresh:null,cloneToTop:!1,alertwidth:200,alertheight:"auto",alerttop:null,alertleft:null,alertzIndex:null},a.jgrid.nav,
+d||{});return this.each(function(){if(!this.nav){var p={themodal:"alertmod",modalhead:"alerthd",modalcontent:"alertcnt"},g=this,f;if(g.grid&&"string"==typeof c){null===a("#"+p.themodal).html()&&(!d.alerttop&&!d.alertleft&&("undefined"!=typeof window.innerWidth?(d.alertleft=window.innerWidth,d.alerttop=window.innerHeight):"undefined"!=typeof document.documentElement&&"undefined"!=typeof document.documentElement.clientWidth&&0!==document.documentElement.clientWidth?(d.alertleft=document.documentElement.clientWidth,
+d.alerttop=document.documentElement.clientHeight):(d.alertleft=1024,d.alerttop=768),d.alertleft=d.alertleft/2-parseInt(d.alertwidth,10)/2,d.alerttop=d.alerttop/2-25),a.jgrid.createModal(p,"<div>"+d.alerttext+"</div><span tabindex='0'><span tabindex='-1' id='jqg_alrt'></span></span>",{gbox:"#gbox_"+a.jgrid.jqID(g.p.id),jqModal:!0,drag:!0,resize:!0,caption:d.alertcap,top:d.alerttop,left:d.alertleft,width:d.alertwidth,height:d.alertheight,closeOnEscape:d.closeOnEscape,zIndex:d.alertzIndex},"","",!0));
+var n=1;d.cloneToTop&&g.p.toppager&&(n=2);for(var w=0;w<n;w++){var b=a("<table cellspacing='0' cellpadding='0' border='0' class='ui-pg-table navtable' style='float:left;table-layout:auto;'><tbody><tr></tr></tbody></table>"),m,h;0===w?(m=c,h=g.p.id,m==g.p.toppager&&(h+="_top",n=1)):(m=g.p.toppager,h=g.p.id+"_top");"rtl"==g.p.direction&&a(b).attr("dir","rtl").css("float","right");d.add&&(l=l||{},f=a("<td class='ui-pg-button ui-corner-all'></td>"),a(f).append("<div class='ui-pg-div'><span class='ui-icon "+
+d.addicon+"'></span>"+d.addtext+"</div>"),a("tr",b).append(f),a(f,b).attr({title:d.addtitle||"",id:l.id||"add_"+h}).click(function(){a(this).hasClass("ui-state-disabled")||(a.isFunction(d.addfunc)?d.addfunc.call(g):a(g).jqGrid("editGridRow","new",l));return false}).hover(function(){a(this).hasClass("ui-state-disabled")||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}),f=null);d.edit&&(f=a("<td class='ui-pg-button ui-corner-all'></td>"),e=e||{},a(f).append("<div class='ui-pg-div'><span class='ui-icon "+
+d.editicon+"'></span>"+d.edittext+"</div>"),a("tr",b).append(f),a(f,b).attr({title:d.edittitle||"",id:e.id||"edit_"+h}).click(function(){if(!a(this).hasClass("ui-state-disabled")){var b=g.p.selrow;if(b)a.isFunction(d.editfunc)?d.editfunc.call(g,b):a(g).jqGrid("editGridRow",b,e);else{a.jgrid.viewModal("#"+p.themodal,{gbox:"#gbox_"+a.jgrid.jqID(g.p.id),jqm:true});a("#jqg_alrt").focus()}}return false}).hover(function(){a(this).hasClass("ui-state-disabled")||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}),
+f=null);d.view&&(f=a("<td class='ui-pg-button ui-corner-all'></td>"),s=s||{},a(f).append("<div class='ui-pg-div'><span class='ui-icon "+d.viewicon+"'></span>"+d.viewtext+"</div>"),a("tr",b).append(f),a(f,b).attr({title:d.viewtitle||"",id:s.id||"view_"+h}).click(function(){if(!a(this).hasClass("ui-state-disabled")){var b=g.p.selrow;if(b)a.isFunction(d.viewfunc)?d.viewfunc.call(g,b):a(g).jqGrid("viewGridRow",b,s);else{a.jgrid.viewModal("#"+p.themodal,{gbox:"#gbox_"+a.jgrid.jqID(g.p.id),jqm:true});a("#jqg_alrt").focus()}}return false}).hover(function(){a(this).hasClass("ui-state-disabled")||
+a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}),f=null);d.del&&(f=a("<td class='ui-pg-button ui-corner-all'></td>"),r=r||{},a(f).append("<div class='ui-pg-div'><span class='ui-icon "+d.delicon+"'></span>"+d.deltext+"</div>"),a("tr",b).append(f),a(f,b).attr({title:d.deltitle||"",id:r.id||"del_"+h}).click(function(){if(!a(this).hasClass("ui-state-disabled")){var b;if(g.p.multiselect){b=g.p.selarrrow;b.length===0&&(b=null)}else b=g.p.selrow;if(b)a.isFunction(d.delfunc)?
+d.delfunc.call(g,b):a(g).jqGrid("delGridRow",b,r);else{a.jgrid.viewModal("#"+p.themodal,{gbox:"#gbox_"+a.jgrid.jqID(g.p.id),jqm:true});a("#jqg_alrt").focus()}}return false}).hover(function(){a(this).hasClass("ui-state-disabled")||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}),f=null);(d.add||d.edit||d.del||d.view)&&a("tr",b).append("<td class='ui-pg-button ui-state-disabled' style='width:4px;'><span class='ui-separator'></span></td>");d.search&&(f=a("<td class='ui-pg-button ui-corner-all'></td>"),
+t=t||{},a(f).append("<div class='ui-pg-div'><span class='ui-icon "+d.searchicon+"'></span>"+d.searchtext+"</div>"),a("tr",b).append(f),a(f,b).attr({title:d.searchtitle||"",id:t.id||"search_"+h}).click(function(){a(this).hasClass("ui-state-disabled")||(a.isFunction(d.searchfunc)?d.searchfunc.call(g,t):a(g).jqGrid("searchGrid",t));return false}).hover(function(){a(this).hasClass("ui-state-disabled")||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}),t.showOnLoad&&
+!0===t.showOnLoad&&a(f,b).click(),f=null);d.refresh&&(f=a("<td class='ui-pg-button ui-corner-all'></td>"),a(f).append("<div class='ui-pg-div'><span class='ui-icon "+d.refreshicon+"'></span>"+d.refreshtext+"</div>"),a("tr",b).append(f),a(f,b).attr({title:d.refreshtitle||"",id:"refresh_"+h}).click(function(){if(!a(this).hasClass("ui-state-disabled")){a.isFunction(d.beforeRefresh)&&d.beforeRefresh.call(g);g.p.search=false;try{var b=g.p.id;g.p.postData.filters="";a("#fbox_"+a.jgrid.jqID(b)).jqFilter("resetFilter");
+a.isFunction(g.clearToolbar)&&g.clearToolbar.call(g,false)}catch(c){}switch(d.refreshstate){case "firstpage":a(g).trigger("reloadGrid",[{page:1}]);break;case "current":a(g).trigger("reloadGrid",[{current:true}])}a.isFunction(d.afterRefresh)&&d.afterRefresh.call(g)}return false}).hover(function(){a(this).hasClass("ui-state-disabled")||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}),f=null);f=a(".ui-jqgrid").css("font-size")||"11px";a("body").append("<div id='testpg2' class='ui-jqgrid ui-widget ui-widget-content' style='font-size:"+
+f+";visibility:hidden;' ></div>");f=a(b).clone().appendTo("#testpg2").width();a("#testpg2").remove();a(m+"_"+d.position,m).append(b);g.p._nvtd&&(f>g.p._nvtd[0]&&(a(m+"_"+d.position,m).width(f),g.p._nvtd[0]=f),g.p._nvtd[1]=f);b=f=f=null;this.nav=!0}}}})},navButtonAdd:function(c,d){d=a.extend({caption:"newButton",title:"",buttonicon:"ui-icon-newwin",onClickButton:null,position:"last",cursor:"pointer"},d||{});return this.each(function(){if(this.grid){"string"===typeof c&&0!==c.indexOf("#")&&(c="#"+a.jgrid.jqID(c));
+var e=a(".navtable",c)[0],l=this;if(e&&!(d.id&&null!==a("#"+a.jgrid.jqID(d.id),e).html())){var r=a("<td></td>");"NONE"==d.buttonicon.toString().toUpperCase()?a(r).addClass("ui-pg-button ui-corner-all").append("<div class='ui-pg-div'>"+d.caption+"</div>"):a(r).addClass("ui-pg-button ui-corner-all").append("<div class='ui-pg-div'><span class='ui-icon "+d.buttonicon+"'></span>"+d.caption+"</div>");d.id&&a(r).attr("id",d.id);"first"==d.position?0===e.rows[0].cells.length?a("tr",e).append(r):a("tr td:eq(0)",
+e).before(r):a("tr",e).append(r);a(r,e).attr("title",d.title||"").click(function(c){a(this).hasClass("ui-state-disabled")||a.isFunction(d.onClickButton)&&d.onClickButton.call(l,c);return!1}).hover(function(){a(this).hasClass("ui-state-disabled")||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")})}}})},navSeparatorAdd:function(c,d){d=a.extend({sepclass:"ui-separator",sepcontent:""},d||{});return this.each(function(){if(this.grid){"string"===typeof c&&0!==c.indexOf("#")&&
+(c="#"+a.jgrid.jqID(c));var e=a(".navtable",c)[0];if(e){var l="<td class='ui-pg-button ui-state-disabled' style='width:4px;'><span class='"+d.sepclass+"'></span>"+d.sepcontent+"</td>";a("tr",e).append(l)}}})},GridToForm:function(c,d){return this.each(function(){var e=this;if(e.grid){var l=a(e).jqGrid("getRowData",c);if(l)for(var r in l)a("[name="+a.jgrid.jqID(r)+"]",d).is("input:radio")||a("[name="+a.jgrid.jqID(r)+"]",d).is("input:checkbox")?a("[name="+a.jgrid.jqID(r)+"]",d).each(function(){if(a(this).val()==
+l[r])a(this)[e.p.useProp?"prop":"attr"]("checked",!0);else a(this)[e.p.useProp?"prop":"attr"]("checked",!1)}):a("[name="+a.jgrid.jqID(r)+"]",d).val(l[r])}})},FormToGrid:function(c,d,e,l){return this.each(function(){if(this.grid){e||(e="set");l||(l="first");var r=a(d).serializeArray(),t={};a.each(r,function(a,c){t[c.name]=c.value});"add"==e?a(this).jqGrid("addRowData",c,t,l):"set"==e&&a(this).jqGrid("setRowData",c,t)}})}})})(jQuery);
+(function(a){a.fn.jqFilter=function(d){if("string"===typeof d){var n=a.fn.jqFilter[d];if(!n)throw"jqFilter - No such method: "+d;var u=a.makeArray(arguments).slice(1);return n.apply(this,u)}var o=a.extend(!0,{filter:null,columns:[],onChange:null,afterRedraw:null,checkValues:null,error:!1,errmsg:"",errorcheck:!0,showQuery:!0,sopt:null,ops:[{name:"eq",description:"equal",operator:"="},{name:"ne",description:"not equal",operator:"<>"},{name:"lt",description:"less",operator:"<"},{name:"le",description:"less or equal",
+operator:"<="},{name:"gt",description:"greater",operator:">"},{name:"ge",description:"greater or equal",operator:">="},{name:"bw",description:"begins with",operator:"LIKE"},{name:"bn",description:"does not begin with",operator:"NOT LIKE"},{name:"in",description:"in",operator:"IN"},{name:"ni",description:"not in",operator:"NOT IN"},{name:"ew",description:"ends with",operator:"LIKE"},{name:"en",description:"does not end with",operator:"NOT LIKE"},{name:"cn",description:"contains",operator:"LIKE"},{name:"nc",
+description:"does not contain",operator:"NOT LIKE"},{name:"nu",description:"is null",operator:"IS NULL"},{name:"nn",description:"is not null",operator:"IS NOT NULL"}],numopts:"eq ne lt le gt ge nu nn in ni".split(" "),stropts:"eq ne bw bn ew en cn nc nu nn in ni".split(" "),_gridsopt:[],groupOps:[{op:"AND",text:"AND"},{op:"OR",text:"OR"}],groupButton:!0,ruleButtons:!0,direction:"ltr"},a.jgrid.filter,d||{});return this.each(function(){if(!this.filter){this.p=o;if(null===this.p.filter||void 0===this.p.filter)this.p.filter=
+{groupOp:this.p.groupOps[0].op,rules:[],groups:[]};var d,n=this.p.columns.length,f,t=/msie/i.test(navigator.userAgent)&&!window.opera;if(this.p._gridsopt.length)for(d=0;d<this.p._gridsopt.length;d++)this.p.ops[d].description=this.p._gridsopt[d];this.p.initFilter=a.extend(!0,{},this.p.filter);if(n){for(d=0;d<n;d++)if(f=this.p.columns[d],f.stype?f.inputtype=f.stype:f.inputtype||(f.inputtype="text"),f.sorttype?f.searchtype=f.sorttype:f.searchtype||(f.searchtype="string"),void 0===f.hidden&&(f.hidden=
+!1),f.label||(f.label=f.name),f.index&&(f.name=f.index),f.hasOwnProperty("searchoptions")||(f.searchoptions={}),!f.hasOwnProperty("searchrules"))f.searchrules={};this.p.showQuery&&a(this).append("<table class='queryresult ui-widget ui-widget-content' style='display:block;max-width:440px;border:0px none;' dir='"+this.p.direction+"'><tbody><tr><td class='query'></td></tr></tbody></table>");var r=function(g,k){var b=[!0,""];if(a.isFunction(k.searchrules))b=k.searchrules(g,k);else if(a.jgrid&&a.jgrid.checkValues)try{b=
+a.jgrid.checkValues(g,-1,null,k.searchrules,k.label)}catch(c){}b&&(b.length&&!1===b[0])&&(o.error=!b[0],o.errmsg=b[1])};this.onchange=function(){this.p.error=!1;this.p.errmsg="";return a.isFunction(this.p.onChange)?this.p.onChange.call(this,this.p):!1};this.reDraw=function(){a("table.group:first",this).remove();var g=this.createTableForGroup(o.filter,null);a(this).append(g);a.isFunction(this.p.afterRedraw)&&this.p.afterRedraw.call(this,this.p)};this.createTableForGroup=function(g,k){var b=this,c,
+e=a("<table class='group ui-widget ui-widget-content' style='border:0px none;'><tbody></tbody></table>"),d="left";"rtl"==this.p.direction&&(d="right",e.attr("dir","rtl"));null===k&&e.append("<tr class='error' style='display:none;'><th colspan='5' class='ui-state-error' align='"+d+"'></th></tr>");var h=a("<tr></tr>");e.append(h);d=a("<th colspan='5' align='"+d+"'></th>");h.append(d);if(!0===this.p.ruleButtons){var i=a("<select class='opsel'></select>");d.append(i);var h="",f;for(c=0;c<o.groupOps.length;c++)f=
+g.groupOp===b.p.groupOps[c].op?" selected='selected'":"",h+="<option value='"+b.p.groupOps[c].op+"'"+f+">"+b.p.groupOps[c].text+"</option>";i.append(h).bind("change",function(){g.groupOp=a(i).val();b.onchange()})}h="<span></span>";this.p.groupButton&&(h=a("<input type='button' value='+ {}' title='Add subgroup' class='add-group'/>"),h.bind("click",function(){if(g.groups===void 0)g.groups=[];g.groups.push({groupOp:o.groupOps[0].op,rules:[],groups:[]});b.reDraw();b.onchange();return false}));d.append(h);
+if(!0===this.p.ruleButtons){var h=a("<input type='button' value='+' title='Add rule' class='add-rule ui-add'/>"),l;h.bind("click",function(){if(g.rules===void 0)g.rules=[];for(c=0;c<b.p.columns.length;c++){var a=typeof b.p.columns[c].search==="undefined"?true:b.p.columns[c].search,e=b.p.columns[c].hidden===true;if(b.p.columns[c].searchoptions.searchhidden===true&&a||a&&!e){l=b.p.columns[c];break}}g.rules.push({field:l.name,op:(l.searchoptions.sopt?l.searchoptions.sopt:b.p.sopt?b.p.sopt:l.searchtype===
+"string"?b.p.stropts:b.p.numopts)[0],data:""});b.reDraw();return false});d.append(h)}null!==k&&(h=a("<input type='button' value='-' title='Delete group' class='delete-group'/>"),d.append(h),h.bind("click",function(){for(c=0;c<k.groups.length;c++)if(k.groups[c]===g){k.groups.splice(c,1);break}b.reDraw();b.onchange();return false}));if(void 0!==g.groups)for(c=0;c<g.groups.length;c++)d=a("<tr></tr>"),e.append(d),h=a("<td class='first'></td>"),d.append(h),h=a("<td colspan='4'></td>"),h.append(this.createTableForGroup(g.groups[c],
+g)),d.append(h);void 0===g.groupOp&&(g.groupOp=b.p.groupOps[0].op);if(void 0!==g.rules)for(c=0;c<g.rules.length;c++)e.append(this.createTableRowForRule(g.rules[c],g));return e};this.createTableRowForRule=function(g,d){var b=this,c=a("<tr></tr>"),e,f,h,i,j="",l;c.append("<td class='first'></td>");var m=a("<td class='columns'></td>");c.append(m);var n=a("<select></select>"),p,q=[];m.append(n);n.bind("change",function(){g.field=a(n).val();h=a(this).parents("tr:first");for(e=0;e<b.p.columns.length;e++)if(b.p.columns[e].name===
+g.field){i=b.p.columns[e];break}if(i){i.searchoptions.id=a.jgrid.randId();t&&"text"===i.inputtype&&!i.searchoptions.size&&(i.searchoptions.size=10);var c=a.jgrid.createEl(i.inputtype,i.searchoptions,"",!0,b.p.ajaxSelectOptions,!0);a(c).addClass("input-elm");f=i.searchoptions.sopt?i.searchoptions.sopt:b.p.sopt?b.p.sopt:"string"===i.searchtype?b.p.stropts:b.p.numopts;var d="",k=0;q=[];a.each(b.p.ops,function(){q.push(this.name)});for(e=0;e<f.length;e++)p=a.inArray(f[e],q),-1!==p&&(0===k&&(g.op=b.p.ops[p].name),
+d+="<option value='"+b.p.ops[p].name+"'>"+b.p.ops[p].description+"</option>",k++);a(".selectopts",h).empty().append(d);a(".selectopts",h)[0].selectedIndex=0;a.browser.msie&&9>a.browser.version&&(d=parseInt(a("select.selectopts",h)[0].offsetWidth)+1,a(".selectopts",h).width(d),a(".selectopts",h).css("width","auto"));a(".data",h).empty().append(c);a(".input-elm",h).bind("change",function(c){var d=a(this).hasClass("ui-autocomplete-input")?200:0;setTimeout(function(){var d=c.target;g.data=d.nodeName.toUpperCase()===
+"SPAN"&&i.searchoptions&&a.isFunction(i.searchoptions.custom_value)?i.searchoptions.custom_value(a(d).children(".customelement:first"),"get"):d.value;b.onchange()},d)});setTimeout(function(){g.data=a(c).val();b.onchange()},0)}});for(e=m=0;e<b.p.columns.length;e++){l="undefined"===typeof b.p.columns[e].search?!0:b.p.columns[e].search;var r=!0===b.p.columns[e].hidden;if(!0===b.p.columns[e].searchoptions.searchhidden&&l||l&&!r)l="",g.field===b.p.columns[e].name&&(l=" selected='selected'",m=e),j+="<option value='"+
+b.p.columns[e].name+"'"+l+">"+b.p.columns[e].label+"</option>"}n.append(j);j=a("<td class='operators'></td>");c.append(j);i=o.columns[m];i.searchoptions.id=a.jgrid.randId();t&&"text"===i.inputtype&&!i.searchoptions.size&&(i.searchoptions.size=10);var m=a.jgrid.createEl(i.inputtype,i.searchoptions,g.data,!0,b.p.ajaxSelectOptions,!0),s=a("<select class='selectopts'></select>");j.append(s);s.bind("change",function(){g.op=a(s).val();h=a(this).parents("tr:first");var c=a(".input-elm",h)[0];if(g.op==="nu"||
+g.op==="nn"){g.data="";c.value="";c.setAttribute("readonly","true");c.setAttribute("disabled","true")}else{c.removeAttribute("readonly");c.removeAttribute("disabled")}b.onchange()});f=i.searchoptions.sopt?i.searchoptions.sopt:b.p.sopt?b.p.sopt:"string"===i.searchtype?o.stropts:b.p.numopts;j="";a.each(b.p.ops,function(){q.push(this.name)});for(e=0;e<f.length;e++)p=a.inArray(f[e],q),-1!==p&&(l=g.op===b.p.ops[p].name?" selected='selected'":"",j+="<option value='"+b.p.ops[p].name+"'"+l+">"+b.p.ops[p].description+
+"</option>");s.append(j);j=a("<td class='data'></td>");c.append(j);j.append(m);a(m).addClass("input-elm").bind("change",function(){g.data=i.inputtype==="custom"?i.searchoptions.custom_value(a(this).children(".customelement:first"),"get"):a(this).val();b.onchange()});j=a("<td></td>");c.append(j);!0===this.p.ruleButtons&&(m=a("<input type='button' value='-' title='Delete rule' class='delete-rule ui-del'/>"),j.append(m),m.bind("click",function(){for(e=0;e<d.rules.length;e++)if(d.rules[e]===g){d.rules.splice(e,
+1);break}b.reDraw();b.onchange();return false}));return c};this.getStringForGroup=function(a){var d="(",b;if(void 0!==a.groups)for(b=0;b<a.groups.length;b++){1<d.length&&(d+=" "+a.groupOp+" ");try{d+=this.getStringForGroup(a.groups[b])}catch(c){alert(c)}}if(void 0!==a.rules)try{for(b=0;b<a.rules.length;b++)1<d.length&&(d+=" "+a.groupOp+" "),d+=this.getStringForRule(a.rules[b])}catch(e){alert(e)}d+=")";return"()"===d?"":d};this.getStringForRule=function(d){var f="",b="",c,e;for(c=0;c<this.p.ops.length;c++)if(this.p.ops[c].name===
+d.op){f=this.p.ops[c].operator;b=this.p.ops[c].name;break}for(c=0;c<this.p.columns.length;c++)if(this.p.columns[c].name===d.field){e=this.p.columns[c];break}c=d.data;if("bw"===b||"bn"===b)c+="%";if("ew"===b||"en"===b)c="%"+c;if("cn"===b||"nc"===b)c="%"+c+"%";if("in"===b||"ni"===b)c=" ("+c+")";o.errorcheck&&r(d.data,e);return-1!==a.inArray(e.searchtype,["int","integer","float","number","currency"])||"nn"===b||"nu"===b?d.field+" "+f+" "+c:d.field+" "+f+' "'+c+'"'};this.resetFilter=function(){this.p.filter=
+a.extend(!0,{},this.p.initFilter);this.reDraw();this.onchange()};this.hideError=function(){a("th.ui-state-error",this).html("");a("tr.error",this).hide()};this.showError=function(){a("th.ui-state-error",this).html(this.p.errmsg);a("tr.error",this).show()};this.toUserFriendlyString=function(){return this.getStringForGroup(o.filter)};this.toString=function(){function a(b){var c="(",e;if(void 0!==b.groups)for(e=0;e<b.groups.length;e++)1<c.length&&(c="OR"===b.groupOp?c+" || ":c+" && "),c+=a(b.groups[e]);
+if(void 0!==b.rules)for(e=0;e<b.rules.length;e++){1<c.length&&(c="OR"===b.groupOp?c+" || ":c+" && ");var f=b.rules[e];if(d.p.errorcheck){for(var h=void 0,i=void 0,h=0;h<d.p.columns.length;h++)if(d.p.columns[h].name===f.field){i=d.p.columns[h];break}i&&r(f.data,i)}c+=f.op+"(item."+f.field+",'"+f.data+"')"}c+=")";return"()"===c?"":c}var d=this;return a(this.p.filter)};this.reDraw();if(this.p.showQuery)this.onchange();this.filter=!0}}})};a.extend(a.fn.jqFilter,{toSQLString:function(){var a="";this.each(function(){a=
+this.toUserFriendlyString()});return a},filterData:function(){var a;this.each(function(){a=this.p.filter});return a},getParameter:function(a){return void 0!==a&&this.p.hasOwnProperty(a)?this.p[a]:this.p},resetFilter:function(){return this.each(function(){this.resetFilter()})},addFilter:function(a){"string"===typeof a&&(a=jQuery.jgrid.parse(a));this.each(function(){this.p.filter=a;this.reDraw();this.onchange()})}})})(jQuery);
+(function(a){a.jgrid.inlineEdit=a.jgrid.inlineEdit||{};a.jgrid.extend({editRow:function(c,b,d,k,g,l,p,h,f){var j={},e=a.makeArray(arguments).slice(1);if("object"===a.type(e[0]))j=e[0];else if("undefined"!==typeof b&&(j.keys=b),a.isFunction(d)&&(j.oneditfunc=d),a.isFunction(k)&&(j.successfunc=k),"undefined"!==typeof g&&(j.url=g),"undefined"!==typeof l&&(j.extraparam=l),a.isFunction(p)&&(j.aftersavefunc=p),a.isFunction(h)&&(j.errorfunc=h),a.isFunction(f))j.afterrestorefunc=f;j=a.extend(!0,{keys:!1,
+oneditfunc:null,successfunc:null,url:null,extraparam:{},aftersavefunc:null,errorfunc:null,afterrestorefunc:null,restoreAfterError:!0,mtype:"POST"},a.jgrid.inlineEdit,j);return this.each(function(){var b=this,f,d,e,g=0,h=null,l={},m,n;b.grid&&(m=a(b).jqGrid("getInd",c,!0),!1!==m&&(e=a(m).attr("editable")||"0","0"==e&&!a(m).hasClass("not-editable-row")&&(n=b.p.colModel,a('td[role="gridcell"]',m).each(function(e){f=n[e].name;var j=!0===b.p.treeGrid&&f==b.p.ExpandColumn;if(j)d=a("span:first",this).html();
+else try{d=a.unformat.call(b,this,{rowId:c,colModel:n[e]},e)}catch(m){d=n[e].edittype&&"textarea"==n[e].edittype?a(this).text():a(this).html()}if("cb"!=f&&("subgrid"!=f&&"rn"!=f)&&(b.p.autoencode&&(d=a.jgrid.htmlDecode(d)),l[f]=d,!0===n[e].editable)){null===h&&(h=e);j?a("span:first",this).html(""):a(this).html("");var k=a.extend({},n[e].editoptions||{},{id:c+"_"+f,name:f});n[e].edittype||(n[e].edittype="text");if("&nbsp;"==d||"&#160;"==d||1==d.length&&160==d.charCodeAt(0))d="";k=a.jgrid.createEl.call(b,
+n[e].edittype,k,d,!0,a.extend({},a.jgrid.ajaxOptions,b.p.ajaxSelectOptions||{}));a(k).addClass("editable");j?a("span:first",this).append(k):a(this).append(k);"select"==n[e].edittype&&("undefined"!==typeof n[e].editoptions&&!0===n[e].editoptions.multiple&&"undefined"===typeof n[e].editoptions.dataUrl&&a.browser.msie)&&a(k).width(a(k).width());g++}}),0<g&&(l.id=c,b.p.savedRow.push(l),a(m).attr("editable","1"),a("td:eq("+h+") input",m).focus(),!0===j.keys&&a(m).bind("keydown",function(e){if(27===e.keyCode){a(b).jqGrid("restoreRow",
+c,j.afterrestorefunc);if(b.p._inlinenav)try{a(b).jqGrid("showAddEditButtons")}catch(d){}return!1}if(13===e.keyCode){if("TEXTAREA"==e.target.tagName)return!0;if(a(b).jqGrid("saveRow",c,j)&&b.p._inlinenav)try{a(b).jqGrid("showAddEditButtons")}catch(f){}return!1}}),a(b).triggerHandler("jqGridInlineEditRow",[c,j]),a.isFunction(j.oneditfunc)&&j.oneditfunc.call(b,c)))))})},saveRow:function(c,b,d,k,g,l,p){var h=a.makeArray(arguments).slice(1),f={};if("object"===a.type(h[0]))f=h[0];else if(a.isFunction(b)&&
+(f.successfunc=b),"undefined"!==typeof d&&(f.url=d),"undefined"!==typeof k&&(f.extraparam=k),a.isFunction(g)&&(f.aftersavefunc=g),a.isFunction(l)&&(f.errorfunc=l),a.isFunction(p))f.afterrestorefunc=p;var f=a.extend(!0,{successfunc:null,url:null,extraparam:{},aftersavefunc:null,errorfunc:null,afterrestorefunc:null,restoreAfterError:!0,mtype:"POST"},a.jgrid.inlineEdit,f),j=!1,e=this[0],o,i={},u={},r={},t,s,q;if(!e.grid)return j;q=a(e).jqGrid("getInd",c,!0);if(!1===q)return j;h=a(q).attr("editable");
+f.url=f.url?f.url:e.p.editurl;if("1"===h){var m;a('td[role="gridcell"]',q).each(function(b){m=e.p.colModel[b];o=m.name;if("cb"!=o&&"subgrid"!=o&&!0===m.editable&&"rn"!=o&&!a(this).hasClass("not-editable-cell")){switch(m.edittype){case "checkbox":var c=["Yes","No"];m.editoptions&&(c=m.editoptions.value.split(":"));i[o]=a("input",this).is(":checked")?c[0]:c[1];break;case "text":case "password":case "textarea":case "button":i[o]=a("input, textarea",this).val();break;case "select":if(m.editoptions.multiple){var c=
+a("select",this),d=[];i[o]=a(c).val();i[o]=i[o]?i[o].join(","):"";a("select option:selected",this).each(function(b,c){d[b]=a(c).text()});u[o]=d.join(",")}else i[o]=a("select option:selected",this).val(),u[o]=a("select option:selected",this).text();m.formatter&&"select"==m.formatter&&(u={});break;case "custom":try{if(m.editoptions&&a.isFunction(m.editoptions.custom_value)){if(i[o]=m.editoptions.custom_value.call(e,a(".customelement",this),"get"),void 0===i[o])throw"e2";}else throw"e1";}catch(g){"e1"==
+g&&a.jgrid.info_dialog(a.jgrid.errors.errcap,"function 'custom_value' "+a.jgrid.edit.msg.nodefined,a.jgrid.edit.bClose),"e2"==g?a.jgrid.info_dialog(a.jgrid.errors.errcap,"function 'custom_value' "+a.jgrid.edit.msg.novalue,a.jgrid.edit.bClose):a.jgrid.info_dialog(a.jgrid.errors.errcap,g.message,a.jgrid.edit.bClose)}}s=a.jgrid.checkValues(i[o],b,e);if(!1===s[0])return s[1]=i[o]+" "+s[1],!1;e.p.autoencode&&(i[o]=a.jgrid.htmlEncode(i[o]));"clientArray"!==f.url&&m.editoptions&&!0===m.editoptions.NullIfEmpty&&
+""===i[o]&&(r[o]="null")}});if(!1===s[0]){try{var n=a.jgrid.findPos(a("#"+a.jgrid.jqID(c),e.grid.bDiv)[0]);a.jgrid.info_dialog(a.jgrid.errors.errcap,s[1],a.jgrid.edit.bClose,{left:n[0],top:n[1]})}catch(w){alert(s[1])}return j}var v,h=e.p.prmNames;v=h.oper;n=h.id;i&&(i[v]=h.editoper,i[n]=c,"undefined"==typeof e.p.inlineData&&(e.p.inlineData={}),i=a.extend({},i,e.p.inlineData,f.extraparam));if("clientArray"==f.url){i=a.extend({},i,u);e.p.autoencode&&a.each(i,function(b,c){i[b]=a.jgrid.htmlDecode(c)});
+n=a(e).jqGrid("setRowData",c,i);a(q).attr("editable","0");for(h=0;h<e.p.savedRow.length;h++)if(e.p.savedRow[h].id==c){t=h;break}0<=t&&e.p.savedRow.splice(t,1);a(e).triggerHandler("jqGridInlineAfterSaveRow",[c,n,i,f]);a.isFunction(f.aftersavefunc)&&f.aftersavefunc.call(e,c,n);j=!0;a(q).unbind("keydown")}else a("#lui_"+a.jgrid.jqID(e.p.id)).show(),r=a.extend({},i,r),r[n]=a.jgrid.stripPref(e.p.idPrefix,r[n]),a.ajax(a.extend({url:f.url,data:a.isFunction(e.p.serializeRowData)?e.p.serializeRowData.call(e,
+r):r,type:f.mtype,async:!1,complete:function(b,d){a("#lui_"+a.jgrid.jqID(e.p.id)).hide();if(d==="success"){var g=true,h;h=a(e).triggerHandler("jqGridInlineSuccessSaveRow",[b,c,f]);a.isArray(h)||(h=[true,i]);h[0]&&a.isFunction(f.successfunc)&&(h=f.successfunc.call(e,b));if(a.isArray(h)){g=h[0];i=h[1]?h[1]:i}else g=h;if(g===true){e.p.autoencode&&a.each(i,function(b,c){i[b]=a.jgrid.htmlDecode(c)});i=a.extend({},i,u);a(e).jqGrid("setRowData",c,i);a(q).attr("editable","0");for(g=0;g<e.p.savedRow.length;g++)if(e.p.savedRow[g].id==
+c){t=g;break}t>=0&&e.p.savedRow.splice(t,1);a(e).triggerHandler("jqGridInlineAfterSaveRow",[c,b,i,f]);a.isFunction(f.aftersavefunc)&&f.aftersavefunc.call(e,c,b);j=true;a(q).unbind("keydown")}else{a(e).triggerHandler("jqGridInlineErrorSaveRow",[c,b,d,null,f]);a.isFunction(f.errorfunc)&&f.errorfunc.call(e,c,b,d,null);f.restoreAfterError===true&&a(e).jqGrid("restoreRow",c,f.afterrestorefunc)}}},error:function(b,d,g){a("#lui_"+a.jgrid.jqID(e.p.id)).hide();a(e).triggerHandler("jqGridInlineErrorSaveRow",
+[c,b,d,g,f]);if(a.isFunction(f.errorfunc))f.errorfunc.call(e,c,b,d,g);else try{a.jgrid.info_dialog(a.jgrid.errors.errcap,'<div class="ui-state-error">'+b.responseText+"</div>",a.jgrid.edit.bClose,{buttonalign:"right"})}catch(h){alert(b.responseText)}f.restoreAfterError===true&&a(e).jqGrid("restoreRow",c,f.afterrestorefunc)}},a.jgrid.ajaxOptions,e.p.ajaxRowOptions||{}))}return j},restoreRow:function(c,b){var d=a.makeArray(arguments).slice(1),k={};"object"===a.type(d[0])?k=d[0]:a.isFunction(b)&&(k.afterrestorefunc=
+b);k=a.extend(!0,a.jgrid.inlineEdit,k);return this.each(function(){var b=this,d,p,h={};if(b.grid){p=a(b).jqGrid("getInd",c,true);if(p!==false){for(var f=0;f<b.p.savedRow.length;f++)if(b.p.savedRow[f].id==c){d=f;break}if(d>=0){if(a.isFunction(a.fn.datepicker))try{a("input.hasDatepicker","#"+a.jgrid.jqID(p.id)).datepicker("hide")}catch(j){}a.each(b.p.colModel,function(){this.editable===true&&this.name in b.p.savedRow[d]&&(h[this.name]=b.p.savedRow[d][this.name])});a(b).jqGrid("setRowData",c,h);a(p).attr("editable",
+"0").unbind("keydown");b.p.savedRow.splice(d,1);a("#"+a.jgrid.jqID(c),"#"+a.jgrid.jqID(b.p.id)).hasClass("jqgrid-new-row")&&setTimeout(function(){a(b).jqGrid("delRowData",c)},0)}a(b).triggerHandler("jqGridInlineAfterRestoreRow",[c]);a.isFunction(k.afterrestorefunc)&&k.afterrestorefunc.call(b,c)}}})},addRow:function(c){c=a.extend(!0,{rowID:"new_row",initdata:{},position:"first",useDefValues:!0,useFormatter:!1,addRowParams:{extraparam:{}}},c||{});return this.each(function(){if(this.grid){var b=this;
+!0===c.useDefValues&&a(b.p.colModel).each(function(){if(this.editoptions&&this.editoptions.defaultValue){var d=this.editoptions.defaultValue,d=a.isFunction(d)?d.call(b):d;c.initdata[this.name]=d}});a(b).jqGrid("addRowData",c.rowID,c.initdata,c.position);c.rowID=b.p.idPrefix+c.rowID;a("#"+a.jgrid.jqID(c.rowID),"#"+a.jgrid.jqID(b.p.id)).addClass("jqgrid-new-row");if(c.useFormatter)a("#"+a.jgrid.jqID(c.rowID)+" .ui-inline-edit","#"+a.jgrid.jqID(b.p.id)).click();else{var d=b.p.prmNames;c.addRowParams.extraparam[d.oper]=
+d.addoper;a(b).jqGrid("editRow",c.rowID,c.addRowParams);a(b).jqGrid("setSelection",c.rowID)}}})},inlineNav:function(c,b){b=a.extend({edit:!0,editicon:"ui-icon-pencil",add:!0,addicon:"ui-icon-plus",save:!0,saveicon:"ui-icon-disk",cancel:!0,cancelicon:"ui-icon-cancel",addParams:{useFormatter:!1,rowID:"new_row"},editParams:{},restoreAfterSelect:!0},a.jgrid.nav,b||{});return this.each(function(){if(this.grid){var d=this,k,g=a.jgrid.jqID(d.p.id);d.p._inlinenav=!0;if(!0===b.addParams.useFormatter){var l=
+d.p.colModel,p;for(p=0;p<l.length;p++)if(l[p].formatter&&"actions"===l[p].formatter){l[p].formatoptions&&(l=a.extend({keys:!1,onEdit:null,onSuccess:null,afterSave:null,onError:null,afterRestore:null,extraparam:{},url:null},l[p].formatoptions),b.addParams.addRowParams={keys:l.keys,oneditfunc:l.onEdit,successfunc:l.onSuccess,url:l.url,extraparam:l.extraparam,aftersavefunc:l.afterSavef,errorfunc:l.onError,afterrestorefunc:l.afterRestore});break}}b.add&&a(d).jqGrid("navButtonAdd",c,{caption:b.addtext,
+title:b.addtitle,buttonicon:b.addicon,id:d.p.id+"_iladd",onClickButton:function(){a(d).jqGrid("addRow",b.addParams);b.addParams.useFormatter||(a("#"+g+"_ilsave").removeClass("ui-state-disabled"),a("#"+g+"_ilcancel").removeClass("ui-state-disabled"),a("#"+g+"_iladd").addClass("ui-state-disabled"),a("#"+g+"_iledit").addClass("ui-state-disabled"))}});b.edit&&a(d).jqGrid("navButtonAdd",c,{caption:b.edittext,title:b.edittitle,buttonicon:b.editicon,id:d.p.id+"_iledit",onClickButton:function(){var c=a(d).jqGrid("getGridParam",
+"selrow");c?(a(d).jqGrid("editRow",c,b.editParams),a("#"+g+"_ilsave").removeClass("ui-state-disabled"),a("#"+g+"_ilcancel").removeClass("ui-state-disabled"),a("#"+g+"_iladd").addClass("ui-state-disabled"),a("#"+g+"_iledit").addClass("ui-state-disabled")):(a.jgrid.viewModal("#alertmod",{gbox:"#gbox_"+g,jqm:!0}),a("#jqg_alrt").focus())}});b.save&&(a(d).jqGrid("navButtonAdd",c,{caption:b.savetext||"",title:b.savetitle||"Save row",buttonicon:b.saveicon,id:d.p.id+"_ilsave",onClickButton:function(){var c=
+d.p.savedRow[0].id;if(c){var f=d.p.prmNames,j=f.oper;b.editParams.extraparam||(b.editParams.extraparam={});b.editParams.extraparam[j]=a("#"+a.jgrid.jqID(c),"#"+g).hasClass("jqgrid-new-row")?f.addoper:f.editoper;a(d).jqGrid("saveRow",c,b.editParams)&&a(d).jqGrid("showAddEditButtons")}else a.jgrid.viewModal("#alertmod",{gbox:"#gbox_"+g,jqm:!0}),a("#jqg_alrt").focus()}}),a("#"+g+"_ilsave").addClass("ui-state-disabled"));b.cancel&&(a(d).jqGrid("navButtonAdd",c,{caption:b.canceltext||"",title:b.canceltitle||
+"Cancel row editing",buttonicon:b.cancelicon,id:d.p.id+"_ilcancel",onClickButton:function(){var c=d.p.savedRow[0].id;if(c){a(d).jqGrid("restoreRow",c,b.editParams);a(d).jqGrid("showAddEditButtons")}else{a.jgrid.viewModal("#alertmod",{gbox:"#gbox_"+g,jqm:true});a("#jqg_alrt").focus()}}}),a("#"+g+"_ilcancel").addClass("ui-state-disabled"));!0===b.restoreAfterSelect&&(k=a.isFunction(d.p.beforeSelectRow)?d.p.beforeSelectRow:!1,d.p.beforeSelectRow=function(c,f){var g=true;if(d.p.savedRow.length>0&&d.p._inlinenav===
+true&&c!==d.p.selrow&&d.p.selrow!==null){d.p.selrow==b.addParams.rowID?a(d).jqGrid("delRowData",d.p.selrow):a(d).jqGrid("restoreRow",d.p.selrow,b.editParams);a(d).jqGrid("showAddEditButtons")}k&&(g=k.call(d,c,f));return g})}})},showAddEditButtons:function(){return this.each(function(){if(this.grid){var c=a.jgrid.jqID(this.p.id);a("#"+c+"_ilsave").addClass("ui-state-disabled");a("#"+c+"_ilcancel").addClass("ui-state-disabled");a("#"+c+"_iladd").removeClass("ui-state-disabled");a("#"+c+"_iledit").removeClass("ui-state-disabled")}})}})})(jQuery);
+(function(b){b.jgrid.extend({editCell:function(d,f,a){return this.each(function(){var c=this,g,e,h,i;if(c.grid&&!0===c.p.cellEdit){f=parseInt(f,10);c.p.selrow=c.rows[d].id;c.p.knv||b(c).jqGrid("GridNav");if(0<c.p.savedRow.length){if(!0===a&&d==c.p.iRow&&f==c.p.iCol)return;b(c).jqGrid("saveCell",c.p.savedRow[0].id,c.p.savedRow[0].ic)}else window.setTimeout(function(){b("#"+b.jgrid.jqID(c.p.knv)).attr("tabindex","-1").focus()},0);i=c.p.colModel[f];g=i.name;if(!("subgrid"==g||"cb"==g||"rn"==g)){h=b("td:eq("+
+f+")",c.rows[d]);if(!0===i.editable&&!0===a&&!h.hasClass("not-editable-cell")){0<=parseInt(c.p.iCol,10)&&0<=parseInt(c.p.iRow,10)&&(b("td:eq("+c.p.iCol+")",c.rows[c.p.iRow]).removeClass("edit-cell ui-state-highlight"),b(c.rows[c.p.iRow]).removeClass("selected-row ui-state-hover"));b(h).addClass("edit-cell ui-state-highlight");b(c.rows[d]).addClass("selected-row ui-state-hover");try{e=b.unformat.call(c,h,{rowId:c.rows[d].id,colModel:i},f)}catch(k){e=i.edittype&&"textarea"==i.edittype?b(h).text():b(h).html()}c.p.autoencode&&
+(e=b.jgrid.htmlDecode(e));i.edittype||(i.edittype="text");c.p.savedRow.push({id:d,ic:f,name:g,v:e});if("&nbsp;"===e||"&#160;"===e||1===e.length&&160===e.charCodeAt(0))e="";if(b.isFunction(c.p.formatCell)){var j=c.p.formatCell.call(c,c.rows[d].id,g,e,d,f);void 0!==j&&(e=j)}var j=b.extend({},i.editoptions||{},{id:d+"_"+g,name:g}),n=b.jgrid.createEl.call(c,i.edittype,j,e,!0,b.extend({},b.jgrid.ajaxOptions,c.p.ajaxSelectOptions||{}));b(c).triggerHandler("jqGridBeforeEditCell",[c.rows[d].id,g,e,d,f]);
+b.isFunction(c.p.beforeEditCell)&&c.p.beforeEditCell.call(c,c.rows[d].id,g,e,d,f);b(h).html("").append(n).attr("tabindex","0");window.setTimeout(function(){b(n).focus()},0);b("input, select, textarea",h).bind("keydown",function(a){a.keyCode===27&&(b("input.hasDatepicker",h).length>0?b(".ui-datepicker").is(":hidden")?b(c).jqGrid("restoreCell",d,f):b("input.hasDatepicker",h).datepicker("hide"):b(c).jqGrid("restoreCell",d,f));if(a.keyCode===13){b(c).jqGrid("saveCell",d,f);return false}if(a.keyCode===
+9){if(c.grid.hDiv.loading)return false;a.shiftKey?b(c).jqGrid("prevCell",d,f):b(c).jqGrid("nextCell",d,f)}a.stopPropagation()});b(c).triggerHandler("jqGridAfterEditCell",[c.rows[d].id,g,e,d,f]);b.isFunction(c.p.afterEditCell)&&c.p.afterEditCell.call(c,c.rows[d].id,g,e,d,f)}else 0<=parseInt(c.p.iCol,10)&&0<=parseInt(c.p.iRow,10)&&(b("td:eq("+c.p.iCol+")",c.rows[c.p.iRow]).removeClass("edit-cell ui-state-highlight"),b(c.rows[c.p.iRow]).removeClass("selected-row ui-state-hover")),h.addClass("edit-cell ui-state-highlight"),
+b(c.rows[d]).addClass("selected-row ui-state-hover"),e=h.html().replace(/\&#160\;/ig,""),b(c).triggerHandler("jqGridSelectCell",[c.rows[d].id,g,e,d,f]),b.isFunction(c.p.onSelectCell)&&c.p.onSelectCell.call(c,c.rows[d].id,g,e,d,f);c.p.iCol=f;c.p.iRow=d}}})},saveCell:function(d,f){return this.each(function(){var a=this,c;if(a.grid&&!0===a.p.cellEdit){c=1<=a.p.savedRow.length?0:null;if(null!==c){var g=b("td:eq("+f+")",a.rows[d]),e,h,i=a.p.colModel[f],k=i.name,j=b.jgrid.jqID(k);switch(i.edittype){case "select":if(i.editoptions.multiple){var j=
+b("#"+d+"_"+j,a.rows[d]),n=[];(e=b(j).val())?e.join(","):e="";b("option:selected",j).each(function(a,c){n[a]=b(c).text()});h=n.join(",")}else e=b("#"+d+"_"+j+" option:selected",a.rows[d]).val(),h=b("#"+d+"_"+j+" option:selected",a.rows[d]).text();i.formatter&&(h=e);break;case "checkbox":var l=["Yes","No"];i.editoptions&&(l=i.editoptions.value.split(":"));h=e=b("#"+d+"_"+j,a.rows[d]).is(":checked")?l[0]:l[1];break;case "password":case "text":case "textarea":case "button":h=e=b("#"+d+"_"+j,a.rows[d]).val();
+break;case "custom":try{if(i.editoptions&&b.isFunction(i.editoptions.custom_value)){e=i.editoptions.custom_value.call(a,b(".customelement",g),"get");if(void 0===e)throw"e2";h=e}else throw"e1";}catch(o){"e1"==o&&b.jgrid.info_dialog(jQuery.jgrid.errors.errcap,"function 'custom_value' "+b.jgrid.edit.msg.nodefined,jQuery.jgrid.edit.bClose),"e2"==o?b.jgrid.info_dialog(jQuery.jgrid.errors.errcap,"function 'custom_value' "+b.jgrid.edit.msg.novalue,jQuery.jgrid.edit.bClose):b.jgrid.info_dialog(jQuery.jgrid.errors.errcap,
+o.message,jQuery.jgrid.edit.bClose)}}if(h!==a.p.savedRow[c].v){if(c=b(a).triggerHandler("jqGridBeforeSaveCell",[a.rows[d].id,k,e,d,f]))h=e=c;if(b.isFunction(a.p.beforeSaveCell)&&(c=a.p.beforeSaveCell.call(a,a.rows[d].id,k,e,d,f)))h=e=c;var p=b.jgrid.checkValues(e,f,a);if(!0===p[0]){c=b(a).triggerHandler("jqGridBeforeSubmitCell",[a.rows[d].id,k,e,d,f])||{};b.isFunction(a.p.beforeSubmitCell)&&((c=a.p.beforeSubmitCell.call(a,a.rows[d].id,k,e,d,f))||(c={}));0<b("input.hasDatepicker",g).length&&b("input.hasDatepicker",
+g).datepicker("hide");if("remote"==a.p.cellsubmit)if(a.p.cellurl){var m={};a.p.autoencode&&(e=b.jgrid.htmlEncode(e));m[k]=e;l=a.p.prmNames;i=l.id;j=l.oper;m[i]=b.jgrid.stripPref(a.p.idPrefix,a.rows[d].id);m[j]=l.editoper;m=b.extend(c,m);b("#lui_"+b.jgrid.jqID(a.p.id)).show();a.grid.hDiv.loading=!0;b.ajax(b.extend({url:a.p.cellurl,data:b.isFunction(a.p.serializeCellData)?a.p.serializeCellData.call(a,m):m,type:"POST",complete:function(c,i){b("#lui_"+a.p.id).hide();a.grid.hDiv.loading=false;if(i=="success"){var j=
+b(a).triggerHandler("jqGridAfterSubmitCell",[a,c,m.id,k,e,d,f])||[true,""];j[0]===true&&b.isFunction(a.p.afterSubmitCell)&&(j=a.p.afterSubmitCell.call(a,c,m.id,k,e,d,f));if(j[0]===true){b(g).empty();b(a).jqGrid("setCell",a.rows[d].id,f,h,false,false,true);b(g).addClass("dirty-cell");b(a.rows[d]).addClass("edited");b(a).triggerHandler("jqGridAfterSaveCell",[a.rows[d].id,k,e,d,f]);b.isFunction(a.p.afterSaveCell)&&a.p.afterSaveCell.call(a,a.rows[d].id,k,e,d,f);a.p.savedRow.splice(0,1)}else{b.jgrid.info_dialog(b.jgrid.errors.errcap,
+j[1],b.jgrid.edit.bClose);b(a).jqGrid("restoreCell",d,f)}}},error:function(c,e,h){b("#lui_"+b.jgrid.jqID(a.p.id)).hide();a.grid.hDiv.loading=false;b(a).triggerHandler("jqGridErrorCell",[c,e,h]);b.isFunction(a.p.errorCell)?a.p.errorCell.call(a,c,e,h):b.jgrid.info_dialog(b.jgrid.errors.errcap,c.status+" : "+c.statusText+"<br/>"+e,b.jgrid.edit.bClose);b(a).jqGrid("restoreCell",d,f)}},b.jgrid.ajaxOptions,a.p.ajaxCellOptions||{}))}else try{b.jgrid.info_dialog(b.jgrid.errors.errcap,b.jgrid.errors.nourl,
+b.jgrid.edit.bClose),b(a).jqGrid("restoreCell",d,f)}catch(q){}"clientArray"==a.p.cellsubmit&&(b(g).empty(),b(a).jqGrid("setCell",a.rows[d].id,f,h,!1,!1,!0),b(g).addClass("dirty-cell"),b(a.rows[d]).addClass("edited"),b(a).triggerHandler("jqGridAfterSaveCell",[a.rows[d].id,k,e,d,f]),b.isFunction(a.p.afterSaveCell)&&a.p.afterSaveCell.call(a,a.rows[d].id,k,e,d,f),a.p.savedRow.splice(0,1))}else try{window.setTimeout(function(){b.jgrid.info_dialog(b.jgrid.errors.errcap,e+" "+p[1],b.jgrid.edit.bClose)},
+100),b(a).jqGrid("restoreCell",d,f)}catch(r){}}else b(a).jqGrid("restoreCell",d,f)}b.browser.opera?b("#"+b.jgrid.jqID(a.p.knv)).attr("tabindex","-1").focus():window.setTimeout(function(){b("#"+b.jgrid.jqID(a.p.knv)).attr("tabindex","-1").focus()},0)}})},restoreCell:function(d,f){return this.each(function(){var a=this,c;if(a.grid&&!0===a.p.cellEdit){c=1<=a.p.savedRow.length?0:null;if(null!==c){var g=b("td:eq("+f+")",a.rows[d]);if(b.isFunction(b.fn.datepicker))try{b("input.hasDatepicker",g).datepicker("hide")}catch(e){}b(g).empty().attr("tabindex",
+"-1");b(a).jqGrid("setCell",a.rows[d].id,f,a.p.savedRow[c].v,!1,!1,!0);b(a).triggerHandler("jqGridAfterRestoreCell",[a.rows[d].id,a.p.savedRow[c].v,d,f]);b.isFunction(a.p.afterRestoreCell)&&a.p.afterRestoreCell.call(a,a.rows[d].id,a.p.savedRow[c].v,d,f);a.p.savedRow.splice(0,1)}window.setTimeout(function(){b("#"+a.p.knv).attr("tabindex","-1").focus()},0)}})},nextCell:function(d,f){return this.each(function(){var a=!1;if(this.grid&&!0===this.p.cellEdit){for(var c=f+1;c<this.p.colModel.length;c++)if(!0===
+this.p.colModel[c].editable){a=c;break}!1!==a?b(this).jqGrid("editCell",d,a,!0):0<this.p.savedRow.length&&b(this).jqGrid("saveCell",d,f)}})},prevCell:function(d,f){return this.each(function(){var a=!1;if(this.grid&&!0===this.p.cellEdit){for(var c=f-1;0<=c;c--)if(!0===this.p.colModel[c].editable){a=c;break}!1!==a?b(this).jqGrid("editCell",d,a,!0):0<this.p.savedRow.length&&b(this).jqGrid("saveCell",d,f)}})},GridNav:function(){return this.each(function(){function d(c,d,e){if("v"==e.substr(0,1)){var f=
+b(a.grid.bDiv)[0].clientHeight,g=b(a.grid.bDiv)[0].scrollTop,l=a.rows[c].offsetTop+a.rows[c].clientHeight,o=a.rows[c].offsetTop;"vd"==e&&l>=f&&(b(a.grid.bDiv)[0].scrollTop=b(a.grid.bDiv)[0].scrollTop+a.rows[c].clientHeight);"vu"==e&&o<g&&(b(a.grid.bDiv)[0].scrollTop=b(a.grid.bDiv)[0].scrollTop-a.rows[c].clientHeight)}"h"==e&&(e=b(a.grid.bDiv)[0].clientWidth,f=b(a.grid.bDiv)[0].scrollLeft,g=a.rows[c].cells[d].offsetLeft,a.rows[c].cells[d].offsetLeft+a.rows[c].cells[d].clientWidth>=e+parseInt(f,10)?
+b(a.grid.bDiv)[0].scrollLeft=b(a.grid.bDiv)[0].scrollLeft+a.rows[c].cells[d].clientWidth:g<f&&(b(a.grid.bDiv)[0].scrollLeft=b(a.grid.bDiv)[0].scrollLeft-a.rows[c].cells[d].clientWidth))}function f(b,c){var d,e;if("lft"==c){d=b+1;for(e=b;0<=e;e--)if(!0!==a.p.colModel[e].hidden){d=e;break}}if("rgt"==c){d=b-1;for(e=b;e<a.p.colModel.length;e++)if(!0!==a.p.colModel[e].hidden){d=e;break}}return d}var a=this;if(a.grid&&!0===a.p.cellEdit){a.p.knv=a.p.id+"_kn";var c=b("<span style='width:0px;height:0px;background-color:black;' tabindex='0'><span tabindex='-1' style='width:0px;height:0px;background-color:grey' id='"+
+a.p.knv+"'></span></span>"),g,e;b(c).insertBefore(a.grid.cDiv);b("#"+a.p.knv).focus().keydown(function(c){e=c.keyCode;"rtl"==a.p.direction&&(37===e?e=39:39===e&&(e=37));switch(e){case 38:0<a.p.iRow-1&&(d(a.p.iRow-1,a.p.iCol,"vu"),b(a).jqGrid("editCell",a.p.iRow-1,a.p.iCol,!1));break;case 40:a.p.iRow+1<=a.rows.length-1&&(d(a.p.iRow+1,a.p.iCol,"vd"),b(a).jqGrid("editCell",a.p.iRow+1,a.p.iCol,!1));break;case 37:0<=a.p.iCol-1&&(g=f(a.p.iCol-1,"lft"),d(a.p.iRow,g,"h"),b(a).jqGrid("editCell",a.p.iRow,g,
+!1));break;case 39:a.p.iCol+1<=a.p.colModel.length-1&&(g=f(a.p.iCol+1,"rgt"),d(a.p.iRow,g,"h"),b(a).jqGrid("editCell",a.p.iRow,g,!1));break;case 13:0<=parseInt(a.p.iCol,10)&&0<=parseInt(a.p.iRow,10)&&b(a).jqGrid("editCell",a.p.iRow,a.p.iCol,!0);break;default:return!0}return!1})}})},getChangedCells:function(d){var f=[];d||(d="all");this.each(function(){var a=this,c;a.grid&&!0===a.p.cellEdit&&b(a.rows).each(function(g){var e={};b(this).hasClass("edited")&&(b("td",this).each(function(f){c=a.p.colModel[f].name;
+if("cb"!==c&&"subgrid"!==c)if("dirty"==d){if(b(this).hasClass("dirty-cell"))try{e[c]=b.unformat.call(a,this,{rowId:a.rows[g].id,colModel:a.p.colModel[f]},f)}catch(i){e[c]=b.jgrid.htmlDecode(b(this).html())}}else try{e[c]=b.unformat.call(a,this,{rowId:a.rows[g].id,colModel:a.p.colModel[f]},f)}catch(k){e[c]=b.jgrid.htmlDecode(b(this).html())}}),e.id=this.id,f.push(e))})});return f}})})(jQuery);
+(function(b){b.fn.jqm=function(a){var k={overlay:50,closeoverlay:!0,overlayClass:"jqmOverlay",closeClass:"jqmClose",trigger:".jqModal",ajax:d,ajaxText:"",target:d,modal:d,toTop:d,onShow:d,onHide:d,onLoad:d};return this.each(function(){if(this._jqm)return i[this._jqm].c=b.extend({},i[this._jqm].c,a);g++;this._jqm=g;i[g]={c:b.extend(k,b.jqm.params,a),a:d,w:b(this).addClass("jqmID"+g),s:g};k.trigger&&b(this).jqmAddTrigger(k.trigger)})};b.fn.jqmAddClose=function(a){return n(this,a,"jqmHide")};b.fn.jqmAddTrigger=
+function(a){return n(this,a,"jqmShow")};b.fn.jqmShow=function(a){return this.each(function(){b.jqm.open(this._jqm,a)})};b.fn.jqmHide=function(a){return this.each(function(){b.jqm.close(this._jqm,a)})};b.jqm={hash:{},open:function(a,k){var c=i[a],e=c.c,l="."+e.closeClass,h=parseInt(c.w.css("z-index")),h=0<h?h:3E3,f=b("<div></div>").css({height:"100%",width:"100%",position:"fixed",left:0,top:0,"z-index":h-1,opacity:e.overlay/100});if(c.a)return d;c.t=k;c.a=!0;c.w.css("z-index",h);e.modal?(j[0]||setTimeout(function(){o("bind")},
+1),j.push(a)):0<e.overlay?e.closeoverlay&&c.w.jqmAddClose(f):f=d;c.o=f?f.addClass(e.overlayClass).prependTo("body"):d;if(p&&(b("html,body").css({height:"100%",width:"100%"}),f)){var f=f.css({position:"absolute"})[0],g;for(g in{Top:1,Left:1})f.style.setExpression(g.toLowerCase(),"(_=(document.documentElement.scroll"+g+" || document.body.scroll"+g+"))+'px'")}e.ajax?(h=e.target||c.w,f=e.ajax,h="string"==typeof h?b(h,c.w):b(h),f="@"==f.substr(0,1)?b(k).attr(f.substring(1)):f,h.html(e.ajaxText).load(f,
+function(){e.onLoad&&e.onLoad.call(this,c);l&&c.w.jqmAddClose(b(l,c.w));q(c)})):l&&c.w.jqmAddClose(b(l,c.w));e.toTop&&c.o&&c.w.before('<span id="jqmP'+c.w[0]._jqm+'"></span>').insertAfter(c.o);e.onShow?e.onShow(c):c.w.show();q(c);return d},close:function(a){a=i[a];if(!a.a)return d;a.a=d;j[0]&&(j.pop(),j[0]||o("unbind"));a.c.toTop&&a.o&&b("#jqmP"+a.w[0]._jqm).after(a.w).remove();if(a.c.onHide)a.c.onHide(a);else a.w.hide(),a.o&&a.o.remove();return d},params:{}};var g=0,i=b.jqm.hash,j=[],p=b.browser.msie&&
+"6.0"==b.browser.version,d=!1,q=function(a){var d=b('<iframe src="javascript:false;document.write(\'\');" class="jqm"></iframe>').css({opacity:0});p&&(a.o?a.o.html('<p style="width:100%;height:100%"/>').prepend(d):b("iframe.jqm",a.w)[0]||a.w.prepend(d));r(a)},r=function(a){try{b(":input:visible",a.w)[0].focus()}catch(d){}},o=function(a){b(document)[a]("keypress",m)[a]("keydown",m)[a]("mousedown",m)},m=function(a){var d=i[j[j.length-1]];(a=!b(a.target).parents(".jqmID"+d.s)[0])&&r(d);return!a},n=function(a,
+g,c){return a.each(function(){var a=this._jqm;b(g).each(function(){this[c]||(this[c]=[],b(this).click(function(){for(var a in{jqmShow:1,jqmHide:1})for(var b in this[a])if(i[this[a][b]])i[this[a][b]].w[a](this);return d}));this[c].push(a)})})}})(jQuery);
+(function(b){b.fn.jqDrag=function(a){return h(this,a,"d")};b.fn.jqResize=function(a,b){return h(this,a,"r",b)};b.jqDnR={dnr:{},e:0,drag:function(a){"d"==d.k?e.css({left:d.X+a.pageX-d.pX,top:d.Y+a.pageY-d.pY}):(e.css({width:Math.max(a.pageX-d.pX+d.W,0),height:Math.max(a.pageY-d.pY+d.H,0)}),f&&g.css({width:Math.max(a.pageX-f.pX+f.W,0),height:Math.max(a.pageY-f.pY+f.H,0)}));return!1},stop:function(){b(document).unbind("mousemove",c.drag).unbind("mouseup",c.stop)}};var c=b.jqDnR,d=c.dnr,e=c.e,g,f,h=function(a,
+c,h,l){return a.each(function(){c=c?b(c,a):a;c.bind("mousedown",{e:a,k:h},function(a){var c=a.data,i={};e=c.e;g=l?b(l):!1;if("relative"!=e.css("position"))try{e.position(i)}catch(h){}d={X:i.left||j("left")||0,Y:i.top||j("top")||0,W:j("width")||e[0].scrollWidth||0,H:j("height")||e[0].scrollHeight||0,pX:a.pageX,pY:a.pageY,k:c.k};f=g&&"d"!=c.k?{X:i.left||k("left")||0,Y:i.top||k("top")||0,W:g[0].offsetWidth||k("width")||0,H:g[0].offsetHeight||k("height")||0,pX:a.pageX,pY:a.pageY,k:c.k}:!1;if(b("input.hasDatepicker",
+e[0])[0])try{b("input.hasDatepicker",e[0]).datepicker("hide")}catch(m){}b(document).mousemove(b.jqDnR.drag).mouseup(b.jqDnR.stop);return!1})})},j=function(a){return parseInt(e.css(a),10)||!1},k=function(a){return parseInt(g.css(a),10)||!1}})(jQuery);
+(function(b){b.jgrid.extend({setSubGrid:function(){return this.each(function(){var e;this.p.subGridOptions=b.extend({plusicon:"ui-icon-plus",minusicon:"ui-icon-minus",openicon:"ui-icon-carat-1-sw",expandOnLoad:!1,delayOnLoad:50,selectOnExpand:!1,reloadOnExpand:!0},this.p.subGridOptions||{});this.p.colNames.unshift("");this.p.colModel.unshift({name:"subgrid",width:b.browser.safari?this.p.subGridWidth+this.p.cellLayout:this.p.subGridWidth,sortable:!1,resizable:!1,hidedlg:!0,search:!1,fixed:!0});e=this.p.subGridModel;
+if(e[0]){e[0].align=b.extend([],e[0].align||[]);for(var c=0;c<e[0].name.length;c++)e[0].align[c]=e[0].align[c]||"left"}})},addSubGridCell:function(b,c){var a="",m,l;this.each(function(){a=this.formatCol(b,c);l=this.p.id;m=this.p.subGridOptions.plusicon});return'<td role="gridcell" aria-describedby="'+l+'_subgrid" class="ui-sgcollapsed sgcollapsed" '+a+"><a href='javascript:void(0);'><span class='ui-icon "+m+"'></span></a></td>"},addSubGrid:function(e,c){return this.each(function(){var a=this;if(a.grid){var m=
+function(c,e,h){e=b("<td align='"+a.p.subGridModel[0].align[h]+"'></td>").html(e);b(c).append(e)},l=function(c,e){var h,f,n,d=b("<table cellspacing='0' cellpadding='0' border='0'><tbody></tbody></table>"),i=b("<tr></tr>");for(f=0;f<a.p.subGridModel[0].name.length;f++)h=b("<th class='ui-state-default ui-th-subgrid ui-th-column ui-th-"+a.p.direction+"'></th>"),b(h).html(a.p.subGridModel[0].name[f]),b(h).width(a.p.subGridModel[0].width[f]),b(i).append(h);b(d).append(i);c&&(n=a.p.xmlReader.subgrid,b(n.root+
+" "+n.row,c).each(function(){i=b("<tr class='ui-widget-content ui-subtblcell'></tr>");if(!0===n.repeatitems)b(n.cell,this).each(function(a){m(i,b(this).text()||"&#160;",a)});else{var c=a.p.subGridModel[0].mapping||a.p.subGridModel[0].name;if(c)for(f=0;f<c.length;f++)m(i,b(c[f],this).text()||"&#160;",f)}b(d).append(i)}));h=b("table:first",a.grid.bDiv).attr("id")+"_";b("#"+b.jgrid.jqID(h+e)).append(d);a.grid.hDiv.loading=!1;b("#load_"+b.jgrid.jqID(a.p.id)).hide();return!1},p=function(c,e){var h,f,d,
+g,i,k=b("<table cellspacing='0' cellpadding='0' border='0'><tbody></tbody></table>"),j=b("<tr></tr>");for(f=0;f<a.p.subGridModel[0].name.length;f++)h=b("<th class='ui-state-default ui-th-subgrid ui-th-column ui-th-"+a.p.direction+"'></th>"),b(h).html(a.p.subGridModel[0].name[f]),b(h).width(a.p.subGridModel[0].width[f]),b(j).append(h);b(k).append(j);if(c&&(g=a.p.jsonReader.subgrid,h=c[g.root],"undefined"!==typeof h))for(f=0;f<h.length;f++){d=h[f];j=b("<tr class='ui-widget-content ui-subtblcell'></tr>");
+if(!0===g.repeatitems){g.cell&&(d=d[g.cell]);for(i=0;i<d.length;i++)m(j,d[i]||"&#160;",i)}else{var l=a.p.subGridModel[0].mapping||a.p.subGridModel[0].name;if(l.length)for(i=0;i<l.length;i++)m(j,d[l[i]]||"&#160;",i)}b(k).append(j)}f=b("table:first",a.grid.bDiv).attr("id")+"_";b("#"+b.jgrid.jqID(f+e)).append(k);a.grid.hDiv.loading=!1;b("#load_"+b.jgrid.jqID(a.p.id)).hide();return!1},t=function(c){var e,d,f,g;e=b(c).attr("id");d={nd_:(new Date).getTime()};d[a.p.prmNames.subgridid]=e;if(!a.p.subGridModel[0])return!1;
+if(a.p.subGridModel[0].params)for(g=0;g<a.p.subGridModel[0].params.length;g++)for(f=0;f<a.p.colModel.length;f++)a.p.colModel[f].name===a.p.subGridModel[0].params[g]&&(d[a.p.colModel[f].name]=b("td:eq("+f+")",c).text().replace(/\&#160\;/ig,""));if(!a.grid.hDiv.loading)switch(a.grid.hDiv.loading=!0,b("#load_"+b.jgrid.jqID(a.p.id)).show(),a.p.subgridtype||(a.p.subgridtype=a.p.datatype),b.isFunction(a.p.subgridtype)?a.p.subgridtype.call(a,d):a.p.subgridtype=a.p.subgridtype.toLowerCase(),a.p.subgridtype){case "xml":case "json":b.ajax(b.extend({type:a.p.mtype,
+url:a.p.subGridUrl,dataType:a.p.subgridtype,data:b.isFunction(a.p.serializeSubGridData)?a.p.serializeSubGridData.call(a,d):d,complete:function(c){a.p.subgridtype==="xml"?l(c.responseXML,e):p(b.jgrid.parse(c.responseText),e)}},b.jgrid.ajaxOptions,a.p.ajaxSubgridOptions||{}))}return!1},d,k,q,r=0,g,j;b.each(a.p.colModel,function(){(!0===this.hidden||"rn"===this.name||"cb"===this.name)&&r++});var s=a.rows.length,o=1;void 0!==c&&0<c&&(o=c,s=c+1);for(;o<s;)b(a.rows[o]).hasClass("jqgrow")&&b(a.rows[o].cells[e]).bind("click",
+function(){var c=b(this).parent("tr")[0];j=c.nextSibling;if(b(this).hasClass("sgcollapsed")){k=a.p.id;d=c.id;if(a.p.subGridOptions.reloadOnExpand===true||a.p.subGridOptions.reloadOnExpand===false&&!b(j).hasClass("ui-subgrid")){q=e>=1?"<td colspan='"+e+"'>&#160;</td>":"";g=b(a).triggerHandler("jqGridSubGridBeforeExpand",[k+"_"+d,d]);(g=g===false||g==="stop"?false:true)&&b.isFunction(a.p.subGridBeforeExpand)&&(g=a.p.subGridBeforeExpand.call(a,k+"_"+d,d));if(g===false)return false;b(c).after("<tr role='row' class='ui-subgrid'>"+
+q+"<td class='ui-widget-content subgrid-cell'><span class='ui-icon "+a.p.subGridOptions.openicon+"'></span></td><td colspan='"+parseInt(a.p.colNames.length-1-r,10)+"' class='ui-widget-content subgrid-data'><div id="+k+"_"+d+" class='tablediv'></div></td></tr>");b(a).triggerHandler("jqGridSubGridRowExpanded",[k+"_"+d,d]);b.isFunction(a.p.subGridRowExpanded)?a.p.subGridRowExpanded.call(a,k+"_"+d,d):t(c)}else b(j).show();b(this).html("<a href='javascript:void(0);'><span class='ui-icon "+a.p.subGridOptions.minusicon+
+"'></span></a>").removeClass("sgcollapsed").addClass("sgexpanded");a.p.subGridOptions.selectOnExpand&&b(a).jqGrid("setSelection",d)}else if(b(this).hasClass("sgexpanded")){g=b(a).triggerHandler("jqGridSubGridRowColapsed",[k+"_"+d,d]);if((g=g===false||g==="stop"?false:true)&&b.isFunction(a.p.subGridRowColapsed)){d=c.id;g=a.p.subGridRowColapsed.call(a,k+"_"+d,d)}if(g===false)return false;a.p.subGridOptions.reloadOnExpand===true?b(j).remove(".ui-subgrid"):b(j).hasClass("ui-subgrid")&&b(j).hide();b(this).html("<a href='javascript:void(0);'><span class='ui-icon "+
+a.p.subGridOptions.plusicon+"'></span></a>").removeClass("sgexpanded").addClass("sgcollapsed")}return false}),o++;!0===a.p.subGridOptions.expandOnLoad&&b(a.rows).filter(".jqgrow").each(function(a,c){b(c.cells[0]).click()});a.subGridXml=function(a,b){l(a,b)};a.subGridJson=function(a,b){p(a,b)}}})},expandSubGridRow:function(e){return this.each(function(){if((this.grid||e)&&!0===this.p.subGrid){var c=b(this).jqGrid("getInd",e,!0);c&&(c=b("td.sgcollapsed",c)[0])&&b(c).trigger("click")}})},collapseSubGridRow:function(e){return this.each(function(){if((this.grid||
+e)&&!0===this.p.subGrid){var c=b(this).jqGrid("getInd",e,!0);c&&(c=b("td.sgexpanded",c)[0])&&b(c).trigger("click")}})},toggleSubGridRow:function(e){return this.each(function(){if((this.grid||e)&&!0===this.p.subGrid){var c=b(this).jqGrid("getInd",e,!0);if(c){var a=b("td.sgcollapsed",c)[0];a?b(a).trigger("click"):(a=b("td.sgexpanded",c)[0])&&b(a).trigger("click")}}})}})})(jQuery);
+(function(b){b.extend(b.jgrid,{template:function(a){var d=b.makeArray(arguments).slice(1),e=1;void 0===a&&(a="");return a.replace(/\{([\w\-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,function(a,c){if(isNaN(parseInt(c,10))){for(var b=d[e],g=b.length;g--;)if(c===b[g].nm)return b[g].v;e++}else return e++,d[parseInt(c,10)]})}});b.jgrid.extend({groupingSetup:function(){return this.each(function(){var a=this.p.groupingView;if(null!==a&&("object"===typeof a||b.isFunction(a)))if(a.groupField.length){"undefined"===
+typeof a.visibiltyOnNextGrouping&&(a.visibiltyOnNextGrouping=[]);a.lastvalues=[];a.groups=[];a.counters=[];for(var d=0;d<a.groupField.length;d++)a.groupOrder[d]||(a.groupOrder[d]="asc"),a.groupText[d]||(a.groupText[d]="{0}"),"boolean"!==typeof a.groupColumnShow[d]&&(a.groupColumnShow[d]=!0),"boolean"!==typeof a.groupSummary[d]&&(a.groupSummary[d]=!1),!0===a.groupColumnShow[d]?(a.visibiltyOnNextGrouping[d]=!0,b(this).jqGrid("showCol",a.groupField[d])):(a.visibiltyOnNextGrouping[d]=b("#"+b.jgrid.jqID(this.p.id+
+"_"+a.groupField[d])).is(":visible"),b(this).jqGrid("hideCol",a.groupField[d]));a.summary=[];for(var d=this.p.colModel,e=0,f=d.length;e<f;e++)d[e].summaryType&&a.summary.push({nm:d[e].name,st:d[e].summaryType,v:"",sr:d[e].summaryRound,srt:d[e].summaryRoundType||"round"})}else this.p.grouping=!1;else this.p.grouping=!1})},groupingPrepare:function(a,d,e,f){this.each(function(){for(var c=this.p.groupingView,h=this,g=c.groupField.length,k,j,p=0,i=0;i<g;i++)k=c.groupField[i],j=e[k],void 0!==j&&(0===f?
+(c.groups.push({idx:i,dataIndex:k,value:j,startRow:f,cnt:1,summary:[]}),c.lastvalues[i]=j,c.counters[i]={cnt:1,pos:c.groups.length-1,summary:b.extend(!0,[],c.summary)}):"object"!==typeof j&&c.lastvalues[i]!==j?(c.groups.push({idx:i,dataIndex:k,value:j,startRow:f,cnt:1,summary:[]}),c.lastvalues[i]=j,p=1,c.counters[i]={cnt:1,pos:c.groups.length-1,summary:b.extend(!0,[],c.summary)}):1===p?(c.groups.push({idx:i,dataIndex:k,value:j,startRow:f,cnt:1,summary:[]}),c.lastvalues[i]=j,c.counters[i]={cnt:1,pos:c.groups.length-
+1,summary:b.extend(!0,[],c.summary)}):(c.counters[i].cnt+=1,c.groups[c.counters[i].pos].cnt=c.counters[i].cnt),b.each(c.counters[i].summary,function(){this.v=b.isFunction(this.st)?this.st.call(h,this.v,this.nm,e):b(h).jqGrid("groupingCalculations.handler",this.st,this.v,this.nm,this.sr,this.srt,e)}),c.groups[c.counters[i].pos].summary=c.counters[i].summary);d.push(a)});return d},groupingToggle:function(a){this.each(function(){var d=this.p.groupingView,e=a.split("_"),f=parseInt(e[e.length-2],10);e.splice(e.length-
+2,2);var e=e.join("_"),c=d.minusicon,h=d.plusicon,g=b("#"+b.jgrid.jqID(a)),g=g.length?g[0].nextSibling:null,k=b("#"+b.jgrid.jqID(a)+" span.tree-wrap-"+this.p.direction),j=!1;if(k.hasClass(c)){if(d.showSummaryOnHide){if(g)for(;g&&!b(g).hasClass("jqfoot");)b(g).hide(),g=g.nextSibling}else if(g)for(;g&&!b(g).hasClass(e+"_"+(""+f))&&!b(g).hasClass(e+"_"+(""+(f-1)));)b(g).hide(),g=g.nextSibling;k.removeClass(c).addClass(h);j=!0}else{if(g)for(;g&&!b(g).hasClass(e+"_"+(""+f))&&!b(g).hasClass(e+"_"+(""+(f-
+1)));)b(g).show(),g=g.nextSibling;k.removeClass(h).addClass(c)}b(this).triggerHandler("jqGridGroupingClickGroup",[a,j]);b.isFunction(this.p.onClickGroup)&&this.p.onClickGroup.call(this,a,j)});return!1},groupingRender:function(a,d){return this.each(function(){function e(a,c,b){if(0===c)return b[a];var d=b[a].idx;if(0===d)return b[a];for(;0<=a;a--)if(b[a].idx===d-c)return b[a]}var f=this,c=f.p.groupingView,h="",g="",k,j,p=c.groupCollapse?c.plusicon:c.minusicon,i,w=[],x=c.groupField.length,p=p+(" tree-wrap-"+
+f.p.direction);b.each(f.p.colModel,function(a,b){for(var d=0;d<x;d++)if(c.groupField[d]===b.name){w[d]=a;break}});var s=0,y=c.groupSummary;y.reverse();b.each(c.groups,function(r,l){s++;j=f.p.id+"ghead_"+l.idx;k=j+"_"+r;g="<span style='cursor:pointer;' class='ui-icon "+p+"' onclick=\"jQuery('#"+b.jgrid.jqID(f.p.id)+"').jqGrid('groupingToggle','"+k+"');return false;\"></span>";try{i=f.formatter(k,l.value,w[l.idx],l.value)}catch(C){i=l.value}h+='<tr id="'+k+'" role="row" class= "ui-widget-content jqgroup ui-row-'+
+f.p.direction+" "+j+'"><td style="padding-left:'+12*l.idx+'px;" colspan="'+d+'">'+g+b.jgrid.template(c.groupText[l.idx],i,l.cnt,l.summary)+"</td></tr>";if(x-1===l.idx){for(var m=c.groups[r+1],o=void 0!==m?c.groups[r+1].startRow:a.length,t=l.startRow;t<o;t++)h+=a[t].join("");var q;if(void 0!==m){for(q=0;q<c.groupField.length&&m.dataIndex!==c.groupField[q];q++);s=c.groupField.length-q}for(m=0;m<s;m++)if(y[m]){o="";c.groupCollapse&&!c.showSummaryOnHide&&(o=' style="display:none;"');h+="<tr"+o+' role="row" class="ui-widget-content jqfoot ui-row-'+
+f.p.direction+'">';for(var o=e(r,m,c.groups),u=f.p.colModel,v,z=o.cnt,n=0;n<d;n++){var A="<td "+f.formatCol(n,1,"")+">&#160;</td>",B="{0}";b.each(o.summary,function(){if(this.nm===u[n].name){u[n].summaryTpl&&(B=u[n].summaryTpl);"avg"===this.st.toLowerCase()&&(this.v&&0<z)&&(this.v/=z);try{v=f.formatter("",this.v,n,this)}catch(a){v=this.v}A="<td "+f.formatCol(n,1,"")+">"+b.jgrid.format(B,v)+"</td>";return!1}});h+=A}h+="</tr>"}s=q}});b("#"+b.jgrid.jqID(f.p.id)+" tbody:first").append(h);h=null})},groupingGroupBy:function(a,
+d){return this.each(function(){"string"===typeof a&&(a=[a]);var e=this.p.groupingView;this.p.grouping=!0;"undefined"===typeof e.visibiltyOnNextGrouping&&(e.visibiltyOnNextGrouping=[]);var f;for(f=0;f<e.groupField.length;f++)!e.groupColumnShow[f]&&e.visibiltyOnNextGrouping[f]&&b(this).jqGrid("showCol",e.groupField[f]);for(f=0;f<a.length;f++)e.visibiltyOnNextGrouping[f]=b("#"+b.jgrid.jqID(this.p.id)+"_"+b.jgrid.jqID(a[f])).is(":visible");this.p.groupingView=b.extend(this.p.groupingView,d||{});e.groupField=
+a;b(this).trigger("reloadGrid")})},groupingRemove:function(a){return this.each(function(){"undefined"===typeof a&&(a=!0);this.p.grouping=!1;if(!0===a){for(var d=this.p.groupingView,e=0;e<d.groupField.length;e++)!d.groupColumnShow[e]&&d.visibiltyOnNextGrouping[e]&&b(this).jqGrid("showCol",d.groupField);b("tr.jqgroup, tr.jqfoot","#"+b.jgrid.jqID(this.p.id)+" tbody:first").remove();b("tr.jqgrow:hidden","#"+b.jgrid.jqID(this.p.id)+" tbody:first").show()}else b(this).trigger("reloadGrid")})},groupingCalculations:{handler:function(a,
+b,e,f,c,h){var g={sum:function(){return parseFloat(b||0)+parseFloat(h[e]||0)},min:function(){return""===b?parseFloat(h[e]||0):Math.min(parseFloat(b),parseFloat(h[e]||0))},max:function(){return""===b?parseFloat(h[e]||0):Math.max(parseFloat(b),parseFloat(h[e]||0))},count:function(){""===b&&(b=0);return h.hasOwnProperty(e)?b+1:0},avg:function(){return g.sum()}};if(!g[a])throw"jqGrid Grouping No such method: "+a;a=g[a]();null!=f&&("fixed"==c?a=a.toFixed(f):(f=Math.pow(10,f),a=Math.round(a*f)/f));return a}}})})(jQuery);
+(function(d){d.jgrid.extend({setTreeNode:function(a,c){return this.each(function(){var b=this;if(b.grid&&b.p.treeGrid)for(var e=b.p.expColInd,g=b.p.treeReader.expanded_field,h=b.p.treeReader.leaf_field,f=b.p.treeReader.level_field,l=b.p.treeReader.icon_field,j=b.p.treeReader.loaded,i,p,m,k;a<c;)k=b.p.data[b.p._index[b.rows[a].id]],"nested"==b.p.treeGridModel&&!k[h]&&(i=parseInt(k[b.p.treeReader.left_field],10),p=parseInt(k[b.p.treeReader.right_field],10),k[h]=p===i+1?"true":"false",b.rows[a].cells[b.p._treeleafpos].innerHTML=
+k[h]),i=parseInt(k[f],10),0===b.p.tree_root_level?(m=i+1,p=i):(m=i,p=i-1),m="<div class='tree-wrap tree-wrap-"+b.p.direction+"' style='width:"+18*m+"px;'>",m+="<div style='"+("rtl"==b.p.direction?"right:":"left:")+18*p+"px;' class='ui-icon ",void 0!==k[j]&&(k[j]="true"==k[j]||!0===k[j]?!0:!1),"true"==k[h]||!0===k[h]?(m+=(void 0!==k[l]&&""!==k[l]?k[l]:b.p.treeIcons.leaf)+" tree-leaf treeclick",k[h]=!0,p="leaf"):(k[h]=!1,p=""),k[g]=("true"==k[g]||!0===k[g]?!0:!1)&&k[j],m=!1===k[g]?m+(!0===k[h]?"'":
+b.p.treeIcons.plus+" tree-plus treeclick'"):m+(!0===k[h]?"'":b.p.treeIcons.minus+" tree-minus treeclick'"),m+="></div></div>",d(b.rows[a].cells[e]).wrapInner("<span class='cell-wrapper"+p+"'></span>").prepend(m),i!==parseInt(b.p.tree_root_level,10)&&((k=(k=d(b).jqGrid("getNodeParent",k))&&k.hasOwnProperty(g)?k[g]:!0)||d(b.rows[a]).css("display","none")),d(b.rows[a].cells[e]).find("div.treeclick").bind("click",function(a){a=d(a.target||a.srcElement,b.rows).closest("tr.jqgrow")[0].id;a=b.p._index[a];
+if(!b.p.data[a][h])if(b.p.data[a][g]){d(b).jqGrid("collapseRow",b.p.data[a]);d(b).jqGrid("collapseNode",b.p.data[a])}else{d(b).jqGrid("expandRow",b.p.data[a]);d(b).jqGrid("expandNode",b.p.data[a])}return false}),!0===b.p.ExpandColClick&&d(b.rows[a].cells[e]).find("span.cell-wrapper").css("cursor","pointer").bind("click",function(a){var a=d(a.target||a.srcElement,b.rows).closest("tr.jqgrow")[0].id,c=b.p._index[a];if(!b.p.data[c][h])if(b.p.data[c][g]){d(b).jqGrid("collapseRow",b.p.data[c]);d(b).jqGrid("collapseNode",
+b.p.data[c])}else{d(b).jqGrid("expandRow",b.p.data[c]);d(b).jqGrid("expandNode",b.p.data[c])}d(b).jqGrid("setSelection",a);return false}),a++})},setTreeGrid:function(){return this.each(function(){var a=this,c=0,b,e=!1,g,h=[];if(a.p.treeGrid){a.p.treedatatype||d.extend(a.p,{treedatatype:a.p.datatype});a.p.subGrid=!1;a.p.altRows=!1;a.p.pgbuttons=!1;a.p.pginput=!1;a.p.gridview=!0;null===a.p.rowTotal&&(a.p.rowNum=1E4);a.p.multiselect=!1;a.p.rowList=[];a.p.expColInd=0;b="ui-icon-triangle-1-"+("rtl"==a.p.direction?
+"w":"e");a.p.treeIcons=d.extend({plus:b,minus:"ui-icon-triangle-1-s",leaf:"ui-icon-radio-off"},a.p.treeIcons||{});"nested"==a.p.treeGridModel?a.p.treeReader=d.extend({level_field:"level",left_field:"lft",right_field:"rgt",leaf_field:"isLeaf",expanded_field:"expanded",loaded:"loaded",icon_field:"icon"},a.p.treeReader):"adjacency"==a.p.treeGridModel&&(a.p.treeReader=d.extend({level_field:"level",parent_id_field:"parent",leaf_field:"isLeaf",expanded_field:"expanded",loaded:"loaded",icon_field:"icon"},
+a.p.treeReader));for(g in a.p.colModel)if(a.p.colModel.hasOwnProperty(g)){b=a.p.colModel[g].name;b==a.p.ExpandColumn&&!e&&(e=!0,a.p.expColInd=c);c++;for(var f in a.p.treeReader)a.p.treeReader[f]==b&&h.push(b)}d.each(a.p.treeReader,function(b,e){if(e&&d.inArray(e,h)===-1){if(b==="leaf_field")a.p._treeleafpos=c;c++;a.p.colNames.push(e);a.p.colModel.push({name:e,width:1,hidden:true,sortable:false,resizable:false,hidedlg:true,editable:true,search:false})}})}})},expandRow:function(a){this.each(function(){var c=
+this;if(c.grid&&c.p.treeGrid){var b=d(c).jqGrid("getNodeChildren",a),e=c.p.treeReader.expanded_field,g=c.rows;d(b).each(function(){var a=d.jgrid.getAccessor(this,c.p.localReader.id);d(g.namedItem(a)).css("display","");this[e]&&d(c).jqGrid("expandRow",this)})}})},collapseRow:function(a){this.each(function(){var c=this;if(c.grid&&c.p.treeGrid){var b=d(c).jqGrid("getNodeChildren",a),e=c.p.treeReader.expanded_field,g=c.rows;d(b).each(function(){var a=d.jgrid.getAccessor(this,c.p.localReader.id);d(g.namedItem(a)).css("display",
+"none");this[e]&&d(c).jqGrid("collapseRow",this)})}})},getRootNodes:function(){var a=[];this.each(function(){var c=this;if(c.grid&&c.p.treeGrid)switch(c.p.treeGridModel){case "nested":var b=c.p.treeReader.level_field;d(c.p.data).each(function(){parseInt(this[b],10)===parseInt(c.p.tree_root_level,10)&&a.push(this)});break;case "adjacency":var e=c.p.treeReader.parent_id_field;d(c.p.data).each(function(){(null===this[e]||"null"==(""+this[e]).toLowerCase())&&a.push(this)})}});return a},getNodeDepth:function(a){var c=
+null;this.each(function(){if(this.grid&&this.p.treeGrid)switch(this.p.treeGridModel){case "nested":c=parseInt(a[this.p.treeReader.level_field],10)-parseInt(this.p.tree_root_level,10);break;case "adjacency":c=d(this).jqGrid("getNodeAncestors",a).length}});return c},getNodeParent:function(a){var c=null;this.each(function(){if(this.grid&&this.p.treeGrid)switch(this.p.treeGridModel){case "nested":var b=this.p.treeReader.left_field,e=this.p.treeReader.right_field,g=this.p.treeReader.level_field,h=parseInt(a[b],
+10),f=parseInt(a[e],10),l=parseInt(a[g],10);d(this.p.data).each(function(){if(parseInt(this[g],10)===l-1&&parseInt(this[b],10)<h&&parseInt(this[e],10)>f)return c=this,!1});break;case "adjacency":var j=this.p.treeReader.parent_id_field,i=this.p.localReader.id;d(this.p.data).each(function(){if(this[i]==a[j])return c=this,!1})}});return c},getNodeChildren:function(a){var c=[];this.each(function(){if(this.grid&&this.p.treeGrid)switch(this.p.treeGridModel){case "nested":var b=this.p.treeReader.left_field,
+e=this.p.treeReader.right_field,g=this.p.treeReader.level_field,h=parseInt(a[b],10),f=parseInt(a[e],10),l=parseInt(a[g],10);d(this.p.data).each(function(){parseInt(this[g],10)===l+1&&(parseInt(this[b],10)>h&&parseInt(this[e],10)<f)&&c.push(this)});break;case "adjacency":var j=this.p.treeReader.parent_id_field,i=this.p.localReader.id;d(this.p.data).each(function(){this[j]==a[i]&&c.push(this)})}});return c},getFullTreeNode:function(a){var c=[];this.each(function(){var b;if(this.grid&&this.p.treeGrid)switch(this.p.treeGridModel){case "nested":var e=
+this.p.treeReader.left_field,g=this.p.treeReader.right_field,h=this.p.treeReader.level_field,f=parseInt(a[e],10),l=parseInt(a[g],10),j=parseInt(a[h],10);d(this.p.data).each(function(){parseInt(this[h],10)>=j&&(parseInt(this[e],10)>=f&&parseInt(this[e],10)<=l)&&c.push(this)});break;case "adjacency":if(a){c.push(a);var i=this.p.treeReader.parent_id_field,p=this.p.localReader.id;d(this.p.data).each(function(a){b=c.length;for(a=0;a<b;a++)if(c[a][p]==this[i]){c.push(this);break}})}}});return c},getNodeAncestors:function(a){var c=
+[];this.each(function(){if(this.grid&&this.p.treeGrid)for(var b=d(this).jqGrid("getNodeParent",a);b;)c.push(b),b=d(this).jqGrid("getNodeParent",b)});return c},isVisibleNode:function(a){var c=!0;this.each(function(){if(this.grid&&this.p.treeGrid){var b=d(this).jqGrid("getNodeAncestors",a),e=this.p.treeReader.expanded_field;d(b).each(function(){c=c&&this[e];if(!c)return!1})}});return c},isNodeLoaded:function(a){var c;this.each(function(){if(this.grid&&this.p.treeGrid){var b=this.p.treeReader.leaf_field;
+c=void 0!==a?void 0!==a.loaded?a.loaded:a[b]||0<d(this).jqGrid("getNodeChildren",a).length?!0:!1:!1}});return c},expandNode:function(a){return this.each(function(){if(this.grid&&this.p.treeGrid){var c=this.p.treeReader.expanded_field,b=this.p.treeReader.parent_id_field,e=this.p.treeReader.loaded,g=this.p.treeReader.level_field,h=this.p.treeReader.left_field,f=this.p.treeReader.right_field;if(!a[c]){var l=d.jgrid.getAccessor(a,this.p.localReader.id),j=d("#"+d.jgrid.jqID(l),this.grid.bDiv)[0],i=this.p._index[l];
+d(this).jqGrid("isNodeLoaded",this.p.data[i])?(a[c]=!0,d("div.treeclick",j).removeClass(this.p.treeIcons.plus+" tree-plus").addClass(this.p.treeIcons.minus+" tree-minus")):this.grid.hDiv.loading||(a[c]=!0,d("div.treeclick",j).removeClass(this.p.treeIcons.plus+" tree-plus").addClass(this.p.treeIcons.minus+" tree-minus"),this.p.treeANode=j.rowIndex,this.p.datatype=this.p.treedatatype,"nested"==this.p.treeGridModel?d(this).jqGrid("setGridParam",{postData:{nodeid:l,n_left:a[h],n_right:a[f],n_level:a[g]}}):
+d(this).jqGrid("setGridParam",{postData:{nodeid:l,parentid:a[b],n_level:a[g]}}),d(this).trigger("reloadGrid"),a[e]=!0,"nested"==this.p.treeGridModel?d(this).jqGrid("setGridParam",{postData:{nodeid:"",n_left:"",n_right:"",n_level:""}}):d(this).jqGrid("setGridParam",{postData:{nodeid:"",parentid:"",n_level:""}}))}}})},collapseNode:function(a){return this.each(function(){if(this.grid&&this.p.treeGrid){var c=this.p.treeReader.expanded_field;a[c]&&(a[c]=!1,c=d.jgrid.getAccessor(a,this.p.localReader.id),
+c=d("#"+d.jgrid.jqID(c),this.grid.bDiv)[0],d("div.treeclick",c).removeClass(this.p.treeIcons.minus+" tree-minus").addClass(this.p.treeIcons.plus+" tree-plus"))}})},SortTree:function(a,c,b,e){return this.each(function(){if(this.grid&&this.p.treeGrid){var g,h,f,l=[],j=this,i;g=d(this).jqGrid("getRootNodes");g=d.jgrid.from(g);g.orderBy(a,c,b,e);i=g.select();g=0;for(h=i.length;g<h;g++)f=i[g],l.push(f),d(this).jqGrid("collectChildrenSortTree",l,f,a,c,b,e);d.each(l,function(a){var b=d.jgrid.getAccessor(this,
+j.p.localReader.id);d("#"+d.jgrid.jqID(j.p.id)+" tbody tr:eq("+a+")").after(d("tr#"+d.jgrid.jqID(b),j.grid.bDiv))});l=i=g=null}})},collectChildrenSortTree:function(a,c,b,e,g,h){return this.each(function(){if(this.grid&&this.p.treeGrid){var f,l,j,i;f=d(this).jqGrid("getNodeChildren",c);f=d.jgrid.from(f);f.orderBy(b,e,g,h);i=f.select();f=0;for(l=i.length;f<l;f++)j=i[f],a.push(j),d(this).jqGrid("collectChildrenSortTree",a,j,b,e,g,h)}})},setTreeRow:function(a,c){var b=!1;this.each(function(){this.grid&&
+this.p.treeGrid&&(b=d(this).jqGrid("setRowData",a,c))});return b},delTreeNode:function(a){return this.each(function(){var c=this.p.localReader.id,b=this.p.treeReader.left_field,e=this.p.treeReader.right_field,g,h,f;if(this.grid&&this.p.treeGrid){var l=this.p._index[a];if(void 0!==l){g=parseInt(this.p.data[l][e],10);h=g-parseInt(this.p.data[l][b],10)+1;l=d(this).jqGrid("getFullTreeNode",this.p.data[l]);if(0<l.length)for(var j=0;j<l.length;j++)d(this).jqGrid("delRowData",l[j][c]);if("nested"===this.p.treeGridModel){c=
+d.jgrid.from(this.p.data).greater(b,g,{stype:"integer"}).select();if(c.length)for(f in c)c.hasOwnProperty(f)&&(c[f][b]=parseInt(c[f][b],10)-h);c=d.jgrid.from(this.p.data).greater(e,g,{stype:"integer"}).select();if(c.length)for(f in c)c.hasOwnProperty(f)&&(c[f][e]=parseInt(c[f][e],10)-h)}}}})},addChildNode:function(a,c,b){var e=this[0];if(b){var g=e.p.treeReader.expanded_field,h=e.p.treeReader.leaf_field,f=e.p.treeReader.level_field,l=e.p.treeReader.parent_id_field,j=e.p.treeReader.left_field,i=e.p.treeReader.right_field,
+p=e.p.treeReader.loaded,m,k,q,s,o;m=0;var r=c,t;if("undefined"===typeof a||null===a){o=e.p.data.length-1;if(0<=o)for(;0<=o;)m=Math.max(m,parseInt(e.p.data[o][e.p.localReader.id],10)),o--;a=m+1}var u=d(e).jqGrid("getInd",c);t=!1;if(void 0===c||null===c||""===c)r=c=null,m="last",s=e.p.tree_root_level,o=e.p.data.length+1;else if(m="after",k=e.p._index[c],q=e.p.data[k],c=q[e.p.localReader.id],s=parseInt(q[f],10)+1,o=d(e).jqGrid("getFullTreeNode",q),o.length?(r=o=o[o.length-1][e.p.localReader.id],o=d(e).jqGrid("getInd",
+r)+1):o=d(e).jqGrid("getInd",c)+1,q[h])t=!0,q[g]=!0,d(e.rows[u]).find("span.cell-wrapperleaf").removeClass("cell-wrapperleaf").addClass("cell-wrapper").end().find("div.tree-leaf").removeClass(e.p.treeIcons.leaf+" tree-leaf").addClass(e.p.treeIcons.minus+" tree-minus"),e.p.data[k][h]=!1,q[p]=!0;k=o+1;b[g]=!1;b[p]=!0;b[f]=s;b[h]=!0;"adjacency"===e.p.treeGridModel&&(b[l]=c);if("nested"===e.p.treeGridModel){var n;if(null!==c){h=parseInt(q[i],10);f=d.jgrid.from(e.p.data);f=f.greaterOrEquals(i,h,{stype:"integer"});
+f=f.select();if(f.length)for(n in f)f.hasOwnProperty(n)&&(f[n][j]=f[n][j]>h?parseInt(f[n][j],10)+2:f[n][j],f[n][i]=f[n][i]>=h?parseInt(f[n][i],10)+2:f[n][i]);b[j]=h;b[i]=h+1}else{h=parseInt(d(e).jqGrid("getCol",i,!1,"max"),10);f=d.jgrid.from(e.p.data).greater(j,h,{stype:"integer"}).select();if(f.length)for(n in f)f.hasOwnProperty(n)&&(f[n][j]=parseInt(f[n][j],10)+2);f=d.jgrid.from(e.p.data).greater(i,h,{stype:"integer"}).select();if(f.length)for(n in f)f.hasOwnProperty(n)&&(f[n][i]=parseInt(f[n][i],
+10)+2);b[j]=h+1;b[i]=h+2}}if(null===c||d(e).jqGrid("isNodeLoaded",q)||t)d(e).jqGrid("addRowData",a,b,m,r),d(e).jqGrid("setTreeNode",o,k);q&&!q[g]&&d(e.rows[u]).find("div.treeclick").click()}}})})(jQuery);
+(function(c){c.jgrid.extend({jqGridImport:function(a){a=c.extend({imptype:"xml",impstring:"",impurl:"",mtype:"GET",impData:{},xmlGrid:{config:"roots>grid",data:"roots>rows"},jsonGrid:{config:"grid",data:"data"},ajaxOptions:{}},a||{});return this.each(function(){var d=this,b=function(a,b){var e=c(b.xmlGrid.config,a)[0],h=c(b.xmlGrid.data,a)[0],f;if(xmlJsonClass.xml2json&&c.jgrid.parse){var e=xmlJsonClass.xml2json(e," "),e=c.jgrid.parse(e),g;for(g in e)e.hasOwnProperty(g)&&(f=e[g]);h?(h=e.grid.datatype,
+e.grid.datatype="xmlstring",e.grid.datastr=a,c(d).jqGrid(f).jqGrid("setGridParam",{datatype:h})):c(d).jqGrid(f)}else alert("xml2json or parse are not present")},g=function(a,b){if(a&&"string"==typeof a){var e=!1;c.jgrid.useJSON&&(c.jgrid.useJSON=!1,e=!0);var f=c.jgrid.parse(a);e&&(c.jgrid.useJSON=!0);e=f[b.jsonGrid.config];if(f=f[b.jsonGrid.data]){var g=e.datatype;e.datatype="jsonstring";e.datastr=f;c(d).jqGrid(e).jqGrid("setGridParam",{datatype:g})}else c(d).jqGrid(e)}};switch(a.imptype){case "xml":c.ajax(c.extend({url:a.impurl,
+type:a.mtype,data:a.impData,dataType:"xml",complete:function(f,g){"success"==g&&(b(f.responseXML,a),c(d).triggerHandler("jqGridImportComplete",[f,a]),c.isFunction(a.importComplete)&&a.importComplete(f))}},a.ajaxOptions));break;case "xmlstring":if(a.impstring&&"string"==typeof a.impstring){var f=c.jgrid.stringToDoc(a.impstring);f&&(b(f,a),c(d).triggerHandler("jqGridImportComplete",[f,a]),c.isFunction(a.importComplete)&&a.importComplete(f),a.impstring=null);f=null}break;case "json":c.ajax(c.extend({url:a.impurl,
+type:a.mtype,data:a.impData,dataType:"json",complete:function(b){try{g(b.responseText,a),c(d).triggerHandler("jqGridImportComplete",[b,a]),c.isFunction(a.importComplete)&&a.importComplete(b)}catch(f){}}},a.ajaxOptions));break;case "jsonstring":a.impstring&&"string"==typeof a.impstring&&(g(a.impstring,a),c(d).triggerHandler("jqGridImportComplete",[a.impstring,a]),c.isFunction(a.importComplete)&&a.importComplete(a.impstring),a.impstring=null)}})},jqGridExport:function(a){var a=c.extend({exptype:"xmlstring",
+root:"grid",ident:"\t"},a||{}),d=null;this.each(function(){if(this.grid){var b=c.extend(!0,{},c(this).jqGrid("getGridParam"));b.rownumbers&&(b.colNames.splice(0,1),b.colModel.splice(0,1));b.multiselect&&(b.colNames.splice(0,1),b.colModel.splice(0,1));b.subGrid&&(b.colNames.splice(0,1),b.colModel.splice(0,1));b.knv=null;if(b.treeGrid)for(var g in b.treeReader)b.treeReader.hasOwnProperty(g)&&(b.colNames.splice(b.colNames.length-1),b.colModel.splice(b.colModel.length-1));switch(a.exptype){case "xmlstring":d=
+"<"+a.root+">"+xmlJsonClass.json2xml(b,a.ident)+"</"+a.root+">";break;case "jsonstring":d="{"+xmlJsonClass.toJson(b,a.root,a.ident,!1)+"}",void 0!==b.postData.filters&&(d=d.replace(/filters":"/,'filters":'),d=d.replace(/}]}"/,"}]}"))}}});return d},excelExport:function(a){a=c.extend({exptype:"remote",url:null,oper:"oper",tag:"excel",exportOptions:{}},a||{});return this.each(function(){if(this.grid){var d;"remote"==a.exptype&&(d=c.extend({},this.p.postData),d[a.oper]=a.tag,d=jQuery.param(d),d=-1!=a.url.indexOf("?")?
+a.url+"&"+d:a.url+"?"+d,window.location=d)}})}})})(jQuery);
+var xmlJsonClass={xml2json:function(a,b){9===a.nodeType&&(a=a.documentElement);var g=this.toJson(this.toObj(this.removeWhite(a)),a.nodeName,"\t");return"{\n"+b+(b?g.replace(/\t/g,b):g.replace(/\t|\n/g,""))+"\n}"},json2xml:function(a,b){var g=function(a,b,e){var d="",f,i;if(a instanceof Array)if(0===a.length)d+=e+"<"+b+">__EMPTY_ARRAY_</"+b+">\n";else{f=0;for(i=a.length;f<i;f+=1)var l=e+g(a[f],b,e+"\t")+"\n",d=d+l}else if("object"===typeof a){f=!1;d+=e+"<"+b;for(i in a)a.hasOwnProperty(i)&&("@"===
+i.charAt(0)?d+=" "+i.substr(1)+'="'+a[i].toString()+'"':f=!0);d+=f?">":"/>";if(f){for(i in a)a.hasOwnProperty(i)&&("#text"===i?d+=a[i]:"#cdata"===i?d+="<![CDATA["+a[i]+"]]\>":"@"!==i.charAt(0)&&(d+=g(a[i],i,e+"\t")));d+=("\n"===d.charAt(d.length-1)?e:"")+"</"+b+">"}}else"function"===typeof a?d+=e+"<"+b+"><![CDATA["+a+"]]\></"+b+">":(void 0===a&&(a=""),d='""'===a.toString()||0===a.toString().length?d+(e+"<"+b+">__EMPTY_STRING_</"+b+">"):d+(e+"<"+b+">"+a.toString()+"</"+b+">"));return d},f="",e;for(e in a)a.hasOwnProperty(e)&&
+(f+=g(a[e],e,""));return b?f.replace(/\t/g,b):f.replace(/\t|\n/g,"")},toObj:function(a){var b={},g=/function/i;if(1===a.nodeType){if(a.attributes.length){var f;for(f=0;f<a.attributes.length;f+=1)b["@"+a.attributes[f].nodeName]=(a.attributes[f].nodeValue||"").toString()}if(a.firstChild){var e=f=0,h=!1,c;for(c=a.firstChild;c;c=c.nextSibling)1===c.nodeType?h=!0:3===c.nodeType&&c.nodeValue.match(/[^ \f\n\r\t\v]/)?f+=1:4===c.nodeType&&(e+=1);if(h)if(2>f&&2>e){this.removeWhite(a);for(c=a.firstChild;c;c=
+c.nextSibling)3===c.nodeType?b["#text"]=this.escape(c.nodeValue):4===c.nodeType?g.test(c.nodeValue)?b[c.nodeName]=[b[c.nodeName],c.nodeValue]:b["#cdata"]=this.escape(c.nodeValue):b[c.nodeName]?b[c.nodeName]instanceof Array?b[c.nodeName][b[c.nodeName].length]=this.toObj(c):b[c.nodeName]=[b[c.nodeName],this.toObj(c)]:b[c.nodeName]=this.toObj(c)}else a.attributes.length?b["#text"]=this.escape(this.innerXml(a)):b=this.escape(this.innerXml(a));else if(f)a.attributes.length?b["#text"]=this.escape(this.innerXml(a)):
+(b=this.escape(this.innerXml(a)),"__EMPTY_ARRAY_"===b?b="[]":"__EMPTY_STRING_"===b&&(b=""));else if(e)if(1<e)b=this.escape(this.innerXml(a));else for(c=a.firstChild;c;c=c.nextSibling)if(g.test(a.firstChild.nodeValue)){b=a.firstChild.nodeValue;break}else b["#cdata"]=this.escape(c.nodeValue)}!a.attributes.length&&!a.firstChild&&(b=null)}else 9===a.nodeType?b=this.toObj(a.documentElement):alert("unhandled node type: "+a.nodeType);return b},toJson:function(a,b,g,f){void 0===f&&(f=!0);var e=b?'"'+b+'"':
+"",h="\t",c="\n";f||(c=h="");if("[]"===a)e+=b?":[]":"[]";else if(a instanceof Array){var j,d,k=[];d=0;for(j=a.length;d<j;d+=1)k[d]=this.toJson(a[d],"",g+h,f);e+=(b?":[":"[")+(1<k.length?c+g+h+k.join(","+c+g+h)+c+g:k.join(""))+"]"}else if(null===a)e+=(b&&":")+"null";else if("object"===typeof a){j=[];for(d in a)a.hasOwnProperty(d)&&(j[j.length]=this.toJson(a[d],d,g+h,f));e+=(b?":{":"{")+(1<j.length?c+g+h+j.join(","+c+g+h)+c+g:j.join(""))+"}"}else e="string"===typeof a?e+((b&&":")+'"'+a.replace(/\\/g,
+"\\\\").replace(/\"/g,'\\"')+'"'):e+((b&&":")+a.toString());return e},innerXml:function(a){var b="";if("innerHTML"in a)b=a.innerHTML;else for(var g=function(a){var b="",h;if(1===a.nodeType){b+="<"+a.nodeName;for(h=0;h<a.attributes.length;h+=1)b+=" "+a.attributes[h].nodeName+'="'+(a.attributes[h].nodeValue||"").toString()+'"';if(a.firstChild){b+=">";for(h=a.firstChild;h;h=h.nextSibling)b+=g(h);b+="</"+a.nodeName+">"}else b+="/>"}else 3===a.nodeType?b+=a.nodeValue:4===a.nodeType&&(b+="<![CDATA["+a.nodeValue+
+"]]\>");return b},a=a.firstChild;a;a=a.nextSibling)b+=g(a);return b},escape:function(a){return a.replace(/[\\]/g,"\\\\").replace(/[\"]/g,'\\"').replace(/[\n]/g,"\\n").replace(/[\r]/g,"\\r")},removeWhite:function(a){a.normalize();var b;for(b=a.firstChild;b;)if(3===b.nodeType)if(b.nodeValue.match(/[^ \f\n\r\t\v]/))b=b.nextSibling;else{var g=b.nextSibling;a.removeChild(b);b=g}else 1===b.nodeType&&this.removeWhite(b),b=b.nextSibling;return a}};
+function tableToGrid(j,k){jQuery(j).each(function(){if(!this.grid){jQuery(this).width("99%");var b=jQuery(this).width(),c=jQuery("tr td:first-child input[type=checkbox]:first",jQuery(this)),a=jQuery("tr td:first-child input[type=radio]:first",jQuery(this)),c=0<c.length,a=!c&&0<a.length,i=c||a,d=[],e=[];jQuery("th",jQuery(this)).each(function(){0===d.length&&i?(d.push({name:"__selection__",index:"__selection__",width:0,hidden:!0}),e.push("__selection__")):(d.push({name:jQuery(this).attr("id")||jQuery.trim(jQuery.jgrid.stripHtml(jQuery(this).html())).split(" ").join("_"),
+index:jQuery(this).attr("id")||jQuery.trim(jQuery.jgrid.stripHtml(jQuery(this).html())).split(" ").join("_"),width:jQuery(this).width()||150}),e.push(jQuery(this).html()))});var f=[],g=[],h=[];jQuery("tbody > tr",jQuery(this)).each(function(){var b={},a=0;jQuery("td",jQuery(this)).each(function(){if(0===a&&i){var c=jQuery("input",jQuery(this)),e=c.attr("value");g.push(e||f.length);c.is(":checked")&&h.push(e);b[d[a].name]=c.attr("value")}else b[d[a].name]=jQuery(this).html();a++});0<a&&f.push(b)});
+jQuery(this).empty();jQuery(this).addClass("scroll");jQuery(this).jqGrid(jQuery.extend({datatype:"local",width:b,colNames:e,colModel:d,multiselect:c},k||{}));for(b=0;b<f.length;b++)a=null,0<g.length&&(a=g[b])&&a.replace&&(a=encodeURIComponent(a).replace(/[.\-%]/g,"_")),null===a&&(a=b+1),jQuery(this).jqGrid("addRowData",a,f[b]);for(b=0;b<h.length;b++)jQuery(this).jqGrid("setSelection",h[b])}})};
+(function(b){b.browser.msie&&8==b.browser.version&&(b.expr[":"].hidden=function(b){return 0===b.offsetWidth||0===b.offsetHeight||"none"==b.style.display});b.jgrid._multiselect=!1;if(b.ui&&b.ui.multiselect){if(b.ui.multiselect.prototype._setSelected){var m=b.ui.multiselect.prototype._setSelected;b.ui.multiselect.prototype._setSelected=function(a,e){var c=m.call(this,a,e);if(e&&this.selectedList){var d=this.element;this.selectedList.find("li").each(function(){b(this).data("optionLink")&&b(this).data("optionLink").remove().appendTo(d)})}return c}}b.ui.multiselect.prototype.destroy&&
+(b.ui.multiselect.prototype.destroy=function(){this.element.show();this.container.remove();b.Widget===void 0?b.widget.prototype.destroy.apply(this,arguments):b.Widget.prototype.destroy.apply(this,arguments)});b.jgrid._multiselect=!0}b.jgrid.extend({sortableColumns:function(a){return this.each(function(){function e(){c.p.disableClick=true}var c=this,d=b.jgrid.jqID(c.p.id),d={tolerance:"pointer",axis:"x",scrollSensitivity:"1",items:">th:not(:has(#jqgh_"+d+"_cb,#jqgh_"+d+"_rn,#jqgh_"+d+"_subgrid),:hidden)",
+placeholder:{element:function(a){return b(document.createElement(a[0].nodeName)).addClass(a[0].className+" ui-sortable-placeholder ui-state-highlight").removeClass("ui-sortable-helper")[0]},update:function(b,a){a.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));a.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}},update:function(a,
+g){var d=b(g.item).parent(),d=b(">th",d),e={},i=c.p.id+"_";b.each(c.p.colModel,function(b){e[this.name]=b});var h=[];d.each(function(){var a=b(">div",this).get(0).id.replace(/^jqgh_/,"").replace(i,"");a in e&&h.push(e[a])});b(c).jqGrid("remapColumns",h,true,true);b.isFunction(c.p.sortable.update)&&c.p.sortable.update(h);setTimeout(function(){c.p.disableClick=false},50)}};if(c.p.sortable.options)b.extend(d,c.p.sortable.options);else if(b.isFunction(c.p.sortable))c.p.sortable={update:c.p.sortable};
+if(d.start){var g=d.start;d.start=function(b,a){e();g.call(this,b,a)}}else d.start=e;if(c.p.sortable.exclude)d.items=d.items+(":not("+c.p.sortable.exclude+")");a.sortable(d).data("sortable").floating=true})},columnChooser:function(a){function e(a,c){a&&(typeof a=="string"?b.fn[a]&&b.fn[a].apply(c,b.makeArray(arguments).slice(2)):b.isFunction(a)&&a.apply(c,b.makeArray(arguments).slice(2)))}var c=this;if(!b("#colchooser_"+b.jgrid.jqID(c[0].p.id)).length){var d=b('<div id="colchooser_'+c[0].p.id+'" style="position:relative;overflow:hidden"><div><select multiple="multiple"></select></div></div>'),
+g=b("select",d),a=b.extend({width:420,height:240,classname:null,done:function(b){b&&c.jqGrid("remapColumns",b,true)},msel:"multiselect",dlog:"dialog",dialog_opts:{minWidth:470},dlog_opts:function(a){var c={};c[a.bSubmit]=function(){a.apply_perm();a.cleanup(false)};c[a.bCancel]=function(){a.cleanup(true)};return b.extend(true,{buttons:c,close:function(){a.cleanup(true)},modal:a.modal?a.modal:false,resizable:a.resizable?a.resizable:true,width:a.width+20},a.dialog_opts||{})},apply_perm:function(){b("option",
+g).each(function(){this.selected?c.jqGrid("showCol",k[this.value].name):c.jqGrid("hideCol",k[this.value].name)});var d=[];b("option:selected",g).each(function(){d.push(parseInt(this.value,10))});b.each(d,function(){delete f[k[parseInt(this,10)].name]});b.each(f,function(){var b=parseInt(this,10);var a=d,c=b;if(c>=0){var g=a.slice(),e=g.splice(c,Math.max(a.length-c,c));if(c>a.length)c=a.length;g[c]=b;d=g.concat(e)}else d=void 0});a.done&&a.done.call(c,d)},cleanup:function(b){e(a.dlog,d,"destroy");
+e(a.msel,g,"destroy");d.remove();b&&a.done&&a.done.call(c)},msel_opts:{}},b.jgrid.col,a||{});if(b.ui&&b.ui.multiselect&&a.msel=="multiselect"){if(!b.jgrid._multiselect){alert("Multiselect plugin loaded after jqGrid. Please load the plugin before the jqGrid!");return}a.msel_opts=b.extend(b.ui.multiselect.defaults,a.msel_opts)}a.caption&&d.attr("title",a.caption);if(a.classname){d.addClass(a.classname);g.addClass(a.classname)}if(a.width){b(">div",d).css({width:a.width,margin:"0 auto"});g.css("width",
+a.width)}if(a.height){b(">div",d).css("height",a.height);g.css("height",a.height-10)}var k=c.jqGrid("getGridParam","colModel"),p=c.jqGrid("getGridParam","colNames"),f={},j=[];g.empty();b.each(k,function(b){f[this.name]=b;this.hidedlg?this.hidden||j.push(b):g.append("<option value='"+b+"' "+(this.hidden?"":"selected='selected'")+">"+jQuery.jgrid.stripHtml(p[b])+"</option>")});var i=b.isFunction(a.dlog_opts)?a.dlog_opts.call(c,a):a.dlog_opts;e(a.dlog,d,i);i=b.isFunction(a.msel_opts)?a.msel_opts.call(c,
+a):a.msel_opts;e(a.msel,g,i)}},sortableRows:function(a){return this.each(function(){var e=this;if(e.grid&&!e.p.treeGrid&&b.fn.sortable){a=b.extend({cursor:"move",axis:"y",items:".jqgrow"},a||{});if(a.start&&b.isFunction(a.start)){a._start_=a.start;delete a.start}else a._start_=false;if(a.update&&b.isFunction(a.update)){a._update_=a.update;delete a.update}else a._update_=false;a.start=function(c,d){b(d.item).css("border-width","0px");b("td",d.item).each(function(b){this.style.width=e.grid.cols[b].style.width});
+if(e.p.subGrid){var g=b(d.item).attr("id");try{b(e).jqGrid("collapseSubGridRow",g)}catch(k){}}a._start_&&a._start_.apply(this,[c,d])};a.update=function(c,d){b(d.item).css("border-width","");e.p.rownumbers===true&&b("td.jqgrid-rownum",e.rows).each(function(a){b(this).html(a+1+(parseInt(e.p.page,10)-1)*parseInt(e.p.rowNum,10))});a._update_&&a._update_.apply(this,[c,d])};b("tbody:first",e).sortable(a);b("tbody:first",e).disableSelection()}})},gridDnD:function(a){return this.each(function(){function e(){var a=
+b.data(c,"dnd");b("tr.jqgrow:not(.ui-draggable)",c).draggable(b.isFunction(a.drag)?a.drag.call(b(c),a):a.drag)}var c=this;if(c.grid&&!c.p.treeGrid&&b.fn.draggable&&b.fn.droppable){b("#jqgrid_dnd").html()===null&&b("body").append("<table id='jqgrid_dnd' class='ui-jqgrid-dnd'></table>");if(typeof a=="string"&&a=="updateDnD"&&c.p.jqgdnd===true)e();else{a=b.extend({drag:function(a){return b.extend({start:function(d,e){if(c.p.subGrid){var f=b(e.helper).attr("id");try{b(c).jqGrid("collapseSubGridRow",f)}catch(j){}}for(f=
+0;f<b.data(c,"dnd").connectWith.length;f++)b(b.data(c,"dnd").connectWith[f]).jqGrid("getGridParam","reccount")=="0"&&b(b.data(c,"dnd").connectWith[f]).jqGrid("addRowData","jqg_empty_row",{});e.helper.addClass("ui-state-highlight");b("td",e.helper).each(function(b){this.style.width=c.grid.headers[b].width+"px"});a.onstart&&b.isFunction(a.onstart)&&a.onstart.call(b(c),d,e)},stop:function(d,e){if(e.helper.dropped&&!a.dragcopy){var f=b(e.helper).attr("id");f===void 0&&(f=b(this).attr("id"));b(c).jqGrid("delRowData",
+f)}for(f=0;f<b.data(c,"dnd").connectWith.length;f++)b(b.data(c,"dnd").connectWith[f]).jqGrid("delRowData","jqg_empty_row");a.onstop&&b.isFunction(a.onstop)&&a.onstop.call(b(c),d,e)}},a.drag_opts||{})},drop:function(a){return b.extend({accept:function(a){if(!b(a).hasClass("jqgrow"))return a;a=b(a).closest("table.ui-jqgrid-btable");if(a.length>0&&b.data(a[0],"dnd")!==void 0){a=b.data(a[0],"dnd").connectWith;return b.inArray("#"+b.jgrid.jqID(this.id),a)!=-1?true:false}return false},drop:function(d,e){if(b(e.draggable).hasClass("jqgrow")){var f=
+b(e.draggable).attr("id"),f=e.draggable.parent().parent().jqGrid("getRowData",f);if(!a.dropbyname){var j=0,i={},h,n=b("#"+b.jgrid.jqID(this.id)).jqGrid("getGridParam","colModel");try{for(var o in f){h=n[j].name;h=="cb"||(h=="rn"||h=="subgrid")||f.hasOwnProperty(o)&&n[j]&&(i[h]=f[o]);j++}f=i}catch(m){}}e.helper.dropped=true;if(a.beforedrop&&b.isFunction(a.beforedrop)){h=a.beforedrop.call(this,d,e,f,b("#"+b.jgrid.jqID(c.p.id)),b(this));typeof h!="undefined"&&(h!==null&&typeof h=="object")&&(f=h)}if(e.helper.dropped){var l;
+if(a.autoid)if(b.isFunction(a.autoid))l=a.autoid.call(this,f);else{l=Math.ceil(Math.random()*1E3);l=a.autoidprefix+l}b("#"+b.jgrid.jqID(this.id)).jqGrid("addRowData",l,f,a.droppos)}a.ondrop&&b.isFunction(a.ondrop)&&a.ondrop.call(this,d,e,f)}}},a.drop_opts||{})},onstart:null,onstop:null,beforedrop:null,ondrop:null,drop_opts:{activeClass:"ui-state-active",hoverClass:"ui-state-hover"},drag_opts:{revert:"invalid",helper:"clone",cursor:"move",appendTo:"#jqgrid_dnd",zIndex:5E3},dragcopy:false,dropbyname:false,
+droppos:"first",autoid:true,autoidprefix:"dnd_"},a||{});if(a.connectWith){a.connectWith=a.connectWith.split(",");a.connectWith=b.map(a.connectWith,function(a){return b.trim(a)});b.data(c,"dnd",a);c.p.reccount!="0"&&!c.p.jqgdnd&&e();c.p.jqgdnd=true;for(var d=0;d<a.connectWith.length;d++)b(a.connectWith[d]).droppable(b.isFunction(a.drop)?a.drop.call(b(c),a):a.drop)}}}})},gridResize:function(a){return this.each(function(){var e=this,c=b.jgrid.jqID(e.p.id);if(e.grid&&b.fn.resizable){a=b.extend({},a||
+{});if(a.alsoResize){a._alsoResize_=a.alsoResize;delete a.alsoResize}else a._alsoResize_=false;if(a.stop&&b.isFunction(a.stop)){a._stop_=a.stop;delete a.stop}else a._stop_=false;a.stop=function(d,g){b(e).jqGrid("setGridParam",{height:b("#gview_"+c+" .ui-jqgrid-bdiv").height()});b(e).jqGrid("setGridWidth",g.size.width,a.shrinkToFit);a._stop_&&a._stop_.call(e,d,g)};a.alsoResize=a._alsoResize_?eval("("+("{'#gview_"+c+" .ui-jqgrid-bdiv':true,'"+a._alsoResize_+"':true}")+")"):b(".ui-jqgrid-bdiv","#gview_"+
+c);delete a._alsoResize_;b("#gbox_"+c).resizable(a)}})}})})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/jqgrid/ui.jqgrid.css b/SemanticResultFormats/resources/jquery/jqgrid/ui.jqgrid.css
new file mode 100644
index 00000000..c0801ae6
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqgrid/ui.jqgrid.css
@@ -0,0 +1,144 @@
+/*Grid*/
+.ui-jqgrid {position: relative;}
+.ui-jqgrid .ui-jqgrid-view {position: relative;left:0px; top: 0px; padding: .0em; font-size:11px;}
+/* caption*/
+.ui-jqgrid .ui-jqgrid-titlebar {padding: .3em .2em .2em .3em; position: relative; border-left: 0px none;border-right: 0px none; border-top: 0px none;}
+.ui-jqgrid .ui-jqgrid-title { float: left; margin: .1em 0 .2em; }
+.ui-jqgrid .ui-jqgrid-titlebar-close { position: absolute;top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height:18px;}.ui-jqgrid .ui-jqgrid-titlebar-close span { display: block; margin: 1px; }
+.ui-jqgrid .ui-jqgrid-titlebar-close:hover { padding: 0; }
+/* header*/
+.ui-jqgrid .ui-jqgrid-hdiv {position: relative; margin: 0em;padding: 0em; overflow-x: hidden; border-left: 0px none !important; border-top : 0px none !important; border-right : 0px none !important;}
+.ui-jqgrid .ui-jqgrid-hbox {float: left; padding-right: 20px;}
+.ui-jqgrid .ui-jqgrid-htable {table-layout:fixed;margin:0em;}
+.ui-jqgrid .ui-jqgrid-htable th {height:22px;padding: 0 2px 0 2px;}
+.ui-jqgrid .ui-jqgrid-htable th div {overflow: hidden; position:relative; height:17px;}
+.ui-th-column, .ui-jqgrid .ui-jqgrid-htable th.ui-th-column {overflow: hidden;white-space: nowrap;text-align:center;border-top : 0px none;border-bottom : 0px none;}
+.ui-th-ltr, .ui-jqgrid .ui-jqgrid-htable th.ui-th-ltr {border-left : 0px none;}
+.ui-th-rtl, .ui-jqgrid .ui-jqgrid-htable th.ui-th-rtl {border-right : 0px none;}
+.ui-first-th-ltr {border-right: 1px solid; }
+.ui-first-th-rtl {border-left: 1px solid; }
+.ui-jqgrid .ui-th-div-ie {white-space: nowrap; zoom :1; height:17px;}
+.ui-jqgrid .ui-jqgrid-resize {height:20px !important;position: relative; cursor :e-resize;display: inline;overflow: hidden;}
+.ui-jqgrid .ui-grid-ico-sort {overflow:hidden;position:absolute;display:inline; cursor: pointer !important;}
+.ui-jqgrid .ui-icon-asc {margin-top:-3px; height:12px;}
+.ui-jqgrid .ui-icon-desc {margin-top:3px;height:12px;}
+.ui-jqgrid .ui-i-asc {margin-top:0px;height:16px;}
+.ui-jqgrid .ui-i-desc {margin-top:0px;margin-left:13px;height:16px;}
+.ui-jqgrid .ui-jqgrid-sortable {cursor:pointer;}
+.ui-jqgrid tr.ui-search-toolbar th { border-top-width: 1px !important; border-top-color: inherit !important; border-top-style: ridge !important }
+tr.ui-search-toolbar input {margin: 1px 0px 0px 0px}
+tr.ui-search-toolbar select {margin: 1px 0px 0px 0px}
+/* body */
+.ui-jqgrid .ui-jqgrid-bdiv {position: relative; margin: 0em; padding:0; overflow: auto; text-align:left;}
+.ui-jqgrid .ui-jqgrid-btable {table-layout:fixed; margin:0em; outline-style: none; }
+.ui-jqgrid tr.jqgrow { outline-style: none; }
+.ui-jqgrid tr.jqgroup { outline-style: none; }
+.ui-jqgrid tr.jqgrow td {font-weight: normal; overflow: hidden; white-space: pre; height: 22px;padding: 0 2px 0 2px;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
+.ui-jqgrid tr.jqgfirstrow td {padding: 0 2px 0 2px;border-right-width: 1px; border-right-style: solid;}
+.ui-jqgrid tr.jqgroup td {font-weight: normal; overflow: hidden; white-space: pre; height: 22px;padding: 0 2px 0 2px;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
+.ui-jqgrid tr.jqfoot td {font-weight: bold; overflow: hidden; white-space: pre; height: 22px;padding: 0 2px 0 2px;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
+.ui-jqgrid tr.ui-row-ltr td {text-align:left;border-right-width: 1px; border-right-color: inherit; border-right-style: solid;}
+.ui-jqgrid tr.ui-row-rtl td {text-align:right;border-left-width: 1px; border-left-color: inherit; border-left-style: solid;}
+.ui-jqgrid td.jqgrid-rownum { padding: 0 2px 0 2px; margin: 0px; border: 0px none;}
+.ui-jqgrid .ui-jqgrid-resize-mark { width:2px; left:0; background-color:#777; cursor: e-resize; cursor: col-resize; position:absolute; top:0; height:100px; overflow:hidden; display:none; border:0 none; z-index: 99999;}
+/* footer */
+.ui-jqgrid .ui-jqgrid-sdiv {position: relative; margin: 0em;padding: 0em; overflow: hidden; border-left: 0px none !important; border-top : 0px none !important; border-right : 0px none !important;}
+.ui-jqgrid .ui-jqgrid-ftable {table-layout:fixed; margin-bottom:0em;}
+.ui-jqgrid tr.footrow td {font-weight: bold; overflow: hidden; white-space:nowrap; height: 21px;padding: 0 2px 0 2px;border-top-width: 1px; border-top-color: inherit; border-top-style: solid;}
+.ui-jqgrid tr.footrow-ltr td {text-align:left;border-right-width: 1px; border-right-color: inherit; border-right-style: solid;}
+.ui-jqgrid tr.footrow-rtl td {text-align:right;border-left-width: 1px; border-left-color: inherit; border-left-style: solid;}
+/* Pager*/
+.ui-jqgrid .ui-jqgrid-pager { border-left: 0px none !important;border-right: 0px none !important; border-bottom: 0px none !important; margin: 0px !important; padding: 0px !important; position: relative; height: 25px;white-space: nowrap;overflow: hidden;font-size:11px;}
+.ui-jqgrid .ui-pager-control {position: relative;}
+.ui-jqgrid .ui-pg-table {position: relative; padding-bottom:2px; width:auto; margin: 0em;}
+.ui-jqgrid .ui-pg-table td {font-weight:normal; vertical-align:middle; padding:1px;}
+.ui-jqgrid .ui-pg-button { height:19px !important;}
+.ui-jqgrid .ui-pg-button span { display: block; margin: 1px; float:left;}
+.ui-jqgrid .ui-pg-button:hover { padding: 0px; }
+.ui-jqgrid .ui-state-disabled:hover {padding:1px;}
+.ui-jqgrid .ui-pg-input { height:13px;font-size:.8em; margin: 0em;}
+.ui-jqgrid .ui-pg-selbox {font-size:.8em; line-height:18px; display:block; height:18px; margin: 0em;}
+.ui-jqgrid .ui-separator {height: 18px; border-left: 1px solid #ccc ; border-right: 1px solid #ccc ; margin: 1px; float: right;}
+.ui-jqgrid .ui-paging-info {font-weight: normal;height:19px; margin-top:3px;margin-right:4px;}
+.ui-jqgrid .ui-jqgrid-pager .ui-pg-div {padding:1px 0;float:left;position:relative;}
+.ui-jqgrid .ui-jqgrid-pager .ui-pg-button { cursor:pointer; }
+.ui-jqgrid .ui-jqgrid-pager .ui-pg-div span.ui-icon {float:left;margin:0 2px;}
+.ui-jqgrid td input, .ui-jqgrid td select .ui-jqgrid td textarea { margin: 0em;}
+.ui-jqgrid td textarea {width:auto;height:auto;}
+.ui-jqgrid .ui-jqgrid-toppager {border-left: 0px none !important;border-right: 0px none !important; border-top: 0px none !important; margin: 0px !important; padding: 0px !important; position: relative; height: 25px !important;white-space: nowrap;overflow: hidden;}
+.ui-jqgrid .ui-jqgrid-toppager .ui-pg-div {padding:1px 0;float:left;position:relative;}
+.ui-jqgrid .ui-jqgrid-toppager .ui-pg-button { cursor:pointer; }
+.ui-jqgrid .ui-jqgrid-toppager .ui-pg-div span.ui-icon {float:left;margin:0 2px;}
+/*subgrid*/
+.ui-jqgrid .ui-jqgrid-btable .ui-sgcollapsed span {display: block;}
+.ui-jqgrid .ui-subgrid {margin:0em;padding:0em; width:100%;}
+.ui-jqgrid .ui-subgrid table {table-layout: fixed;}
+.ui-jqgrid .ui-subgrid tr.ui-subtblcell td {height:18px;border-right-width: 1px; border-right-color: inherit; border-right-style: solid;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
+.ui-jqgrid .ui-subgrid td.subgrid-data {border-top: 0px none !important;}
+.ui-jqgrid .ui-subgrid td.subgrid-cell {border-width: 0px 0px 1px 0px;}
+.ui-jqgrid .ui-th-subgrid {height:20px;}
+/* loading */
+.ui-jqgrid .loading {position: absolute; top: 45%;left: 45%;width: auto;z-index:101;padding: 6px; margin: 5px;text-align: center;font-weight: bold;display: none;border-width: 2px !important; font-size:11px;}
+.ui-jqgrid .jqgrid-overlay {display:none;z-index:100;}
+* html .jqgrid-overlay {width: expression(this.parentNode.offsetWidth+'px');height: expression(this.parentNode.offsetHeight+'px');}
+* .jqgrid-overlay iframe {position:absolute;top:0;left:0;z-index:-1;width: expression(this.parentNode.offsetWidth+'px');height: expression(this.parentNode.offsetHeight+'px');}
+/* end loading div */
+/* toolbar */
+.ui-jqgrid .ui-userdata {border-left: 0px none; border-right: 0px none; height : 21px;overflow: hidden; }
+/*Modal Window */
+.ui-jqdialog { display: none; width: 300px; position: absolute; padding: .2em; font-size:11px; overflow:visible;}
+.ui-jqdialog .ui-jqdialog-titlebar { padding: .3em .2em; position: relative; }
+.ui-jqdialog .ui-jqdialog-title { margin: .1em 0 .2em; }
+.ui-jqdialog .ui-jqdialog-titlebar-close { position: absolute; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+
+.ui-jqdialog .ui-jqdialog-titlebar-close span { display: block; margin: 1px; }
+.ui-jqdialog .ui-jqdialog-titlebar-close:hover, .ui-jqdialog .ui-jqdialog-titlebar-close:focus { padding: 0; }
+.ui-jqdialog-content, .ui-jqdialog .ui-jqdialog-content { border: 0; padding: .3em .2em; background: none; height:auto;}
+.ui-jqdialog .ui-jqconfirm {padding: .4em 1em; border-width:3px;position:absolute;bottom:10px;right:10px;overflow:visible;display:none;height:80px;width:220px;text-align:center;}
+/* end Modal window*/
+/* Form edit */
+.ui-jqdialog-content .FormGrid {margin: 0px;}
+.ui-jqdialog-content .EditTable { width: 100%; margin-bottom:0em;}
+.ui-jqdialog-content .DelTable { width: 100%; margin-bottom:0em;}
+.EditTable td input, .EditTable td select, .EditTable td textarea {margin: 0em;}
+.EditTable td textarea { width:auto; height:auto;}
+.ui-jqdialog-content td.EditButton {text-align: right;border-top: 0px none;border-left: 0px none;border-right: 0px none; padding-bottom:5px; padding-top:5px;}
+.ui-jqdialog-content td.navButton {text-align: center; border-left: 0px none;border-top: 0px none;border-right: 0px none; padding-bottom:5px; padding-top:5px;}
+.ui-jqdialog-content input.FormElement {padding:.3em}
+.ui-jqdialog-content .data-line {padding-top:.1em;border: 0px none;}
+
+.ui-jqdialog-content .CaptionTD {vertical-align: middle;border: 0px none; padding: 2px;white-space: nowrap;}
+.ui-jqdialog-content .DataTD {padding: 2px; border: 0px none; vertical-align: top;}
+.ui-jqdialog-content .form-view-data {white-space:pre}
+.fm-button { display: inline-block; margin:0 4px 0 0; padding: .4em .5em; text-decoration:none !important; cursor:pointer; position: relative; text-align: center; zoom: 1; }
+.fm-button-icon-left { padding-left: 1.9em; }
+.fm-button-icon-right { padding-right: 1.9em; }
+.fm-button-icon-left .ui-icon { right: auto; left: .2em; margin-left: 0; position: absolute; top: 50%; margin-top: -8px; }
+.fm-button-icon-right .ui-icon { left: auto; right: .2em; margin-left: 0; position: absolute; top: 50%; margin-top: -8px;}
+#nData, #pData { float: left; margin:3px;padding: 0; width: 15px; }
+/* End Eorm edit */
+/*.ui-jqgrid .edit-cell {}*/
+.ui-jqgrid .selected-row, div.ui-jqgrid .selected-row td {font-style : normal;border-left: 0px none;}
+/* inline edit actions button*/
+.ui-inline-del.ui-state-hover span, .ui-inline-edit.ui-state-hover span,
+.ui-inline-save.ui-state-hover span, .ui-inline-cancel.ui-state-hover span {
+ margin: -1px;
+}
+/* Tree Grid */
+.ui-jqgrid .tree-wrap {float: left; position: relative;height: 18px;white-space: nowrap;overflow: hidden;}
+.ui-jqgrid .tree-minus {position: absolute; height: 18px; width: 18px; overflow: hidden;}
+.ui-jqgrid .tree-plus {position: absolute; height: 18px; width: 18px; overflow: hidden;}
+.ui-jqgrid .tree-leaf {position: absolute; height: 18px; width: 18px;overflow: hidden;}
+.ui-jqgrid .treeclick {cursor: pointer;}
+/* moda dialog */
+* iframe.jqm {position:absolute;top:0;left:0;z-index:-1;width: expression(this.parentNode.offsetWidth+'px');height: expression(this.parentNode.offsetHeight+'px');}
+.ui-jqgrid-dnd tr td {border-right-width: 1px; border-right-color: inherit; border-right-style: solid; height:20px}
+/* RTL Support */
+.ui-jqgrid .ui-jqgrid-title-rtl {float:right;margin: .1em 0 .2em; }
+.ui-jqgrid .ui-jqgrid-hbox-rtl {float: right; padding-left: 20px;}
+.ui-jqgrid .ui-jqgrid-resize-ltr {float: right;margin: -2px -2px -2px 0px;}
+.ui-jqgrid .ui-jqgrid-resize-rtl {float: left;margin: -2px 0px -1px -3px;}
+.ui-jqgrid .ui-sort-rtl {left:0px;}
+.ui-jqgrid .tree-wrap-ltr {float: left;}
+.ui-jqgrid .tree-wrap-rtl {float: right;}
+.ui-jqgrid .ui-ellipsis {text-overflow:ellipsis;}
diff --git a/SemanticResultFormats/resources/jquery/jqplot/excanvas.js b/SemanticResultFormats/resources/jquery/jqplot/excanvas.js
new file mode 100644
index 00000000..4ca9653f
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/excanvas.js
@@ -0,0 +1,1438 @@
+// Memory Leaks patch from http://explorercanvas.googlecode.com/svn/trunk/
+// svn : r73
+// ------------------------------------------------------------------
+// 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 only support repeat.
+// * 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)
+// * Non uniform scaling does not correctly scale strokes.
+// * Optimize. There is always room for speed improvements.
+
+// Only add this code if we do not already have a canvas implementation
+if (!document.createElement('canvas').getContext) {
+
+(function() {
+
+ // alias some functions to make (compiled) code shorter
+ var m = Math;
+ var mr = m.round;
+ var ms = m.sin;
+ var mc = m.cos;
+ var abs = m.abs;
+ var sqrt = m.sqrt;
+
+ // this is used for sub pixel precision
+ var Z = 10;
+ var Z2 = Z / 2;
+
+ var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];
+
+ /**
+ * This funtion is assigned to the <canvas> elements as element.getContext().
+ * @this {HTMLElement}
+ * @return {CanvasRenderingContext2D_}
+ */
+ function getContext() {
+ return this.context_ ||
+ (this.context_ = new CanvasRenderingContext2D_(this));
+ }
+
+ var slice = Array.prototype.slice;
+
+ /**
+ * Binds a function to an object. The returned function will always use the
+ * passed in {@code obj} as {@code this}.
+ *
+ * Example:
+ *
+ * g = bind(f, obj, a, b)
+ * g(c, d) // will do f.call(obj, a, b, c, d)
+ *
+ * @param {Function} f The function to bind the object to
+ * @param {Object} obj The object that should act as this when the function
+ * is called
+ * @param {*} var_args Rest arguments that will be used as the initial
+ * arguments when the function is called
+ * @return {Function} A new function that has bound this
+ */
+ function bind(f, obj, var_args) {
+ var a = slice.call(arguments, 2);
+ return function() {
+ return f.apply(obj, a.concat(slice.call(arguments)));
+ };
+ }
+
+ function encodeHtmlAttribute(s) {
+ return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
+ }
+
+ function addNamespace(doc, prefix, urn) {
+ if (!doc.namespaces[prefix]) {
+ doc.namespaces.add(prefix, urn, '#default#VML');
+ }
+ }
+
+ function addNamespacesAndStylesheet(doc) {
+ addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml');
+ addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office');
+
+ // Setup default CSS. Only add one style sheet per document
+ if (!doc.styleSheets['ex_canvas_']) {
+ var ss = doc.createStyleSheet();
+ ss.owningElement.id = 'ex_canvas_';
+ ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
+ // default size is 300x150 in Gecko and Opera
+ 'text-align:left;width:300px;height:150px}';
+ }
+ }
+
+ // Add namespaces and stylesheet at startup.
+ addNamespacesAndStylesheet(document);
+
+ var G_vmlCanvasManager_ = {
+ init: function(opt_doc) {
+ var doc = opt_doc || document;
+ // Create a dummy element so that IE will allow canvas elements to be
+ // recognized.
+ doc.createElement('canvas');
+ doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
+ },
+
+ init_: function(doc) {
+ // find all canvas elements
+ var els = doc.getElementsByTagName('canvas');
+ for (var i = 0; i < els.length; i++) {
+ this.initElement(els[i]);
+ }
+ },
+
+ /**
+ * 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) {
+ if (!el.getContext) {
+ el.getContext = getContext;
+
+ // Add namespaces and stylesheet to document of the element.
+ addNamespacesAndStylesheet(el.ownerDocument);
+
+ // Remove fallback content. There is no way to hide text nodes so we
+ // just remove all childNodes. We could hide all elements and remove
+ // text nodes but who really cares about the fallback content.
+ el.innerHTML = '';
+
+ // 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;
+ },
+
+ // Memory Leaks patch : see http://code.google.com/p/explorercanvas/issues/detail?id=82
+ uninitElement: function(el){
+ if (el.getContext) {
+ var ctx = el.getContext();
+ delete ctx.element_;
+ delete ctx.canvas;
+ el.innerHTML = "";
+ //el.outerHTML = "";
+ el.context_ = null;
+ el.getContext = null;
+ el.detachEvent("onpropertychange", onPropertyChange);
+ el.detachEvent("onresize", onResize);
+ }
+ }
+ };
+
+ function onPropertyChange(e) {
+ var el = e.srcElement;
+
+ switch (e.propertyName) {
+ case 'width':
+ el.getContext().clearRect();
+ el.style.width = el.attributes.width.nodeValue + 'px';
+ // In IE8 this does not trigger onresize.
+ el.firstChild.style.width = el.clientWidth + 'px';
+ break;
+ case 'height':
+ el.getContext().clearRect();
+ el.style.height = el.attributes.height.nodeValue + 'px';
+ el.firstChild.style.height = el.clientHeight + 'px';
+ 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 decToHex = [];
+ for (var i = 0; i < 16; i++) {
+ for (var j = 0; j < 16; j++) {
+ decToHex[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.globalAlpha = o1.globalAlpha;
+ o2.font = o1.font;
+ o2.textAlign = o1.textAlign;
+ o2.textBaseline = o1.textBaseline;
+ o2.arcScaleX_ = o1.arcScaleX_;
+ o2.arcScaleY_ = o1.arcScaleY_;
+ o2.lineScale_ = o1.lineScale_;
+ }
+
+ var colorData = {
+ aliceblue: '#F0F8FF',
+ antiquewhite: '#FAEBD7',
+ aquamarine: '#7FFFD4',
+ azure: '#F0FFFF',
+ beige: '#F5F5DC',
+ bisque: '#FFE4C4',
+ black: '#000000',
+ blanchedalmond: '#FFEBCD',
+ blueviolet: '#8A2BE2',
+ brown: '#A52A2A',
+ burlywood: '#DEB887',
+ cadetblue: '#5F9EA0',
+ chartreuse: '#7FFF00',
+ chocolate: '#D2691E',
+ coral: '#FF7F50',
+ cornflowerblue: '#6495ED',
+ cornsilk: '#FFF8DC',
+ crimson: '#DC143C',
+ cyan: '#00FFFF',
+ darkblue: '#00008B',
+ darkcyan: '#008B8B',
+ darkgoldenrod: '#B8860B',
+ darkgray: '#A9A9A9',
+ darkgreen: '#006400',
+ darkgrey: '#A9A9A9',
+ darkkhaki: '#BDB76B',
+ darkmagenta: '#8B008B',
+ darkolivegreen: '#556B2F',
+ darkorange: '#FF8C00',
+ darkorchid: '#9932CC',
+ darkred: '#8B0000',
+ darksalmon: '#E9967A',
+ darkseagreen: '#8FBC8F',
+ darkslateblue: '#483D8B',
+ darkslategray: '#2F4F4F',
+ darkslategrey: '#2F4F4F',
+ darkturquoise: '#00CED1',
+ darkviolet: '#9400D3',
+ deeppink: '#FF1493',
+ deepskyblue: '#00BFFF',
+ dimgray: '#696969',
+ dimgrey: '#696969',
+ dodgerblue: '#1E90FF',
+ firebrick: '#B22222',
+ floralwhite: '#FFFAF0',
+ forestgreen: '#228B22',
+ gainsboro: '#DCDCDC',
+ ghostwhite: '#F8F8FF',
+ gold: '#FFD700',
+ goldenrod: '#DAA520',
+ grey: '#808080',
+ greenyellow: '#ADFF2F',
+ honeydew: '#F0FFF0',
+ hotpink: '#FF69B4',
+ indianred: '#CD5C5C',
+ indigo: '#4B0082',
+ ivory: '#FFFFF0',
+ khaki: '#F0E68C',
+ lavender: '#E6E6FA',
+ lavenderblush: '#FFF0F5',
+ lawngreen: '#7CFC00',
+ lemonchiffon: '#FFFACD',
+ lightblue: '#ADD8E6',
+ lightcoral: '#F08080',
+ lightcyan: '#E0FFFF',
+ lightgoldenrodyellow: '#FAFAD2',
+ lightgreen: '#90EE90',
+ lightgrey: '#D3D3D3',
+ lightpink: '#FFB6C1',
+ lightsalmon: '#FFA07A',
+ lightseagreen: '#20B2AA',
+ lightskyblue: '#87CEFA',
+ lightslategray: '#778899',
+ lightslategrey: '#778899',
+ lightsteelblue: '#B0C4DE',
+ lightyellow: '#FFFFE0',
+ limegreen: '#32CD32',
+ linen: '#FAF0E6',
+ magenta: '#FF00FF',
+ mediumaquamarine: '#66CDAA',
+ mediumblue: '#0000CD',
+ mediumorchid: '#BA55D3',
+ mediumpurple: '#9370DB',
+ mediumseagreen: '#3CB371',
+ mediumslateblue: '#7B68EE',
+ mediumspringgreen: '#00FA9A',
+ mediumturquoise: '#48D1CC',
+ mediumvioletred: '#C71585',
+ midnightblue: '#191970',
+ mintcream: '#F5FFFA',
+ mistyrose: '#FFE4E1',
+ moccasin: '#FFE4B5',
+ navajowhite: '#FFDEAD',
+ oldlace: '#FDF5E6',
+ olivedrab: '#6B8E23',
+ orange: '#FFA500',
+ orangered: '#FF4500',
+ orchid: '#DA70D6',
+ palegoldenrod: '#EEE8AA',
+ palegreen: '#98FB98',
+ paleturquoise: '#AFEEEE',
+ palevioletred: '#DB7093',
+ papayawhip: '#FFEFD5',
+ peachpuff: '#FFDAB9',
+ peru: '#CD853F',
+ pink: '#FFC0CB',
+ plum: '#DDA0DD',
+ powderblue: '#B0E0E6',
+ rosybrown: '#BC8F8F',
+ royalblue: '#4169E1',
+ saddlebrown: '#8B4513',
+ salmon: '#FA8072',
+ sandybrown: '#F4A460',
+ seagreen: '#2E8B57',
+ seashell: '#FFF5EE',
+ sienna: '#A0522D',
+ skyblue: '#87CEEB',
+ slateblue: '#6A5ACD',
+ slategray: '#708090',
+ slategrey: '#708090',
+ snow: '#FFFAFA',
+ springgreen: '#00FF7F',
+ steelblue: '#4682B4',
+ tan: '#D2B48C',
+ thistle: '#D8BFD8',
+ tomato: '#FF6347',
+ turquoise: '#40E0D0',
+ violet: '#EE82EE',
+ wheat: '#F5DEB3',
+ whitesmoke: '#F5F5F5',
+ yellowgreen: '#9ACD32'
+ };
+
+
+ function getRgbHslContent(styleString) {
+ var start = styleString.indexOf('(', 3);
+ var end = styleString.indexOf(')', start + 1);
+ var parts = styleString.substring(start + 1, end).split(',');
+ // add alpha if needed
+ if (parts.length != 4 || styleString.charAt(3) != 'a') {
+ parts[3] = 1;
+ }
+ return parts;
+ }
+
+ function percent(s) {
+ return parseFloat(s) / 100;
+ }
+
+ function clamp(v, min, max) {
+ return Math.min(max, Math.max(min, v));
+ }
+
+ function hslToRgb(parts){
+ var r, g, b, h, s, l;
+ h = parseFloat(parts[0]) / 360 % 360;
+ if (h < 0)
+ h++;
+ s = clamp(percent(parts[1]), 0, 1);
+ l = clamp(percent(parts[2]), 0, 1);
+ if (s == 0) {
+ r = g = b = l; // achromatic
+ } else {
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ var p = 2 * l - q;
+ r = hueToRgb(p, q, h + 1 / 3);
+ g = hueToRgb(p, q, h);
+ b = hueToRgb(p, q, h - 1 / 3);
+ }
+
+ return '#' + decToHex[Math.floor(r * 255)] +
+ decToHex[Math.floor(g * 255)] +
+ decToHex[Math.floor(b * 255)];
+ }
+
+ function hueToRgb(m1, m2, h) {
+ if (h < 0)
+ h++;
+ if (h > 1)
+ h--;
+
+ if (6 * h < 1)
+ return m1 + (m2 - m1) * 6 * h;
+ else if (2 * h < 1)
+ return m2;
+ else if (3 * h < 2)
+ return m1 + (m2 - m1) * (2 / 3 - h) * 6;
+ else
+ return m1;
+ }
+
+ var processStyleCache = {};
+
+ function processStyle(styleString) {
+ if (styleString in processStyleCache) {
+ return processStyleCache[styleString];
+ }
+
+ var str, alpha = 1;
+
+ styleString = String(styleString);
+ if (styleString.charAt(0) == '#') {
+ str = styleString;
+ } else if (/^rgb/.test(styleString)) {
+ var parts = getRgbHslContent(styleString);
+ var str = '#', n;
+ for (var i = 0; i < 3; i++) {
+ if (parts[i].indexOf('%') != -1) {
+ n = Math.floor(percent(parts[i]) * 255);
+ } else {
+ n = +parts[i];
+ }
+ str += decToHex[clamp(n, 0, 255)];
+ }
+ alpha = +parts[3];
+ } else if (/^hsl/.test(styleString)) {
+ var parts = getRgbHslContent(styleString);
+ str = hslToRgb(parts);
+ alpha = parts[3];
+ } else {
+ str = colorData[styleString] || styleString;
+ }
+ return processStyleCache[styleString] = {color: str, alpha: alpha};
+ }
+
+ var DEFAULT_STYLE = {
+ style: 'normal',
+ variant: 'normal',
+ weight: 'normal',
+ size: 10,
+ family: 'sans-serif'
+ };
+
+ // Internal text style cache
+ var fontStyleCache = {};
+
+ function processFontStyle(styleString) {
+ if (fontStyleCache[styleString]) {
+ return fontStyleCache[styleString];
+ }
+
+ var el = document.createElement('div');
+ var style = el.style;
+ try {
+ style.font = styleString;
+ } catch (ex) {
+ // Ignore failures to set to invalid font.
+ }
+
+ return fontStyleCache[styleString] = {
+ style: style.fontStyle || DEFAULT_STYLE.style,
+ variant: style.fontVariant || DEFAULT_STYLE.variant,
+ weight: style.fontWeight || DEFAULT_STYLE.weight,
+ size: style.fontSize || DEFAULT_STYLE.size,
+ family: style.fontFamily || DEFAULT_STYLE.family
+ };
+ }
+
+ function getComputedStyle(style, element) {
+ var computedStyle = {};
+
+ for (var p in style) {
+ computedStyle[p] = style[p];
+ }
+
+ // Compute the size
+ var canvasFontSize = parseFloat(element.currentStyle.fontSize),
+ fontSize = parseFloat(style.size);
+
+ if (typeof style.size == 'number') {
+ computedStyle.size = style.size;
+ } else if (style.size.indexOf('px') != -1) {
+ computedStyle.size = fontSize;
+ } else if (style.size.indexOf('em') != -1) {
+ computedStyle.size = canvasFontSize * fontSize;
+ } else if(style.size.indexOf('%') != -1) {
+ computedStyle.size = (canvasFontSize / 100) * fontSize;
+ } else if (style.size.indexOf('pt') != -1) {
+ computedStyle.size = fontSize / .75;
+ } else {
+ computedStyle.size = canvasFontSize;
+ }
+
+ // Different scaling between normal text and VML text. This was found using
+ // trial and error to get the same size as non VML text.
+ computedStyle.size *= 0.981;
+
+ // Fix for VML handling of bare font family names. Add a '' around font family names.
+ computedStyle.family = "'" + computedStyle.family.replace(/(\'|\")/g,'').replace(/\s*,\s*/g, "', '") + "'";
+
+ return computedStyle;
+ }
+
+ function buildStyle(style) {
+ return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
+ style.size + 'px ' + style.family;
+ }
+
+ var lineCapMap = {
+ 'butt': 'flat',
+ 'round': 'round'
+ };
+
+ function processLineCap(lineCap) {
+ return lineCapMap[lineCap] || 'square';
+ }
+
+ /**
+ * This class implements CanvasRenderingContext2D interface as described by
+ * the WHATWG.
+ * @param {HTMLElement} canvasElement The element that the 2D context should
+ * be associated with
+ */
+ function CanvasRenderingContext2D_(canvasElement) {
+ 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.font = '10px sans-serif';
+ this.textAlign = 'left';
+ this.textBaseline = 'alphabetic';
+ this.canvas = canvasElement;
+
+ var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' +
+ canvasElement.clientHeight + 'px;overflow:hidden;position:absolute';
+ var el = canvasElement.ownerDocument.createElement('div');
+ el.style.cssText = cssText;
+ canvasElement.appendChild(el);
+
+ var overlayEl = el.cloneNode(false);
+ // Use a non transparent background.
+ overlayEl.style.backgroundColor = 'red';
+ overlayEl.style.filter = 'alpha(opacity=0)';
+ canvasElement.appendChild(overlayEl);
+
+ this.element_ = el;
+ this.arcScaleX_ = 1;
+ this.arcScaleY_ = 1;
+ this.lineScale_ = 1;
+ }
+
+ var contextPrototype = CanvasRenderingContext2D_.prototype;
+ contextPrototype.clearRect = function() {
+ if (this.textMeasureEl_) {
+ this.textMeasureEl_.removeNode(true);
+ this.textMeasureEl_ = null;
+ }
+ this.element_.innerHTML = '';
+ };
+
+ 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) {
+ var p = getCoords(this, aX, aY);
+ this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
+ this.currentX_ = p.x;
+ this.currentY_ = p.y;
+ };
+
+ contextPrototype.lineTo = function(aX, aY) {
+ var p = getCoords(this, aX, aY);
+ this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
+
+ this.currentX_ = p.x;
+ this.currentY_ = p.y;
+ };
+
+ contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
+ aCP2x, aCP2y,
+ aX, aY) {
+ var p = getCoords(this, aX, aY);
+ var cp1 = getCoords(this, aCP1x, aCP1y);
+ var cp2 = getCoords(this, aCP2x, aCP2y);
+ bezierCurveTo(this, cp1, cp2, p);
+ };
+
+ // Helper function that takes the already fixed cordinates.
+ function bezierCurveTo(self, cp1, cp2, p) {
+ self.currentPath_.push({
+ type: 'bezierCurveTo',
+ cp1x: cp1.x,
+ cp1y: cp1.y,
+ cp2x: cp2.x,
+ cp2y: cp2.y,
+ x: p.x,
+ y: p.y
+ });
+ self.currentX_ = p.x;
+ self.currentY_ = p.y;
+ }
+
+ 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 cp = getCoords(this, aCPx, aCPy);
+ var p = getCoords(this, aX, aY);
+
+ var cp1 = {
+ x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
+ y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
+ };
+ var cp2 = {
+ x: cp1.x + (p.x - this.currentX_) / 3.0,
+ y: cp1.y + (p.y - this.currentY_) / 3.0
+ };
+
+ bezierCurveTo(this, cp1, cp2, p);
+ };
+
+ 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
+ }
+
+ var p = getCoords(this, aX, aY);
+ var pStart = getCoords(this, xStart, yStart);
+ var pEnd = getCoords(this, xEnd, yEnd);
+
+ this.currentPath_.push({type: arcType,
+ x: p.x,
+ y: p.y,
+ radius: aRadius,
+ xStart: pStart.x,
+ yStart: pStart.y,
+ xEnd: pEnd.x,
+ yEnd: pEnd.y});
+
+ };
+
+ 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) {
+ var oldPath = this.currentPath_;
+ 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();
+
+ this.currentPath_ = oldPath;
+ };
+
+ contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
+ var oldPath = this.currentPath_;
+ 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();
+
+ this.currentPath_ = oldPath;
+ };
+
+ contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
+ var gradient = new CanvasGradient_('gradient');
+ gradient.x0_ = aX0;
+ gradient.y0_ = aY0;
+ gradient.x1_ = aX1;
+ gradient.y1_ = aY1;
+ return gradient;
+ };
+
+ contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
+ aX1, aY1, aR1) {
+ var gradient = new CanvasGradient_('gradientradial');
+ gradient.x0_ = aX0;
+ gradient.y0_ = aY0;
+ gradient.r0_ = aR0;
+ gradient.x1_ = aX1;
+ gradient.y1_ = aY1;
+ gradient.r1_ = aR1;
+ 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 Error('Invalid number of arguments');
+ }
+
+ var d = getCoords(this, 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(' <g_vml_:group',
+ ' coordsize="', Z * W, ',', Z * H, '"',
+ ' coordorigin="0,0"' ,
+ ' style="width:', W, 'px;height:', H, 'px;position:absolute;');
+
+ // If filters are necessary (rotation exists), create them
+ // filters are bog-slow, so only create them if abbsolutely necessary
+ // The following check doesn't account for skews (which don't exist
+ // in the canvas spec (yet) anyway.
+
+ if (this.m_[0][0] != 1 || this.m_[0][1] ||
+ this.m_[1][1] != 1 || this.m_[1][0]) {
+ var filter = [];
+
+ // Note the 12/21 reversal
+ filter.push('M11=', this.m_[0][0], ',',
+ 'M12=', this.m_[1][0], ',',
+ 'M21=', this.m_[0][1], ',',
+ 'M22=', this.m_[1][1], ',',
+ 'Dx=', mr(d.x / Z), ',',
+ 'Dy=', mr(d.y / Z), '');
+
+ // Bounding box calculation (need to minimize displayed area so that
+ // filters don't waste time on unused pixels.
+ var max = d;
+ var c2 = getCoords(this, dx + dw, dy);
+ var c3 = getCoords(this, dx, dy + dh);
+ var c4 = getCoords(this, dx + dw, dy + dh);
+
+ max.x = m.max(max.x, c2.x, c3.x, c4.x);
+ max.y = m.max(max.y, c2.y, c3.y, c4.y);
+
+ vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
+ 'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
+ filter.join(''), ", sizingmethod='clip');");
+
+ } else {
+ vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
+ }
+
+ vmlStr.push(' ">' ,
+ '<g_vml_:image src="', image.src, '"',
+ ' style="width:', Z * dw, 'px;',
+ ' height:', Z * dh, 'px"',
+ ' cropleft="', sx / w, '"',
+ ' croptop="', sy / h, '"',
+ ' cropright="', (w - sx - sw) / w, '"',
+ ' cropbottom="', (h - sy - sh) / h, '"',
+ ' />',
+ '</g_vml_:group>');
+
+ this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
+ };
+
+ contextPrototype.stroke = function(aFill) {
+ var lineStr = [];
+ var lineOpen = false;
+
+ var W = 10;
+ var H = 10;
+
+ lineStr.push('<g_vml_:shape',
+ ' filled="', !!aFill, '"',
+ ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
+ ' coordorigin="0,0"',
+ ' coordsize="', Z * W, ',', Z * H, '"',
+ ' stroked="', !aFill, '"',
+ ' path="');
+
+ var newSeq = false;
+ var min = {x: null, y: null};
+ var max = {x: null, y: null};
+
+ for (var i = 0; i < this.currentPath_.length; i++) {
+ var p = this.currentPath_[i];
+ var c;
+
+ switch (p.type) {
+ case 'moveTo':
+ c = p;
+ lineStr.push(' m ', mr(p.x), ',', mr(p.y));
+ break;
+ case 'lineTo':
+ lineStr.push(' l ', mr(p.x), ',', mr(p.y));
+ break;
+ case 'close':
+ lineStr.push(' x ');
+ p = null;
+ break;
+ case 'bezierCurveTo':
+ lineStr.push(' c ',
+ mr(p.cp1x), ',', mr(p.cp1y), ',',
+ mr(p.cp2x), ',', mr(p.cp2y), ',',
+ mr(p.x), ',', mr(p.y));
+ break;
+ case 'at':
+ case 'wa':
+ lineStr.push(' ', p.type, ' ',
+ mr(p.x - this.arcScaleX_ * p.radius), ',',
+ mr(p.y - this.arcScaleY_ * p.radius), ' ',
+ mr(p.x + this.arcScaleX_ * p.radius), ',',
+ mr(p.y + this.arcScaleY_ * p.radius), ' ',
+ mr(p.xStart), ',', mr(p.yStart), ' ',
+ mr(p.xEnd), ',', mr(p.yEnd));
+ break;
+ }
+
+
+ // TODO: Following is broken for curves due to
+ // move to proper paths.
+
+ // Figure out dimensions so we can do gradient fills
+ // properly
+ if (p) {
+ if (min.x == null || p.x < min.x) {
+ min.x = p.x;
+ }
+ if (max.x == null || p.x > max.x) {
+ max.x = p.x;
+ }
+ if (min.y == null || p.y < min.y) {
+ min.y = p.y;
+ }
+ if (max.y == null || p.y > max.y) {
+ max.y = p.y;
+ }
+ }
+ }
+ lineStr.push(' ">');
+
+ if (!aFill) {
+ appendStroke(this, lineStr);
+ } else {
+ appendFill(this, lineStr, min, max);
+ }
+
+ lineStr.push('</g_vml_:shape>');
+
+ this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
+ };
+
+ function appendStroke(ctx, lineStr) {
+ var a = processStyle(ctx.strokeStyle);
+ var color = a.color;
+ var opacity = a.alpha * ctx.globalAlpha;
+ var lineWidth = ctx.lineScale_ * ctx.lineWidth;
+
+ // VML cannot correctly render a line if the width is less than 1px.
+ // In that case, we dilute the color to make the line look thinner.
+ if (lineWidth < 1) {
+ opacity *= lineWidth;
+ }
+
+ lineStr.push(
+ '<g_vml_:stroke',
+ ' opacity="', opacity, '"',
+ ' joinstyle="', ctx.lineJoin, '"',
+ ' miterlimit="', ctx.miterLimit, '"',
+ ' endcap="', processLineCap(ctx.lineCap), '"',
+ ' weight="', lineWidth, 'px"',
+ ' color="', color, '" />'
+ );
+ }
+
+ function appendFill(ctx, lineStr, min, max) {
+ var fillStyle = ctx.fillStyle;
+ var arcScaleX = ctx.arcScaleX_;
+ var arcScaleY = ctx.arcScaleY_;
+ var width = max.x - min.x;
+ var height = max.y - min.y;
+ if (fillStyle instanceof CanvasGradient_) {
+ // TODO: Gradients transformed with the transformation matrix.
+ var angle = 0;
+ var focus = {x: 0, y: 0};
+
+ // additional offset
+ var shift = 0;
+ // scale factor for offset
+ var expansion = 1;
+
+ if (fillStyle.type_ == 'gradient') {
+ var x0 = fillStyle.x0_ / arcScaleX;
+ var y0 = fillStyle.y0_ / arcScaleY;
+ var x1 = fillStyle.x1_ / arcScaleX;
+ var y1 = fillStyle.y1_ / arcScaleY;
+ var p0 = getCoords(ctx, x0, y0);
+ var p1 = getCoords(ctx, x1, y1);
+ var dx = p1.x - p0.x;
+ var dy = p1.y - p0.y;
+ angle = Math.atan2(dx, dy) * 180 / Math.PI;
+
+ // The angle should be a non-negative number.
+ if (angle < 0) {
+ angle += 360;
+ }
+
+ // Very small angles produce an unexpected result because they are
+ // converted to a scientific notation string.
+ if (angle < 1e-6) {
+ angle = 0;
+ }
+ } else {
+ var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_);
+ focus = {
+ x: (p0.x - min.x) / width,
+ y: (p0.y - min.y) / height
+ };
+
+ width /= arcScaleX * Z;
+ height /= arcScaleY * Z;
+ var dimension = m.max(width, height);
+ shift = 2 * fillStyle.r0_ / dimension;
+ expansion = 2 * fillStyle.r1_ / dimension - shift;
+ }
+
+ // We need to sort the color stops in ascending order by offset,
+ // otherwise IE won't interpret it correctly.
+ var stops = fillStyle.colors_;
+ stops.sort(function(cs1, cs2) {
+ return cs1.offset - cs2.offset;
+ });
+
+ var length = stops.length;
+ var color1 = stops[0].color;
+ var color2 = stops[length - 1].color;
+ var opacity1 = stops[0].alpha * ctx.globalAlpha;
+ var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
+
+ var colors = [];
+ for (var i = 0; i < length; i++) {
+ var stop = stops[i];
+ colors.push(stop.offset * expansion + shift + ' ' + stop.color);
+ }
+
+ // When colors attribute is used, the meanings of opacity and o:opacity2
+ // are reversed.
+ lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
+ ' method="none" focus="100%"',
+ ' color="', color1, '"',
+ ' color2="', color2, '"',
+ ' colors="', colors.join(','), '"',
+ ' opacity="', opacity2, '"',
+ ' g_o_:opacity2="', opacity1, '"',
+ ' angle="', angle, '"',
+ ' focusposition="', focus.x, ',', focus.y, '" />');
+ } else if (fillStyle instanceof CanvasPattern_) {
+ if (width && height) {
+ var deltaLeft = -min.x;
+ var deltaTop = -min.y;
+ lineStr.push('<g_vml_:fill',
+ ' position="',
+ deltaLeft / width * arcScaleX * arcScaleX, ',',
+ deltaTop / height * arcScaleY * arcScaleY, '"',
+ ' type="tile"',
+ // TODO: Figure out the correct size to fit the scale.
+ //' size="', w, 'px ', h, 'px"',
+ ' src="', fillStyle.src_, '" />');
+ }
+ } else {
+ var a = processStyle(ctx.fillStyle);
+ var color = a.color;
+ var opacity = a.alpha * ctx.globalAlpha;
+ lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
+ '" />');
+ }
+ }
+
+ contextPrototype.fill = function() {
+ this.stroke(true);
+ };
+
+ contextPrototype.closePath = function() {
+ this.currentPath_.push({type: 'close'});
+ };
+
+ function getCoords(ctx, aX, aY) {
+ var m = ctx.m_;
+ return {
+ x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
+ y: Z * (aX * m[0][1] + aY * m[1][1] + 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() {
+ if (this.aStack_.length) {
+ copyState(this.aStack_.pop(), this);
+ this.m_ = this.mStack_.pop();
+ }
+ };
+
+ function matrixIsFinite(m) {
+ return isFinite(m[0][0]) && isFinite(m[0][1]) &&
+ isFinite(m[1][0]) && isFinite(m[1][1]) &&
+ isFinite(m[2][0]) && isFinite(m[2][1]);
+ }
+
+ function setM(ctx, m, updateLineScale) {
+ if (!matrixIsFinite(m)) {
+ return;
+ }
+ ctx.m_ = m;
+
+ if (updateLineScale) {
+ // Get the line scale.
+ // Determinant of this.m_ means how much the area is enlarged by the
+ // transformation. So its square root can be used as a scale factor
+ // for width.
+ var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
+ ctx.lineScale_ = sqrt(abs(det));
+ }
+ }
+
+ contextPrototype.translate = function(aX, aY) {
+ var m1 = [
+ [1, 0, 0],
+ [0, 1, 0],
+ [aX, aY, 1]
+ ];
+
+ setM(this, matrixMultiply(m1, this.m_), false);
+ };
+
+ contextPrototype.rotate = function(aRot) {
+ var c = mc(aRot);
+ var s = ms(aRot);
+
+ var m1 = [
+ [c, s, 0],
+ [-s, c, 0],
+ [0, 0, 1]
+ ];
+
+ setM(this, matrixMultiply(m1, this.m_), false);
+ };
+
+ contextPrototype.scale = function(aX, aY) {
+ this.arcScaleX_ *= aX;
+ this.arcScaleY_ *= aY;
+ var m1 = [
+ [aX, 0, 0],
+ [0, aY, 0],
+ [0, 0, 1]
+ ];
+
+ setM(this, matrixMultiply(m1, this.m_), true);
+ };
+
+ contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
+ var m1 = [
+ [m11, m12, 0],
+ [m21, m22, 0],
+ [dx, dy, 1]
+ ];
+
+ setM(this, matrixMultiply(m1, this.m_), true);
+ };
+
+ contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
+ var m = [
+ [m11, m12, 0],
+ [m21, m22, 0],
+ [dx, dy, 1]
+ ];
+
+ setM(this, m, true);
+ };
+
+ /**
+ * The text drawing function.
+ * The maxWidth argument isn't taken in account, since no browser supports
+ * it yet.
+ */
+ contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {
+ var m = this.m_,
+ delta = 1000,
+ left = 0,
+ right = delta,
+ offset = {x: 0, y: 0},
+ lineStr = [];
+
+ var fontStyle = getComputedStyle(processFontStyle(this.font), this.element_);
+
+ var fontStyleString = buildStyle(fontStyle);
+
+ var elementStyle = this.element_.currentStyle;
+ var textAlign = this.textAlign.toLowerCase();
+ switch (textAlign) {
+ case 'left':
+ case 'center':
+ case 'right':
+ break;
+ case 'end':
+ textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';
+ break;
+ case 'start':
+ textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';
+ break;
+ default:
+ textAlign = 'left';
+ }
+
+ // 1.75 is an arbitrary number, as there is no info about the text baseline
+ switch (this.textBaseline) {
+ case 'hanging':
+ case 'top':
+ offset.y = fontStyle.size / 1.75;
+ break;
+ case 'middle':
+ break;
+ default:
+ case null:
+ case 'alphabetic':
+ case 'ideographic':
+ case 'bottom':
+ offset.y = -fontStyle.size / 2.25;
+ break;
+ }
+
+ switch(textAlign) {
+ case 'right':
+ left = delta;
+ right = 0.05;
+ break;
+ case 'center':
+ left = right = delta / 2;
+ break;
+ }
+
+ var d = getCoords(this, x + offset.x, y + offset.y);
+
+ lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',
+ ' coordsize="100 100" coordorigin="0 0"',
+ ' filled="', !stroke, '" stroked="', !!stroke,
+ '" style="position:absolute;width:1px;height:1px;">');
+
+ if (stroke) {
+ appendStroke(this, lineStr);
+ } else {
+ // TODO: Fix the min and max params.
+ appendFill(this, lineStr, {x: -left, y: 0},
+ {x: right, y: fontStyle.size});
+ }
+
+ var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +
+ m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';
+
+ var skewOffset = mr(d.x / Z + 1 - m[0][0]) + ',' + mr(d.y / Z - 2 * m[1][0]);
+
+
+ lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ',
+ ' offset="', skewOffset, '" origin="', left ,' 0" />',
+ '<g_vml_:path textpathok="true" />',
+ '<g_vml_:textpath on="true" string="',
+ encodeHtmlAttribute(text),
+ '" style="v-text-align:', textAlign,
+ ';font:', encodeHtmlAttribute(fontStyleString),
+ '" /></g_vml_:line>');
+
+ this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
+ };
+
+ contextPrototype.fillText = function(text, x, y, maxWidth) {
+ this.drawText_(text, x, y, maxWidth, false);
+ };
+
+ contextPrototype.strokeText = function(text, x, y, maxWidth) {
+ this.drawText_(text, x, y, maxWidth, true);
+ };
+
+ contextPrototype.measureText = function(text) {
+ if (!this.textMeasureEl_) {
+ var s = '<span style="position:absolute;' +
+ 'top:-20000px;left:0;padding:0;margin:0;border:none;' +
+ 'white-space:pre;"></span>';
+ this.element_.insertAdjacentHTML('beforeEnd', s);
+ this.textMeasureEl_ = this.element_.lastChild;
+ }
+ var doc = this.element_.ownerDocument;
+ this.textMeasureEl_.innerHTML = '';
+ this.textMeasureEl_.style.font = this.font;
+ // Don't use innerHTML or innerText because they allow markup/whitespace.
+ this.textMeasureEl_.appendChild(doc.createTextNode(text));
+ return {width: this.textMeasureEl_.offsetWidth};
+ };
+
+ /******** STUBS ********/
+ contextPrototype.clip = function() {
+ // TODO: Implement
+ };
+
+ contextPrototype.arcTo = function() {
+ // TODO: Implement
+ };
+
+ contextPrototype.createPattern = function(image, repetition) {
+ return new CanvasPattern_(image, repetition);
+ };
+
+ // Gradient / Pattern Stubs
+ function CanvasGradient_(aType) {
+ this.type_ = aType;
+ this.x0_ = 0;
+ this.y0_ = 0;
+ this.r0_ = 0;
+ this.x1_ = 0;
+ this.y1_ = 0;
+ this.r1_ = 0;
+ this.colors_ = [];
+ }
+
+ CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
+ aColor = processStyle(aColor);
+ this.colors_.push({offset: aOffset,
+ color: aColor.color,
+ alpha: aColor.alpha});
+ };
+
+ function CanvasPattern_(image, repetition) {
+ assertImageIsValid(image);
+ switch (repetition) {
+ case 'repeat':
+ case null:
+ case '':
+ this.repetition_ = 'repeat';
+ break;
+ case 'repeat-x':
+ case 'repeat-y':
+ case 'no-repeat':
+ this.repetition_ = repetition;
+ break;
+ default:
+ throwException('SYNTAX_ERR');
+ }
+
+ this.src_ = image.src;
+ this.width_ = image.width;
+ this.height_ = image.height;
+ }
+
+ function throwException(s) {
+ throw new DOMException_(s);
+ }
+
+ function assertImageIsValid(img) {
+ if (!img || img.nodeType != 1 || img.tagName != 'IMG') {
+ throwException('TYPE_MISMATCH_ERR');
+ }
+ if (img.readyState != 'complete') {
+ throwException('INVALID_STATE_ERR');
+ }
+ }
+
+ function DOMException_(s) {
+ this.code = this[s];
+ this.message = s +': DOM Exception ' + this.code;
+ }
+ var p = DOMException_.prototype = new Error;
+ p.INDEX_SIZE_ERR = 1;
+ p.DOMSTRING_SIZE_ERR = 2;
+ p.HIERARCHY_REQUEST_ERR = 3;
+ p.WRONG_DOCUMENT_ERR = 4;
+ p.INVALID_CHARACTER_ERR = 5;
+ p.NO_DATA_ALLOWED_ERR = 6;
+ p.NO_MODIFICATION_ALLOWED_ERR = 7;
+ p.NOT_FOUND_ERR = 8;
+ p.NOT_SUPPORTED_ERR = 9;
+ p.INUSE_ATTRIBUTE_ERR = 10;
+ p.INVALID_STATE_ERR = 11;
+ p.SYNTAX_ERR = 12;
+ p.INVALID_MODIFICATION_ERR = 13;
+ p.NAMESPACE_ERR = 14;
+ p.INVALID_ACCESS_ERR = 15;
+ p.VALIDATION_ERR = 16;
+ p.TYPE_MISMATCH_ERR = 17;
+
+ // set up externs
+ G_vmlCanvasManager = G_vmlCanvasManager_;
+ CanvasRenderingContext2D = CanvasRenderingContext2D_;
+ CanvasGradient = CanvasGradient_;
+ CanvasPattern = CanvasPattern_;
+ DOMException = DOMException_;
+ G_vmlCanvasManager._version = 888;
+})();
+
+} // if
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqPlot.Copyright b/SemanticResultFormats/resources/jquery/jqplot/jqPlot.Copyright
new file mode 100644
index 00000000..1329729f
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqPlot.Copyright
@@ -0,0 +1,29 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: @VERSION
+ *
+ * Copyright (c) 2009-2011 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqPlot.MIT LICENSE b/SemanticResultFormats/resources/jquery/jqplot/jqPlot.MIT LICENSE
new file mode 100644
index 00000000..da4732ec
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqPlot.MIT LICENSE
@@ -0,0 +1,21 @@
+Title: MIT License
+
+Copyright (c) 2009-2011 Chris Leonello
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.BezierCurveRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.BezierCurveRenderer.js
new file mode 100644
index 00000000..00b33815
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.BezierCurveRenderer.js
@@ -0,0 +1,313 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ // Class: $.jqplot.BezierCurveRenderer.js
+ // Renderer which draws lines as stacked bezier curves.
+ // Data for the line will not be specified as an array of
+ // [x, y] data point values, but as a an array of [start piont, bezier curve]
+ // So, the line is specified as: [[xstart, ystart], [cp1x, cp1y, cp2x, cp2y, xend, yend]].
+ $.jqplot.BezierCurveRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.BezierCurveRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.BezierCurveRenderer.prototype.constructor = $.jqplot.BezierCurveRenderer;
+
+
+ // Method: setGridData
+ // converts the user data values to grid coordinates and stores them
+ // in the gridData array.
+ // Called with scope of a series.
+ $.jqplot.BezierCurveRenderer.prototype.setGridData = function(plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ // this._plotData should be same as this.data
+ var data = this.data;
+ this.gridData = [];
+ this._prevGridData = [];
+ // if seriesIndex = 0, fill to x axis.
+ // if seriesIndex > 0, fill to previous series data.
+ var idx = this.index;
+ if (data.length == 2) {
+ if (idx == 0) {
+ this.gridData = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]),
+ xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])],
+ [xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, this._yaxis.min)],
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)]
+ ];
+ }
+ else {
+ var psd = plot.series[idx-1].data;
+ this.gridData = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]),
+ xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])],
+ [xp.call(this._xaxis, psd[1][4]), yp.call(this._yaxis, psd[1][5])],
+ [xp.call(this._xaxis, psd[1][2]), yp.call(this._yaxis, psd[1][3]),
+ xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]),
+ xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])]
+ ];
+ }
+ }
+ else {
+ if (idx == 0) {
+ this.gridData = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]),
+ xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])],
+ [xp.call(this._xaxis, data[3][1]), yp.call(this._yaxis, this._yaxis.min)],
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)]
+ ];
+ }
+ else {
+ var psd = plot.series[idx-1].data;
+ this.gridData = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]),
+ xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])],
+ [xp.call(this._xaxis, psd[3][0]), yp.call(this._yaxis, psd[3][1])],
+ [xp.call(this._xaxis, psd[2][0]), yp.call(this._yaxis, psd[2][1]),
+ xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]),
+ xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])]
+ ];
+ }
+ }
+ };
+
+ // Method: makeGridData
+ // converts any arbitrary data values to grid coordinates and
+ // returns them. This method exists so that plugins can use a series'
+ // linerenderer to generate grid data points without overwriting the
+ // grid data associated with that series.
+ // Called with scope of a series.
+ $.jqplot.BezierCurveRenderer.prototype.makeGridData = function(data, plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var gd = [];
+ var pgd = [];
+ // if seriesIndex = 0, fill to x axis.
+ // if seriesIndex > 0, fill to previous series data.
+ var idx = this.index;
+ if (data.length == 2) {
+ if (idx == 0) {
+ gd = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]),
+ xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])],
+ [xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, this._yaxis.min)],
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)]
+ ];
+ }
+ else {
+ var psd = plot.series[idx-1].data;
+ gd = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]),
+ xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])],
+ [xp.call(this._xaxis, psd[1][4]), yp.call(this._yaxis, psd[1][5])],
+ [xp.call(this._xaxis, psd[1][2]), yp.call(this._yaxis, psd[1][3]),
+ xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]),
+ xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])]
+ ];
+ }
+ }
+ else {
+ if (idx == 0) {
+ gd = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]),
+ xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])],
+ [xp.call(this._xaxis, data[3][1]), yp.call(this._yaxis, this._yaxis.min)],
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)]
+ ];
+ }
+ else {
+ var psd = plot.series[idx-1].data;
+ gd = [
+ [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
+ [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
+ xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]),
+ xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])],
+ [xp.call(this._xaxis, psd[3][0]), yp.call(this._yaxis, psd[3][1])],
+ [xp.call(this._xaxis, psd[2][0]), yp.call(this._yaxis, psd[2][1]),
+ xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]),
+ xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])]
+ ];
+ }
+ }
+ return gd;
+ };
+
+
+ // called within scope of series.
+ $.jqplot.BezierCurveRenderer.prototype.draw = function(ctx, gd, options) {
+ var i;
+ ctx.save();
+ if (gd.length) {
+ if (this.showLine) {
+ ctx.save();
+ var opts = (options != null) ? options : {};
+ ctx.fillStyle = opts.fillStyle || this.color;
+ ctx.beginPath();
+ ctx.moveTo(gd[0][0], gd[0][1]);
+ ctx.bezierCurveTo(gd[1][0], gd[1][1], gd[1][2], gd[1][3], gd[1][4], gd[1][5]);
+ ctx.lineTo(gd[2][0], gd[2][1]);
+ if (gd[3].length == 2) {
+ ctx.lineTo(gd[3][0], gd[3][1]);
+ }
+ else {
+ ctx.bezierCurveTo(gd[3][0], gd[3][1], gd[3][2], gd[3][3], gd[3][4], gd[3][5]);
+ }
+ ctx.closePath();
+ ctx.fill();
+ ctx.restore();
+ }
+ }
+
+ ctx.restore();
+ };
+
+ $.jqplot.BezierCurveRenderer.prototype.drawShadow = function(ctx, gd, options) {
+ // This is a no-op, shadows drawn with lines.
+ };
+
+ $.jqplot.BezierAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.BezierAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.BezierAxisRenderer.prototype.constructor = $.jqplot.BezierAxisRenderer;
+
+
+ // Axes on a plot with Bezier Curves
+ $.jqplot.BezierAxisRenderer.prototype.init = function(options){
+ $.extend(true, this, options);
+ var db = this._dataBounds;
+ // Go through all the series attached to this axis and find
+ // the min/max bounds for this axis.
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ var d = s.data;
+ if (d.length == 4) {
+ for (var j=0; j<d.length; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ if (d[j][0] < db.min || db.min == null) {
+ db.min = d[j][0];
+ }
+ if (d[j][0] > db.max || db.max == null) {
+ db.max = d[j][0];
+ }
+ }
+ else {
+ if (d[j][1] < db.min || db.min == null) {
+ db.min = d[j][1];
+ }
+ if (d[j][1] > db.max || db.max == null) {
+ db.max = d[j][1];
+ }
+ }
+ }
+ }
+ else {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ if (d[0][0] < db.min || db.min == null) {
+ db.min = d[0][0];
+ }
+ if (d[0][0] > db.max || db.max == null) {
+ db.max = d[0][0];
+ }
+ for (var j=0; j<5; j+=2) {
+ if (d[1][j] < db.min || db.min == null) {
+ db.min = d[1][j];
+ }
+ if (d[1][j] > db.max || db.max == null) {
+ db.max = d[1][j];
+ }
+ }
+ }
+ else {
+ if (d[0][1] < db.min || db.min == null) {
+ db.min = d[0][1];
+ }
+ if (d[0][1] > db.max || db.max == null) {
+ db.max = d[0][1];
+ }
+ for (var j=1; j<6; j+=2) {
+ if (d[1][j] < db.min || db.min == null) {
+ db.min = d[1][j];
+ }
+ if (d[1][j] > db.max || db.max == null) {
+ db.max = d[1][j];
+ }
+ }
+ }
+ }
+ }
+ };
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = $.extend(true, {pad:0}, options.axesDefaults);
+ options.legend = $.extend(true, {placement:'outside'}, options.legend);
+ // only set these if there is a pie series
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.BezierCurveRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.BezierCurveRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.BezierAxisRenderer;
+ }
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.barRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.barRenderer.js
new file mode 100644
index 00000000..c1be235d
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.barRenderer.js
@@ -0,0 +1,797 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+
+ // Class: $.jqplot.BarRenderer
+ // A plugin renderer for jqPlot to draw a bar plot.
+ // Draws series as a line.
+
+ $.jqplot.BarRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.BarRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.BarRenderer.prototype.constructor = $.jqplot.BarRenderer;
+
+ // called with scope of series.
+ $.jqplot.BarRenderer.prototype.init = function(options, plot) {
+ // Group: Properties
+ //
+ // prop: barPadding
+ // Number of pixels between adjacent bars at the same axis value.
+ this.barPadding = 8;
+ // prop: barMargin
+ // Number of pixels between groups of bars at adjacent axis values.
+ this.barMargin = 10;
+ // prop: barDirection
+ // 'vertical' = up and down bars, 'horizontal' = side to side bars
+ this.barDirection = 'vertical';
+ // prop: barWidth
+ // Width of the bar in pixels (auto by devaul). null = calculated automatically.
+ this.barWidth = null;
+ // prop: shadowOffset
+ // offset of the shadow from the slice and offset of
+ // each succesive stroke of the shadow from the last.
+ this.shadowOffset = 2;
+ // prop: shadowDepth
+ // number of strokes to apply to the shadow,
+ // each stroke offset shadowOffset from the last.
+ this.shadowDepth = 5;
+ // prop: shadowAlpha
+ // transparency of the shadow (0 = transparent, 1 = opaque)
+ this.shadowAlpha = 0.08;
+ // prop: waterfall
+ // true to enable waterfall plot.
+ this.waterfall = false;
+ // prop: groups
+ // group bars into this many groups
+ this.groups = 1;
+ // prop: varyBarColor
+ // true to color each bar of a series separately rather than
+ // have every bar of a given series the same color.
+ // If used for non-stacked multiple series bar plots, user should
+ // specify a separate 'seriesColors' array for each series.
+ // Otherwise, each series will set their bars to the same color array.
+ // This option has no Effect for stacked bar charts and is disabled.
+ this.varyBarColor = false;
+ // prop: highlightMouseOver
+ // True to highlight slice when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over a slice.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColors
+ // an array of colors to use when highlighting a bar.
+ this.highlightColors = [];
+ // prop: transposedData
+ // NOT IMPLEMENTED YET. True if this is a horizontal bar plot and
+ // x and y values are "transposed". Tranposed, or "swapped", data is
+ // required prior to rev. 894 builds of jqPlot with horizontal bars.
+ // Allows backward compatability of bar renderer horizontal bars with
+ // old style data sets.
+ this.transposedData = true;
+ this.renderer.animation = {
+ show: false,
+ direction: 'down',
+ speed: 3000,
+ _supported: true
+ };
+ this._type = 'bar';
+
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
+ options.highlightMouseOver = false;
+ }
+
+ //////
+ // This is probably wrong here.
+ // After going back and forth on wether renderer should be the thing
+ // or extend the thing, it seems that it it best if it is a property
+ // on the thing. This should be something that is commonized
+ // among series renderers in the future.
+ //////
+ $.extend(true, this, options);
+
+ // really should probably do this
+ $.extend(true, this.renderer, options);
+ // fill is still needed to properly draw the legend.
+ // bars have to be filled.
+ this.fill = true;
+
+ // if horizontal bar and animating, reset the default direction
+ if (this.barDirection === 'horizontal' && this.rendererOptions.animation && this.rendererOptions.animation.direction == null) {
+ this.renderer.animation.direction = 'left';
+ }
+
+ if (this.waterfall) {
+ this.fillToZero = false;
+ this.disableStack = true;
+ }
+
+ if (this.barDirection == 'vertical' ) {
+ this._primaryAxis = '_xaxis';
+ this._stackAxis = 'y';
+ this.fillAxis = 'y';
+ }
+ else {
+ this._primaryAxis = '_yaxis';
+ this._stackAxis = 'x';
+ this.fillAxis = 'x';
+ }
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+ // total number of values for all bar series, total number of bar series, and position of this series
+ this._plotSeriesInfo = null;
+ // Array of actual data colors used for each data point.
+ this._dataColors = [];
+ this._barPoints = [];
+
+ // set the shape renderer options
+ var opts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, strokeStyle:this.color, fillStyle:this.color, closePath:this.fill};
+ this.renderer.shapeRenderer.init(opts);
+ // set the shadow renderer options
+ var sopts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, closePath:this.fill};
+ this.renderer.shadowRenderer.init(sopts);
+
+ plot.postInitHooks.addOnce(postInit);
+ plot.postDrawHooks.addOnce(postPlotDraw);
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
+ };
+
+ // called with scope of series
+ function barPreInit(target, data, seriesDefaults, options) {
+ if (this.rendererOptions.barDirection == 'horizontal') {
+ this._stackAxis = 'x';
+ this._primaryAxis = '_yaxis';
+ }
+ if (this.rendererOptions.waterfall == true) {
+ this._data = $.extend(true, [], this.data);
+ var sum = 0;
+ var pos = (!this.rendererOptions.barDirection || this.rendererOptions.barDirection === 'vertical' || this.transposedData === false) ? 1 : 0;
+ for(var i=0; i<this.data.length; i++) {
+ sum += this.data[i][pos];
+ if (i>0) {
+ this.data[i][pos] += this.data[i-1][pos];
+ }
+ }
+ this.data[this.data.length] = (pos == 1) ? [this.data.length+1, sum] : [sum, this.data.length+1];
+ this._data[this._data.length] = (pos == 1) ? [this._data.length+1, sum] : [sum, this._data.length+1];
+ }
+ if (this.rendererOptions.groups > 1) {
+ this.breakOnNull = true;
+ var l = this.data.length;
+ var skip = parseInt(l/this.rendererOptions.groups, 10);
+ var count = 0;
+ for (var i=skip; i<l; i+=skip) {
+ this.data.splice(i+count, 0, [null, null]);
+ this._plotData.splice(i+count, 0, [null, null]);
+ this._stackData.splice(i+count, 0, [null, null]);
+ count++;
+ }
+ for (i=0; i<this.data.length; i++) {
+ if (this._primaryAxis == '_xaxis') {
+ this.data[i][0] = i+1;
+ this._plotData[i][0] = i+1;
+ this._stackData[i][0] = i+1;
+ }
+ else {
+ this.data[i][1] = i+1;
+ this._plotData[i][1] = i+1;
+ this._stackData[i][1] = i+1;
+ }
+ }
+ }
+ }
+
+ $.jqplot.preSeriesInitHooks.push(barPreInit);
+
+ // needs to be called with scope of series, not renderer.
+ $.jqplot.BarRenderer.prototype.calcSeriesNumbers = function() {
+ var nvals = 0;
+ var nseries = 0;
+ var paxis = this[this._primaryAxis];
+ var s, series, pos;
+ // loop through all series on this axis
+ for (var i=0; i < paxis._series.length; i++) {
+ series = paxis._series[i];
+ if (series === this) {
+ pos = i;
+ }
+ // is the series rendered as a bar?
+ if (series.renderer.constructor == $.jqplot.BarRenderer) {
+ // gridData may not be computed yet, use data length insted
+ nvals += series.data.length;
+ nseries += 1;
+ }
+ }
+ // return total number of values for all bar series, total number of bar series, and position of this series
+ return [nvals, nseries, pos];
+ };
+
+ $.jqplot.BarRenderer.prototype.setBarWidth = function() {
+ // need to know how many data values we have on the approprate axis and figure it out.
+ var i;
+ var nvals = 0;
+ var nseries = 0;
+ var paxis = this[this._primaryAxis];
+ var s, series, pos;
+ var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
+ nvals = temp[0];
+ nseries = temp[1];
+ var nticks = paxis.numberTicks;
+ var nbins = (nticks-1)/2;
+ // so, now we have total number of axis values.
+ if (paxis.name == 'xaxis' || paxis.name == 'x2axis') {
+ if (this._stack) {
+ this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals * nseries - this.barMargin;
+ }
+ else {
+ this.barWidth = ((paxis._offsets.max - paxis._offsets.min)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
+ // this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals - this.barPadding - this.barMargin/nseries;
+ }
+ }
+ else {
+ if (this._stack) {
+ this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals * nseries - this.barMargin;
+ }
+ else {
+ this.barWidth = ((paxis._offsets.min - paxis._offsets.max)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
+ // this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals - this.barPadding - this.barMargin/nseries;
+ }
+ }
+ return [nvals, nseries];
+ };
+
+ function computeHighlightColors (colors) {
+ var ret = [];
+ for (var i=0; i<colors.length; i++){
+ var rgba = $.jqplot.getColorComponents(colors[i]);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
+ newrgb[j] = parseInt(newrgb[j], 10);
+ }
+ ret.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
+ }
+ return ret;
+ }
+
+ function getStart(sidx, didx, comp, plot, axis) {
+ // check if sign change
+ var seriesIndex = sidx,
+ prevSeriesIndex = sidx - 1,
+ start,
+ prevVal,
+ aidx = (axis === 'x') ? 0 : 1;
+
+ // is this not the first series?
+ if (seriesIndex > 0) {
+ prevVal = plot.series[prevSeriesIndex]._plotData[didx][aidx];
+
+ // is there a sign change
+ if ((comp * prevVal) < 0) {
+ start = getStart(prevSeriesIndex, didx, comp, plot, axis);
+ }
+
+ // no sign change.
+ else {
+ start = plot.series[prevSeriesIndex].gridData[didx][aidx];
+ }
+
+ }
+
+ // if first series, return value at 0
+ else {
+
+ start = (aidx === 0) ? plot.series[seriesIndex]._xaxis.series_u2p(0) : plot.series[seriesIndex]._yaxis.series_u2p(0);
+ }
+
+ return start;
+ }
+
+
+ $.jqplot.BarRenderer.prototype.draw = function(ctx, gridData, options, plot) {
+ var i;
+ // Ughhh, have to make a copy of options b/c it may be modified later.
+ var opts = $.extend({}, options);
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var xaxis = this.xaxis;
+ var yaxis = this.yaxis;
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var pointx, pointy;
+ // clear out data colors.
+ this._dataColors = [];
+ this._barPoints = [];
+
+ if (this.barWidth == null) {
+ this.renderer.setBarWidth.call(this);
+ }
+
+ var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
+ var nvals = temp[0];
+ var nseries = temp[1];
+ var pos = temp[2];
+ var points = [];
+
+ if (this._stack) {
+ this._barNudge = 0;
+ }
+ else {
+ this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
+ }
+ if (showLine) {
+ var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors);
+ var positiveColors = new $.jqplot.ColorGenerator(this.seriesColors);
+ var negativeColor = negativeColors.get(this.index);
+ if (! this.useNegativeColors) {
+ negativeColor = opts.fillStyle;
+ }
+ var positiveColor = opts.fillStyle;
+ var base;
+ var xstart;
+ var ystart;
+
+ if (this.barDirection == 'vertical') {
+ for (var i=0; i<gridData.length; i++) {
+ if (!this._stack && this.data[i][1] == null) {
+ continue;
+ }
+ points = [];
+ base = gridData[i][0] + this._barNudge;
+
+ // stacked
+ if (this._stack && this._prevGridData.length) {
+ ystart = getStart(this.index, i, this._plotData[i][1], plot, 'y');
+ }
+
+ // not stacked
+ else {
+ if (this.fillToZero) {
+ ystart = this._yaxis.series_u2p(0);
+ }
+ else if (this.waterfall && i > 0 && i < this.gridData.length-1) {
+ ystart = this.gridData[i-1][1];
+ }
+ else if (this.waterfall && i == 0 && i < this.gridData.length-1) {
+ if (this._yaxis.min <= 0 && this._yaxis.max >= 0) {
+ ystart = this._yaxis.series_u2p(0);
+ }
+ else if (this._yaxis.min > 0) {
+ ystart = ctx.canvas.height;
+ }
+ else {
+ ystart = 0;
+ }
+ }
+ else if (this.waterfall && i == this.gridData.length - 1) {
+ if (this._yaxis.min <= 0 && this._yaxis.max >= 0) {
+ ystart = this._yaxis.series_u2p(0);
+ }
+ else if (this._yaxis.min > 0) {
+ ystart = ctx.canvas.height;
+ }
+ else {
+ ystart = 0;
+ }
+ }
+ else {
+ ystart = ctx.canvas.height;
+ }
+ }
+ if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) {
+ if (this.varyBarColor && !this._stack) {
+ if (this.useNegativeColors) {
+ opts.fillStyle = negativeColors.next();
+ }
+ else {
+ opts.fillStyle = positiveColors.next();
+ }
+ }
+ else {
+ opts.fillStyle = negativeColor;
+ }
+ }
+ else {
+ if (this.varyBarColor && !this._stack) {
+ opts.fillStyle = positiveColors.next();
+ }
+ else {
+ opts.fillStyle = positiveColor;
+ }
+ }
+
+ if (!this.fillToZero || this._plotData[i][1] >= 0) {
+ points.push([base-this.barWidth/2, ystart]);
+ points.push([base-this.barWidth/2, gridData[i][1]]);
+ points.push([base+this.barWidth/2, gridData[i][1]]);
+ points.push([base+this.barWidth/2, ystart]);
+ }
+ // for negative bars make sure points are always ordered clockwise
+ else {
+ points.push([base-this.barWidth/2, gridData[i][1]]);
+ points.push([base-this.barWidth/2, ystart]);
+ points.push([base+this.barWidth/2, ystart]);
+ points.push([base+this.barWidth/2, gridData[i][1]]);
+ }
+ this._barPoints.push(points);
+ // now draw the shadows if not stacked.
+ // for stacked plots, they are predrawn by drawShadow
+ if (shadow && !this._stack) {
+ var sopts = $.extend(true, {}, opts);
+ // need to get rid of fillStyle on shadow.
+ delete sopts.fillStyle;
+ this.renderer.shadowRenderer.draw(ctx, points, sopts);
+ }
+ var clr = opts.fillStyle || this.color;
+ this._dataColors.push(clr);
+ this.renderer.shapeRenderer.draw(ctx, points, opts);
+ }
+ }
+
+ else if (this.barDirection == 'horizontal'){
+ for (var i=0; i<gridData.length; i++) {
+ if (!this._stack && this.data[i][0] == null) {
+ continue;
+ }
+ points = [];
+ base = gridData[i][1] - this._barNudge;
+ xstart;
+
+ if (this._stack && this._prevGridData.length) {
+ xstart = getStart(this.index, i, this._plotData[i][0], plot, 'x');
+ }
+ // not stacked
+ else {
+ if (this.fillToZero) {
+ xstart = this._xaxis.series_u2p(0);
+ }
+ else if (this.waterfall && i > 0 && i < this.gridData.length-1) {
+ xstart = this.gridData[i-1][0];
+ }
+ else if (this.waterfall && i == 0 && i < this.gridData.length-1) {
+ if (this._xaxis.min <= 0 && this._xaxis.max >= 0) {
+ xstart = this._xaxis.series_u2p(0);
+ }
+ else if (this._xaxis.min > 0) {
+ xstart = 0;
+ }
+ else {
+ xstart = 0;
+ }
+ }
+ else if (this.waterfall && i == this.gridData.length - 1) {
+ if (this._xaxis.min <= 0 && this._xaxis.max >= 0) {
+ xstart = this._xaxis.series_u2p(0);
+ }
+ else if (this._xaxis.min > 0) {
+ xstart = 0;
+ }
+ else {
+ xstart = ctx.canvas.width;
+ }
+ }
+ else {
+ xstart = 0;
+ }
+ }
+ if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) {
+ if (this.varyBarColor && !this._stack) {
+ if (this.useNegativeColors) {
+ opts.fillStyle = negativeColors.next();
+ }
+ else {
+ opts.fillStyle = positiveColors.next();
+ }
+ }
+ }
+ else {
+ if (this.varyBarColor && !this._stack) {
+ opts.fillStyle = positiveColors.next();
+ }
+ else {
+ opts.fillStyle = positiveColor;
+ }
+ }
+
+
+ if (!this.fillToZero || this._plotData[i][0] >= 0) {
+ points.push([xstart, base + this.barWidth / 2]);
+ points.push([xstart, base - this.barWidth / 2]);
+ points.push([gridData[i][0], base - this.barWidth / 2]);
+ points.push([gridData[i][0], base + this.barWidth / 2]);
+ }
+ else {
+ points.push([gridData[i][0], base + this.barWidth / 2]);
+ points.push([gridData[i][0], base - this.barWidth / 2]);
+ points.push([xstart, base - this.barWidth / 2]);
+ points.push([xstart, base + this.barWidth / 2]);
+ }
+
+ this._barPoints.push(points);
+ // now draw the shadows if not stacked.
+ // for stacked plots, they are predrawn by drawShadow
+ if (shadow && !this._stack) {
+ var sopts = $.extend(true, {}, opts);
+ delete sopts.fillStyle;
+ this.renderer.shadowRenderer.draw(ctx, points, sopts);
+ }
+ var clr = opts.fillStyle || this.color;
+ this._dataColors.push(clr);
+ this.renderer.shapeRenderer.draw(ctx, points, opts);
+ }
+ }
+ }
+
+ if (this.highlightColors.length == 0) {
+ this.highlightColors = $.jqplot.computeHighlightColors(this._dataColors);
+ }
+
+ else if (typeof(this.highlightColors) == 'string') {
+ var temp = this.highlightColors;
+ this.highlightColors = [];
+ for (var i=0; i<this._dataColors.length; i++) {
+ this.highlightColors.push(temp);
+ }
+ }
+
+ };
+
+
+ // for stacked plots, shadows will be pre drawn by drawShadow.
+ $.jqplot.BarRenderer.prototype.drawShadow = function(ctx, gridData, options, plot) {
+ var i;
+ var opts = (options != undefined) ? options : {};
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var xaxis = this.xaxis;
+ var yaxis = this.yaxis;
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var pointx, points, pointy, nvals, nseries, pos;
+
+ if (this._stack && this.shadow) {
+ if (this.barWidth == null) {
+ this.renderer.setBarWidth.call(this);
+ }
+
+ var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
+ nvals = temp[0];
+ nseries = temp[1];
+ pos = temp[2];
+
+ if (this._stack) {
+ this._barNudge = 0;
+ }
+ else {
+ this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
+ }
+ if (showLine) {
+
+ if (this.barDirection == 'vertical') {
+ for (var i=0; i<gridData.length; i++) {
+ if (this.data[i][1] == null) {
+ continue;
+ }
+ points = [];
+ var base = gridData[i][0] + this._barNudge;
+ var ystart;
+
+ if (this._stack && this._prevGridData.length) {
+ ystart = getStart(this.index, i, this._plotData[i][1], plot, 'y');
+ }
+ else {
+ if (this.fillToZero) {
+ ystart = this._yaxis.series_u2p(0);
+ }
+ else {
+ ystart = ctx.canvas.height;
+ }
+ }
+
+ points.push([base-this.barWidth/2, ystart]);
+ points.push([base-this.barWidth/2, gridData[i][1]]);
+ points.push([base+this.barWidth/2, gridData[i][1]]);
+ points.push([base+this.barWidth/2, ystart]);
+ this.renderer.shadowRenderer.draw(ctx, points, opts);
+ }
+ }
+
+ else if (this.barDirection == 'horizontal'){
+ for (var i=0; i<gridData.length; i++) {
+ if (this.data[i][0] == null) {
+ continue;
+ }
+ points = [];
+ var base = gridData[i][1] - this._barNudge;
+ var xstart;
+
+ if (this._stack && this._prevGridData.length) {
+ xstart = getStart(this.index, i, this._plotData[i][0], plot, 'x');
+ }
+ else {
+ if (this.fillToZero) {
+ xstart = this._xaxis.series_u2p(0);
+ }
+ else {
+ xstart = 0;
+ }
+ }
+
+ points.push([xstart, base+this.barWidth/2]);
+ points.push([gridData[i][0], base+this.barWidth/2]);
+ points.push([gridData[i][0], base-this.barWidth/2]);
+ points.push([xstart, base-this.barWidth/2]);
+ this.renderer.shadowRenderer.draw(ctx, points, opts);
+ }
+ }
+ }
+
+ }
+ };
+
+ function postInit(target, data, options) {
+ for (var i=0; i<this.series.length; i++) {
+ if (this.series[i].renderer.constructor == $.jqplot.BarRenderer) {
+ // don't allow mouseover and mousedown at same time.
+ if (this.series[i].highlightMouseOver) {
+ this.series[i].highlightMouseDown = false;
+ }
+ }
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.barRenderer && this.plugins.barRenderer.highlightCanvas) {
+
+ this.plugins.barRenderer.highlightCanvas.resetCanvas();
+ this.plugins.barRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.barRenderer = {highlightedSeriesIndex:null};
+ this.plugins.barRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ this.eventCanvas._elem.before(this.plugins.barRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-barRenderer-highlight-canvas', this._plotDimensions, this));
+ this.plugins.barRenderer.highlightCanvas.setContext();
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
+ }
+
+ function highlight (plot, sidx, pidx, points) {
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.barRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.barRenderer.highlightedSeriesIndex = sidx;
+ var opts = {fillStyle: s.highlightColors[pidx]};
+ s.renderer.shapeRenderer.draw(canvas._ctx, points, opts);
+ canvas = null;
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.barRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.barRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ canvas = null;
+ }
+
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
+ var idx = plot.plugins.barRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ }
+
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt = jQuery.Event('jqplotDataClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var idx = plot.plugins.barRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ var evt = jQuery.Event('jqplotDataRightClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.blockRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.blockRenderer.js
new file mode 100644
index 00000000..5f2bc341
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.blockRenderer.js
@@ -0,0 +1,235 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.BlockRenderer
+ * Plugin renderer to draw a x-y block chart. A Block chart has data points displayed as
+ * colored squares with a text label inside. Data must be supplied in the form:
+ *
+ * > [[x1, y1, "label 1", {css}], [x2, y2, "label 2", {css}], ...]
+ *
+ * The label and css object are optional. If the label is ommitted, the
+ * box will collapse unless a css height and/or width is specified.
+ *
+ * The css object is an object specifying css properties
+ * such as:
+ *
+ * > {background:'#4f98a5', border:'3px solid gray', padding:'1px'}
+ *
+ * Note that css properties specified with the data point override defaults
+ * specified with the series.
+ *
+ */
+ $.jqplot.BlockRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.BlockRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.BlockRenderer.prototype.constructor = $.jqplot.BlockRenderer;
+
+ // called with scope of a series
+ $.jqplot.BlockRenderer.prototype.init = function(options) {
+ // Group: Properties
+ //
+ // prop: css
+ // default css styles that will be applied to all data blocks.
+ // these values will be overridden by css styles supplied with the
+ // individulal data points.
+ this.css = {padding:'2px', border:'1px solid #999', textAlign:'center'};
+ // prop: escapeHtml
+ // true to escape html in the box label.
+ this.escapeHtml = false;
+ // prop: insertBreaks
+ // true to turn spaces in data block label into html breaks <br />.
+ this.insertBreaks = true;
+ // prop: varyBlockColors
+ // true to vary the color of each block in this series according to
+ // the seriesColors array. False to set each block to the color
+ // specified on this series. This has no effect if a css background color
+ // option is specified in the renderer css options.
+ this.varyBlockColors = false;
+ $.extend(true, this, options);
+ if (this.css.backgroundColor) {
+ this.color = this.css.backgroundColor;
+ }
+ else if (this.css.background) {
+ this.color = this.css.background;
+ }
+ else if (!this.varyBlockColors) {
+ this.css.background = this.color;
+ }
+ this.canvas = new $.jqplot.BlockCanvas();
+ this.shadowCanvas = new $.jqplot.BlockCanvas();
+ this.canvas._plotDimensions = this._plotDimensions;
+ this.shadowCanvas._plotDimensions = this._plotDimensions;
+ this._type = 'block';
+
+ // group: Methods
+ //
+ // Method: moveBlock
+ // Moves an individual block. More efficient than redrawing
+ // the whole series by calling plot.drawSeries().
+ // Properties:
+ // idx - the 0 based index of the block or point in this series.
+ // x - the x coordinate in data units (value on x axis) to move the block to.
+ // y - the y coordinate in data units (value on the y axis) to move the block to.
+ // duration - optional parameter to create an animated movement. Can be a
+ // number (higher is slower animation) or 'fast', 'normal' or 'slow'. If not
+ // provided, the element is moved without any animation.
+ this.moveBlock = function (idx, x, y, duration) {
+ // update plotData, stackData, data and gridData
+ // x and y are in data coordinates.
+ var el = this.canvas._elem.children(':eq('+idx+')');
+ this.data[idx][0] = x;
+ this.data[idx][1] = y;
+ this._plotData[idx][0] = x;
+ this._plotData[idx][1] = y;
+ this._stackData[idx][0] = x;
+ this._stackData[idx][1] = y;
+ this.gridData[idx][0] = this._xaxis.series_u2p(x);
+ this.gridData[idx][1] = this._yaxis.series_u2p(y);
+ var w = el.outerWidth();
+ var h = el.outerHeight();
+ var left = this.gridData[idx][0] - w/2 + 'px';
+ var top = this.gridData[idx][1] - h/2 + 'px';
+ if (duration) {
+ if (parseInt(duration, 10)) {
+ duration = parseInt(duration, 10);
+ }
+ el.animate({left:left, top:top}, duration);
+ }
+ else {
+ el.css({left:left, top:top});
+ }
+ el = null;
+ };
+ };
+
+ // called with scope of series
+ $.jqplot.BlockRenderer.prototype.draw = function (ctx, gd, options) {
+ if (this.plugins.pointLabels) {
+ this.plugins.pointLabels.show = false;
+ }
+ var i, el, d, gd, t, css, w, h, left, top;
+ var opts = (options != undefined) ? options : {};
+ var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
+ this.canvas._elem.empty();
+ for (i=0; i<this.gridData.length; i++) {
+ d = this.data[i];
+ gd = this.gridData[i];
+ t = '';
+ css = {};
+ if (typeof d[2] == 'string') {
+ t = d[2];
+ }
+ else if (typeof d[2] == 'object') {
+ css = d[2];
+ }
+ if (typeof d[3] == 'object') {
+ css = d[3];
+ }
+ if (this.insertBreaks){
+ t = t.replace(/ /g, '<br />');
+ }
+ css = $.extend(true, {}, this.css, css);
+ // create a div
+ el = $('<div style="position:absolute;margin-left:auto;margin-right:auto;"></div>');
+ this.canvas._elem.append(el);
+ // set text
+ this.escapeHtml ? el.text(t) : el.html(t);
+ // style it
+ // remove styles we don't want overridden.
+ delete css.position;
+ delete css.marginRight;
+ delete css.marginLeft;
+ if (!css.background && !css.backgroundColor && !css.backgroundImage){
+ css.background = colorGenerator.next();
+ }
+ el.css(css);
+ w = el.outerWidth();
+ h = el.outerHeight();
+ left = gd[0] - w/2 + 'px';
+ top = gd[1] - h/2 + 'px';
+ el.css({left:left, top:top});
+ el = null;
+ }
+ };
+
+ $.jqplot.BlockCanvas = function() {
+ $.jqplot.ElemContainer.call(this);
+ this._ctx;
+ };
+
+ $.jqplot.BlockCanvas.prototype = new $.jqplot.ElemContainer();
+ $.jqplot.BlockCanvas.prototype.constructor = $.jqplot.BlockCanvas;
+
+ $.jqplot.BlockCanvas.prototype.createElement = function(offsets, clss, plotDimensions) {
+ this._offsets = offsets;
+ var klass = 'jqplot-blockCanvas';
+ if (clss != undefined) {
+ klass = clss;
+ }
+ var elem;
+ // if this canvas already has a dom element, don't make a new one.
+ if (this._elem) {
+ elem = this._elem.get(0);
+ }
+ else {
+ elem = document.createElement('div');
+ }
+ // if new plotDimensions supplied, use them.
+ if (plotDimensions != undefined) {
+ this._plotDimensions = plotDimensions;
+ }
+
+ var w = this._plotDimensions.width - this._offsets.left - this._offsets.right + 'px';
+ var h = this._plotDimensions.height - this._offsets.top - this._offsets.bottom + 'px';
+ this._elem = $(elem);
+ this._elem.css({ position: 'absolute', width:w, height:h, left: this._offsets.left, top: this._offsets.top });
+
+ this._elem.addClass(klass);
+ return this._elem;
+ };
+
+ $.jqplot.BlockCanvas.prototype.setContext = function() {
+ this._ctx = {
+ canvas:{
+ width:0,
+ height:0
+ },
+ clearRect:function(){return null;}
+ };
+ return this._ctx;
+ };
+
+})(jQuery);
+
+ \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.bubbleRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.bubbleRenderer.js
new file mode 100644
index 00000000..d46f7b77
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.bubbleRenderer.js
@@ -0,0 +1,759 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ var arrayMax = function( array ){
+ return Math.max.apply( Math, array );
+ };
+ var arrayMin = function( array ){
+ return Math.min.apply( Math, array );
+ };
+
+ /**
+ * Class: $.jqplot.BubbleRenderer
+ * Plugin renderer to draw a bubble chart. A Bubble chart has data points displayed as
+ * colored circles with an optional text label inside. To use
+ * the bubble renderer, you must include the bubble renderer like:
+ *
+ * > <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.bubbleRenderer.js"></script>
+ *
+ * Data must be supplied in
+ * the form:
+ *
+ * > [[x1, y1, r1, <label or {label:'text', color:color}>], ...]
+ *
+ * where the label or options
+ * object is optional.
+ *
+ * Note that all bubble colors will be the same
+ * unless the "varyBubbleColors" option is set to true. Colors can be specified in the data array
+ * or in the seriesColors array option on the series. If no colors are defined, the default jqPlot
+ * series of 16 colors are used. Colors are automatically cycled around again if there are more
+ * bubbles than colors.
+ *
+ * Bubbles are autoscaled by default to fit within the chart area while maintaining
+ * relative sizes. If the "autoscaleBubbles" option is set to false, the r(adius) values
+ * in the data array a treated as literal pixel values for the radii of the bubbles.
+ *
+ * Properties are passed into the bubble renderer in the rendererOptions object of
+ * the series options like:
+ *
+ * > seriesDefaults: {
+ * > renderer: $.jqplot.BubbleRenderer,
+ * > rendererOptions: {
+ * > bubbleAlpha: 0.7,
+ * > varyBubbleColors: false
+ * > }
+ * > }
+ *
+ */
+ $.jqplot.BubbleRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.BubbleRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.BubbleRenderer.prototype.constructor = $.jqplot.BubbleRenderer;
+
+ // called with scope of a series
+ $.jqplot.BubbleRenderer.prototype.init = function(options, plot) {
+ // Group: Properties
+ //
+ // prop: varyBubbleColors
+ // True to vary the color of each bubble in this series according to
+ // the seriesColors array. False to set each bubble to the color
+ // specified on this series. This has no effect if a css background color
+ // option is specified in the renderer css options.
+ this.varyBubbleColors = true;
+ // prop: autoscaleBubbles
+ // True to scale the bubble radius based on plot size.
+ // False will use the radius value as provided as a raw pixel value for
+ // bubble radius.
+ this.autoscaleBubbles = true;
+ // prop: autoscaleMultiplier
+ // Multiplier the bubble size if autoscaleBubbles is true.
+ this.autoscaleMultiplier = 1.0;
+ // prop: autoscalePointsFactor
+ // Factor which decreases bubble size based on how many bubbles on on the chart.
+ // 0 means no adjustment for number of bubbles. Negative values will decrease
+ // size of bubbles as more bubbles are added. Values between 0 and -0.2
+ // should work well.
+ this.autoscalePointsFactor = -0.07;
+ // prop: escapeHtml
+ // True to escape html in bubble label text.
+ this.escapeHtml = true;
+ // prop: highlightMouseOver
+ // True to highlight bubbles when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over a bubble.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColors
+ // An array of colors to use when highlighting a slice. Calculated automatically
+ // if not supplied.
+ this.highlightColors = [];
+ // prop: bubbleAlpha
+ // Alpha transparency to apply to all bubbles in this series.
+ this.bubbleAlpha = 1.0;
+ // prop: highlightAlpha
+ // Alpha transparency to apply when highlighting bubble.
+ // Set to value of bubbleAlpha by default.
+ this.highlightAlpha = null;
+ // prop: bubbleGradients
+ // True to color the bubbles with gradient fills instead of flat colors.
+ // NOT AVAILABLE IN IE due to lack of excanvas support for radial gradient fills.
+ // will be ignored in IE.
+ this.bubbleGradients = false;
+ // prop: showLabels
+ // True to show labels on bubbles (if any), false to not show.
+ this.showLabels = true;
+ // array of [point index, radius] which will be sorted in descending order to plot
+ // largest points below smaller points.
+ this.radii = [];
+ this.maxRadius = 0;
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+ // array of jQuery labels.
+ this.labels = [];
+ this.bubbleCanvases = [];
+ this._type = 'bubble';
+
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
+ options.highlightMouseOver = false;
+ }
+
+ $.extend(true, this, options);
+
+ if (this.highlightAlpha == null) {
+ this.highlightAlpha = this.bubbleAlpha;
+ if (this.bubbleGradients) {
+ this.highlightAlpha = 0.35;
+ }
+ }
+
+ this.autoscaleMultiplier = this.autoscaleMultiplier * Math.pow(this.data.length, this.autoscalePointsFactor);
+
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+
+ // adjust the series colors for options colors passed in with data or for alpha.
+ // note, this can leave undefined holes in the seriesColors array.
+ var comps;
+ for (var i=0; i<this.data.length; i++) {
+ var color = null;
+ var d = this.data[i];
+ this.maxRadius = Math.max(this.maxRadius, d[2]);
+ if (d[3]) {
+ if (typeof(d[3]) == 'object') {
+ color = d[3]['color'];
+ }
+ }
+
+ if (color == null) {
+ if (this.seriesColors[i] != null) {
+ color = this.seriesColors[i];
+ }
+ }
+
+ if (color && this.bubbleAlpha < 1.0) {
+ comps = $.jqplot.getColorComponents(color);
+ color = 'rgba('+comps[0]+', '+comps[1]+', '+comps[2]+', '+this.bubbleAlpha+')';
+ }
+
+ if (color) {
+ this.seriesColors[i] = color;
+ }
+ }
+
+ if (!this.varyBubbleColors) {
+ this.seriesColors = [this.color];
+ }
+
+ this.colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
+
+ // set highlight colors if none provided
+ if (this.highlightColors.length == 0) {
+ for (var i=0; i<this.seriesColors.length; i++){
+ var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
+ newrgb[j] = parseInt(newrgb[j], 10);
+ }
+ this.highlightColors.push('rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+', '+this.highlightAlpha+')');
+ }
+ }
+
+ this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors);
+
+ var sopts = {fill:true, isarc:true, angle:this.shadowAngle, alpha:this.shadowAlpha, closePath:true};
+
+ this.renderer.shadowRenderer.init(sopts);
+
+ this.canvas = new $.jqplot.DivCanvas();
+ this.canvas._plotDimensions = this._plotDimensions;
+
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
+ plot.postDrawHooks.addOnce(postPlotDraw);
+
+ };
+
+
+ // converts the user data values to grid coordinates and stores them
+ // in the gridData array.
+ // Called with scope of a series.
+ $.jqplot.BubbleRenderer.prototype.setGridData = function(plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var data = this._plotData;
+ this.gridData = [];
+ var radii = [];
+ this.radii = [];
+ var dim = Math.min(plot._height, plot._width);
+ for (var i=0; i<this.data.length; i++) {
+ if (data[i] != null) {
+ this.gridData.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1]), data[i][2]]);
+ this.radii.push([i, data[i][2]]);
+ radii.push(data[i][2]);
+ }
+ }
+ var r, val, maxr = this.maxRadius = arrayMax(radii);
+ var l = this.gridData.length;
+ if (this.autoscaleBubbles) {
+ for (var i=0; i<l; i++) {
+ val = radii[i]/maxr;
+ r = this.autoscaleMultiplier * dim / 6;
+ this.gridData[i][2] = r * val;
+ }
+ }
+
+ this.radii.sort(function(a, b) { return b[1] - a[1]; });
+ };
+
+ // converts any arbitrary data values to grid coordinates and
+ // returns them. This method exists so that plugins can use a series'
+ // linerenderer to generate grid data points without overwriting the
+ // grid data associated with that series.
+ // Called with scope of a series.
+ $.jqplot.BubbleRenderer.prototype.makeGridData = function(data, plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var gd = [];
+ var radii = [];
+ this.radii = [];
+ var dim = Math.min(plot._height, plot._width);
+ for (var i=0; i<data.length; i++) {
+ if (data[i] != null) {
+ gd.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1]), data[i][2]]);
+ radii.push(data[i][2]);
+ this.radii.push([i, data[i][2]]);
+ }
+ }
+ var r, val, maxr = this.maxRadius = arrayMax(radii);
+ var l = this.gridData.length;
+ if (this.autoscaleBubbles) {
+ for (var i=0; i<l; i++) {
+ val = radii[i]/maxr;
+ r = this.autoscaleMultiplier * dim / 6;
+ gd[i][2] = r * val;
+ }
+ }
+ this.radii.sort(function(a, b) { return b[1] - a[1]; });
+ return gd;
+ };
+
+ // called with scope of series
+ $.jqplot.BubbleRenderer.prototype.draw = function (ctx, gd, options) {
+ if (this.plugins.pointLabels) {
+ this.plugins.pointLabels.show = false;
+ }
+ var opts = (options != undefined) ? options : {};
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ this.canvas._elem.empty();
+ for (var i=0; i<this.radii.length; i++) {
+ var idx = this.radii[i][0];
+ var t=null;
+ var color = null;
+ var el = null;
+ var tel = null;
+ var d = this.data[idx];
+ var gd = this.gridData[idx];
+ if (d[3]) {
+ if (typeof(d[3]) == 'object') {
+ t = d[3]['label'];
+ }
+ else if (typeof(d[3]) == 'string') {
+ t = d[3];
+ }
+ }
+
+ // color = (this.varyBubbleColors) ? this.colorGenerator.get(idx) : this.color;
+ color = this.colorGenerator.get(idx);
+
+ // If we're drawing a shadow, expand the canvas dimensions to accomodate.
+ var canvasRadius = gd[2];
+ var offset, depth;
+ if (this.shadow) {
+ offset = (0.7 + gd[2]/40).toFixed(1);
+ depth = 1 + Math.ceil(gd[2]/15);
+ canvasRadius += offset*depth;
+ }
+ this.bubbleCanvases[idx] = new $.jqplot.BubbleCanvas();
+ this.canvas._elem.append(this.bubbleCanvases[idx].createElement(gd[0], gd[1], canvasRadius));
+ this.bubbleCanvases[idx].setContext();
+ var ctx = this.bubbleCanvases[idx]._ctx;
+ var x = ctx.canvas.width/2;
+ var y = ctx.canvas.height/2;
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [x, y, gd[2], 0, 2*Math.PI], {offset: offset, depth: depth});
+ }
+ this.bubbleCanvases[idx].draw(gd[2], color, this.bubbleGradients, this.shadowAngle/180*Math.PI);
+
+ // now draw label.
+ if (t && this.showLabels) {
+ tel = $('<div style="position:absolute;" class="jqplot-bubble-label"></div>');
+ if (this.escapeHtml) {
+ tel.text(t);
+ }
+ else {
+ tel.html(t);
+ }
+ this.canvas._elem.append(tel);
+ var h = $(tel).outerHeight();
+ var w = $(tel).outerWidth();
+ var top = gd[1] - 0.5*h;
+ var left = gd[0] - 0.5*w;
+ tel.css({top: top, left: left});
+ this.labels[idx] = $(tel);
+ }
+ }
+ };
+
+
+ $.jqplot.DivCanvas = function() {
+ $.jqplot.ElemContainer.call(this);
+ this._ctx;
+ };
+
+ $.jqplot.DivCanvas.prototype = new $.jqplot.ElemContainer();
+ $.jqplot.DivCanvas.prototype.constructor = $.jqplot.DivCanvas;
+
+ $.jqplot.DivCanvas.prototype.createElement = function(offsets, clss, plotDimensions) {
+ this._offsets = offsets;
+ var klass = 'jqplot-DivCanvas';
+ if (clss != undefined) {
+ klass = clss;
+ }
+ var elem;
+ // if this canvas already has a dom element, don't make a new one.
+ if (this._elem) {
+ elem = this._elem.get(0);
+ }
+ else {
+ elem = document.createElement('div');
+ }
+ // if new plotDimensions supplied, use them.
+ if (plotDimensions != undefined) {
+ this._plotDimensions = plotDimensions;
+ }
+
+ var w = this._plotDimensions.width - this._offsets.left - this._offsets.right + 'px';
+ var h = this._plotDimensions.height - this._offsets.top - this._offsets.bottom + 'px';
+ this._elem = $(elem);
+ this._elem.css({ position: 'absolute', width:w, height:h, left: this._offsets.left, top: this._offsets.top });
+
+ this._elem.addClass(klass);
+ return this._elem;
+ };
+
+ $.jqplot.DivCanvas.prototype.setContext = function() {
+ this._ctx = {
+ canvas:{
+ width:0,
+ height:0
+ },
+ clearRect:function(){return null;}
+ };
+ return this._ctx;
+ };
+
+ $.jqplot.BubbleCanvas = function() {
+ $.jqplot.ElemContainer.call(this);
+ this._ctx;
+ };
+
+ $.jqplot.BubbleCanvas.prototype = new $.jqplot.ElemContainer();
+ $.jqplot.BubbleCanvas.prototype.constructor = $.jqplot.BubbleCanvas;
+
+ // initialize with the x,y pont of bubble center and the bubble radius.
+ $.jqplot.BubbleCanvas.prototype.createElement = function(x, y, r) {
+ var klass = 'jqplot-bubble-point';
+
+ var elem;
+ // if this canvas already has a dom element, don't make a new one.
+ if (this._elem) {
+ elem = this._elem.get(0);
+ }
+ else {
+ elem = document.createElement('canvas');
+ }
+
+ elem.width = (r != null) ? 2*r : elem.width;
+ elem.height = (r != null) ? 2*r : elem.height;
+ this._elem = $(elem);
+ var l = (x != null && r != null) ? x - r : this._elem.css('left');
+ var t = (y != null && r != null) ? y - r : this._elem.css('top');
+ this._elem.css({ position: 'absolute', left: l, top: t });
+
+ this._elem.addClass(klass);
+ if ($.jqplot.use_excanvas) {
+ window.G_vmlCanvasManager.init_(document);
+ elem = window.G_vmlCanvasManager.initElement(elem);
+ }
+
+ return this._elem;
+ };
+
+ $.jqplot.BubbleCanvas.prototype.draw = function(r, color, gradients, angle) {
+ var ctx = this._ctx;
+ // r = Math.floor(r*1.04);
+ // var x = Math.round(ctx.canvas.width/2);
+ // var y = Math.round(ctx.canvas.height/2);
+ var x = ctx.canvas.width/2;
+ var y = ctx.canvas.height/2;
+ ctx.save();
+ if (gradients && !$.jqplot.use_excanvas) {
+ r = r*1.04;
+ var comps = $.jqplot.getColorComponents(color);
+ var colorinner = 'rgba('+Math.round(comps[0]+0.8*(255-comps[0]))+', '+Math.round(comps[1]+0.8*(255-comps[1]))+', '+Math.round(comps[2]+0.8*(255-comps[2]))+', '+comps[3]+')';
+ var colorend = 'rgba('+comps[0]+', '+comps[1]+', '+comps[2]+', 0)';
+ // var rinner = Math.round(0.35 * r);
+ // var xinner = Math.round(x - Math.cos(angle) * 0.33 * r);
+ // var yinner = Math.round(y - Math.sin(angle) * 0.33 * r);
+ var rinner = 0.35 * r;
+ var xinner = x - Math.cos(angle) * 0.33 * r;
+ var yinner = y - Math.sin(angle) * 0.33 * r;
+ var radgrad = ctx.createRadialGradient(xinner, yinner, rinner, x, y, r);
+ radgrad.addColorStop(0, colorinner);
+ radgrad.addColorStop(0.93, color);
+ radgrad.addColorStop(0.96, colorend);
+ radgrad.addColorStop(1, colorend);
+ // radgrad.addColorStop(.98, colorend);
+ ctx.fillStyle = radgrad;
+ ctx.fillRect(0,0, ctx.canvas.width, ctx.canvas.height);
+ }
+ else {
+ ctx.fillStyle = color;
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 1;
+ ctx.beginPath();
+ var ang = 2*Math.PI;
+ ctx.arc(x, y, r, 0, ang, 0);
+ ctx.closePath();
+ ctx.fill();
+ }
+ ctx.restore();
+ };
+
+ $.jqplot.BubbleCanvas.prototype.setContext = function() {
+ this._ctx = this._elem.get(0).getContext("2d");
+ return this._ctx;
+ };
+
+ $.jqplot.BubbleAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.BubbleAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.BubbleAxisRenderer.prototype.constructor = $.jqplot.BubbleAxisRenderer;
+
+ // called with scope of axis object.
+ $.jqplot.BubbleAxisRenderer.prototype.init = function(options){
+ $.extend(true, this, options);
+ var db = this._dataBounds;
+ var minsidx = 0,
+ minpidx = 0,
+ maxsidx = 0,
+ maxpidx = 0,
+ maxr = 0,
+ minr = 0,
+ minMaxRadius = 0,
+ maxMaxRadius = 0,
+ maxMult = 0,
+ minMult = 0;
+ // Go through all the series attached to this axis and find
+ // the min/max bounds for this axis.
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ var d = s._plotData;
+
+ for (var j=0; j<d.length; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ if (d[j][0] < db.min || db.min == null) {
+ db.min = d[j][0];
+ minsidx=i;
+ minpidx=j;
+ minr = d[j][2];
+ minMaxRadius = s.maxRadius;
+ minMult = s.autoscaleMultiplier;
+ }
+ if (d[j][0] > db.max || db.max == null) {
+ db.max = d[j][0];
+ maxsidx=i;
+ maxpidx=j;
+ maxr = d[j][2];
+ maxMaxRadius = s.maxRadius;
+ maxMult = s.autoscaleMultiplier;
+ }
+ }
+ else {
+ if (d[j][1] < db.min || db.min == null) {
+ db.min = d[j][1];
+ minsidx=i;
+ minpidx=j;
+ minr = d[j][2];
+ minMaxRadius = s.maxRadius;
+ minMult = s.autoscaleMultiplier;
+ }
+ if (d[j][1] > db.max || db.max == null) {
+ db.max = d[j][1];
+ maxsidx=i;
+ maxpidx=j;
+ maxr = d[j][2];
+ maxMaxRadius = s.maxRadius;
+ maxMult = s.autoscaleMultiplier;
+ }
+ }
+ }
+ }
+
+ var minRatio = minr/minMaxRadius;
+ var maxRatio = maxr/maxMaxRadius;
+
+ // need to estimate the effect of the radius on total axis span and adjust axis accordingly.
+ var span = db.max - db.min;
+ // var dim = (this.name == 'xaxis' || this.name == 'x2axis') ? this._plotDimensions.width : this._plotDimensions.height;
+ var dim = Math.min(this._plotDimensions.width, this._plotDimensions.height);
+
+ var minfact = minRatio * minMult/3 * span;
+ var maxfact = maxRatio * maxMult/3 * span;
+ db.max += maxfact;
+ db.min -= minfact;
+ };
+
+ function highlight (plot, sidx, pidx) {
+ plot.plugins.bubbleRenderer.highlightLabelCanvas.empty();
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.bubbleRenderer.highlightCanvas;
+ var ctx = canvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.bubbleRenderer.highlightedSeriesIndex = sidx;
+
+ var color = s.highlightColorGenerator.get(pidx);
+ var x = s.gridData[pidx][0],
+ y = s.gridData[pidx][1],
+ r = s.gridData[pidx][2];
+ ctx.save();
+ ctx.fillStyle = color;
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 1;
+ ctx.beginPath();
+ ctx.arc(x, y, r, 0, 2*Math.PI, 0);
+ ctx.closePath();
+ ctx.fill();
+ ctx.restore();
+ // bring label to front
+ if (s.labels[pidx]) {
+ plot.plugins.bubbleRenderer.highlightLabel = s.labels[pidx].clone();
+ plot.plugins.bubbleRenderer.highlightLabel.appendTo(plot.plugins.bubbleRenderer.highlightLabelCanvas);
+ plot.plugins.bubbleRenderer.highlightLabel.addClass('jqplot-bubble-label-highlight');
+ }
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.bubbleRenderer.highlightCanvas;
+ var sidx = plot.plugins.bubbleRenderer.highlightedSeriesIndex;
+ plot.plugins.bubbleRenderer.highlightLabelCanvas.empty();
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.bubbleRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ }
+
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var si = neighbor.seriesIndex;
+ var pi = neighbor.pointIndex;
+ var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.bubbleRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var si = neighbor.seriesIndex;
+ var pi = neighbor.pointIndex;
+ var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]];
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.bubbleRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
+ var idx = plot.plugins.bubbleRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ }
+
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var si = neighbor.seriesIndex;
+ var pi = neighbor.pointIndex;
+ var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]];
+ var evt = jQuery.Event('jqplotDataClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var si = neighbor.seriesIndex;
+ var pi = neighbor.pointIndex;
+ var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]];
+ var idx = plot.plugins.bubbleRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ var evt = jQuery.Event('jqplotDataRightClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.bubbleRenderer && this.plugins.bubbleRenderer.highlightCanvas) {
+ this.plugins.bubbleRenderer.highlightCanvas.resetCanvas();
+ this.plugins.bubbleRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.bubbleRenderer = {highlightedSeriesIndex:null};
+ this.plugins.bubbleRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+ this.plugins.bubbleRenderer.highlightLabel = null;
+ this.plugins.bubbleRenderer.highlightLabelCanvas = $('<div style="position:absolute;"></div>');
+ var top = this._gridPadding.top;
+ var left = this._gridPadding.left;
+ var width = this._plotDimensions.width - this._gridPadding.left - this._gridPadding.right;
+ var height = this._plotDimensions.height - this._gridPadding.top - this._gridPadding.bottom;
+ this.plugins.bubbleRenderer.highlightLabelCanvas.css({top:top, left:left, width:width+'px', height:height+'px'});
+
+ this.eventCanvas._elem.before(this.plugins.bubbleRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-bubbleRenderer-highlight-canvas', this._plotDimensions, this));
+ this.eventCanvas._elem.before(this.plugins.bubbleRenderer.highlightLabelCanvas);
+
+ var hctx = this.plugins.bubbleRenderer.highlightCanvas.setContext();
+ }
+
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ // only set these if there is a Bubble series
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.BubbleRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.BubbleRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.BubbleAxisRenderer;
+ options.sortData = false;
+ }
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+
+})(jQuery);
+
+ \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisLabelRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisLabelRenderer.js
new file mode 100644
index 00000000..18404399
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisLabelRenderer.js
@@ -0,0 +1,203 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.CanvasAxisLabelRenderer
+ * Renderer to draw axis labels with a canvas element to support advanced
+ * featrues such as rotated text. This renderer uses a separate rendering engine
+ * to draw the text on the canvas. Two modes of rendering the text are available.
+ * If the browser has native font support for canvas fonts (currently Mozila 3.5
+ * and Safari 4), you can enable text rendering with the canvas fillText method.
+ * You do so by setting the "enableFontSupport" option to true.
+ *
+ * Browsers lacking native font support will have the text drawn on the canvas
+ * using the Hershey font metrics. Even if the "enableFontSupport" option is true
+ * non-supporting browsers will still render with the Hershey font.
+ *
+ */
+ $.jqplot.CanvasAxisLabelRenderer = function(options) {
+ // Group: Properties
+
+ // prop: angle
+ // angle of text, measured clockwise from x axis.
+ this.angle = 0;
+ // name of the axis associated with this tick
+ this.axis;
+ // prop: show
+ // wether or not to show the tick (mark and label).
+ this.show = true;
+ // prop: showLabel
+ // wether or not to show the label.
+ this.showLabel = true;
+ // prop: label
+ // label for the axis.
+ this.label = '';
+ // prop: fontFamily
+ // CSS spec for the font-family css attribute.
+ // Applies only to browsers supporting native font rendering in the
+ // canvas tag. Currently Mozilla 3.5 and Safari 4.
+ this.fontFamily = '"Trebuchet MS", Arial, Helvetica, sans-serif';
+ // prop: fontSize
+ // CSS spec for font size.
+ this.fontSize = '11pt';
+ // prop: fontWeight
+ // CSS spec for fontWeight: normal, bold, bolder, lighter or a number 100 - 900
+ this.fontWeight = 'normal';
+ // prop: fontStretch
+ // Multiplier to condense or expand font width.
+ // Applies only to browsers which don't support canvas native font rendering.
+ this.fontStretch = 1.0;
+ // prop: textColor
+ // css spec for the color attribute.
+ this.textColor = '#666666';
+ // prop: enableFontSupport
+ // true to turn on native canvas font support in Mozilla 3.5+ and Safari 4+.
+ // If true, label will be drawn with canvas tag native support for fonts.
+ // If false, label will be drawn with Hershey font metrics.
+ this.enableFontSupport = true;
+ // prop: pt2px
+ // Point to pixel scaling factor, used for computing height of bounding box
+ // around a label. The labels text renderer has a default setting of 1.4, which
+ // should be suitable for most fonts. Leave as null to use default. If tops of
+ // letters appear clipped, increase this. If bounding box seems too big, decrease.
+ // This is an issue only with the native font renderering capabilities of Mozilla
+ // 3.5 and Safari 4 since they do not provide a method to determine the font height.
+ this.pt2px = null;
+
+ this._elem;
+ this._ctx;
+ this._plotWidth;
+ this._plotHeight;
+ this._plotDimensions = {height:null, width:null};
+
+ $.extend(true, this, options);
+
+ if (options.angle == null && this.axis != 'xaxis' && this.axis != 'x2axis') {
+ this.angle = -90;
+ }
+
+ var ropts = {fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily};
+ if (this.pt2px) {
+ ropts.pt2px = this.pt2px;
+ }
+
+ if (this.enableFontSupport) {
+ if ($.jqplot.support_canvas_text()) {
+ this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts);
+ }
+
+ else {
+ this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
+ }
+ }
+ else {
+ this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
+ }
+ };
+
+ $.jqplot.CanvasAxisLabelRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ this._textRenderer.init({fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily});
+ };
+
+ // return width along the x axis
+ // will check first to see if an element exists.
+ // if not, will return the computed text box width.
+ $.jqplot.CanvasAxisLabelRenderer.prototype.getWidth = function(ctx) {
+ if (this._elem) {
+ return this._elem.outerWidth(true);
+ }
+ else {
+ var tr = this._textRenderer;
+ var l = tr.getWidth(ctx);
+ var h = tr.getHeight(ctx);
+ var w = Math.abs(Math.sin(tr.angle)*h) + Math.abs(Math.cos(tr.angle)*l);
+ return w;
+ }
+ };
+
+ // return height along the y axis.
+ $.jqplot.CanvasAxisLabelRenderer.prototype.getHeight = function(ctx) {
+ if (this._elem) {
+ return this._elem.outerHeight(true);
+ }
+ else {
+ var tr = this._textRenderer;
+ var l = tr.getWidth(ctx);
+ var h = tr.getHeight(ctx);
+ var w = Math.abs(Math.cos(tr.angle)*h) + Math.abs(Math.sin(tr.angle)*l);
+ return w;
+ }
+ };
+
+ $.jqplot.CanvasAxisLabelRenderer.prototype.getAngleRad = function() {
+ var a = this.angle * Math.PI/180;
+ return a;
+ };
+
+ $.jqplot.CanvasAxisLabelRenderer.prototype.draw = function(ctx, plot) {
+ // Memory Leaks patch
+ if (this._elem) {
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ window.G_vmlCanvasManager.uninitElement(this._elem.get(0));
+ }
+
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ // create a canvas here, but can't draw on it untill it is appended
+ // to dom for IE compatability.
+ var elem = plot.canvasManager.getCanvas();
+
+ this._textRenderer.setText(this.label, ctx);
+ var w = this.getWidth(ctx);
+ var h = this.getHeight(ctx);
+ elem.width = w;
+ elem.height = h;
+ elem.style.width = w;
+ elem.style.height = h;
+
+ elem = plot.canvasManager.initCanvas(elem);
+
+ this._elem = $(elem);
+ this._elem.css({ position: 'absolute'});
+ this._elem.addClass('jqplot-'+this.axis+'-label');
+
+ elem = null;
+ return this._elem;
+ };
+
+ $.jqplot.CanvasAxisLabelRenderer.prototype.pack = function() {
+ this._textRenderer.draw(this._elem.get(0).getContext("2d"), this.label);
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisTickRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisTickRenderer.js
new file mode 100644
index 00000000..1550c7d0
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasAxisTickRenderer.js
@@ -0,0 +1,243 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.CanvasAxisTickRenderer
+ * Renderer to draw axis ticks with a canvas element to support advanced
+ * featrues such as rotated text. This renderer uses a separate rendering engine
+ * to draw the text on the canvas. Two modes of rendering the text are available.
+ * If the browser has native font support for canvas fonts (currently Mozila 3.5
+ * and Safari 4), you can enable text rendering with the canvas fillText method.
+ * You do so by setting the "enableFontSupport" option to true.
+ *
+ * Browsers lacking native font support will have the text drawn on the canvas
+ * using the Hershey font metrics. Even if the "enableFontSupport" option is true
+ * non-supporting browsers will still render with the Hershey font.
+ */
+ $.jqplot.CanvasAxisTickRenderer = function(options) {
+ // Group: Properties
+
+ // prop: mark
+ // tick mark on the axis. One of 'inside', 'outside', 'cross', '' or null.
+ this.mark = 'outside';
+ // prop: showMark
+ // wether or not to show the mark on the axis.
+ this.showMark = true;
+ // prop: showGridline
+ // wether or not to draw the gridline on the grid at this tick.
+ this.showGridline = true;
+ // prop: isMinorTick
+ // if this is a minor tick.
+ this.isMinorTick = false;
+ // prop: angle
+ // angle of text, measured clockwise from x axis.
+ this.angle = 0;
+ // prop: markSize
+ // Length of the tick marks in pixels. For 'cross' style, length
+ // will be stoked above and below axis, so total length will be twice this.
+ this.markSize = 4;
+ // prop: show
+ // wether or not to show the tick (mark and label).
+ this.show = true;
+ // prop: showLabel
+ // wether or not to show the label.
+ this.showLabel = true;
+ // prop: labelPosition
+ // 'auto', 'start', 'middle' or 'end'.
+ // Whether tick label should be positioned so the start, middle, or end
+ // of the tick mark.
+ this.labelPosition = 'auto';
+ this.label = '';
+ this.value = null;
+ this._styles = {};
+ // prop: formatter
+ // A class of a formatter for the tick text.
+ // The default $.jqplot.DefaultTickFormatter uses sprintf.
+ this.formatter = $.jqplot.DefaultTickFormatter;
+ // prop: formatString
+ // string passed to the formatter.
+ this.formatString = '';
+ // prop: prefix
+ // String to prepend to the tick label.
+ // Prefix is prepended to the formatted tick label.
+ this.prefix = '';
+ // prop: fontFamily
+ // css spec for the font-family css attribute.
+ this.fontFamily = '"Trebuchet MS", Arial, Helvetica, sans-serif';
+ // prop: fontSize
+ // CSS spec for font size.
+ this.fontSize = '10pt';
+ // prop: fontWeight
+ // CSS spec for fontWeight
+ this.fontWeight = 'normal';
+ // prop: fontStretch
+ // Multiplier to condense or expand font width.
+ // Applies only to browsers which don't support canvas native font rendering.
+ this.fontStretch = 1.0;
+ // prop: textColor
+ // css spec for the color attribute.
+ this.textColor = '#666666';
+ // prop: enableFontSupport
+ // true to turn on native canvas font support in Mozilla 3.5+ and Safari 4+.
+ // If true, tick label will be drawn with canvas tag native support for fonts.
+ // If false, tick label will be drawn with Hershey font metrics.
+ this.enableFontSupport = true;
+ // prop: pt2px
+ // Point to pixel scaling factor, used for computing height of bounding box
+ // around a label. The labels text renderer has a default setting of 1.4, which
+ // should be suitable for most fonts. Leave as null to use default. If tops of
+ // letters appear clipped, increase this. If bounding box seems too big, decrease.
+ // This is an issue only with the native font renderering capabilities of Mozilla
+ // 3.5 and Safari 4 since they do not provide a method to determine the font height.
+ this.pt2px = null;
+
+ this._elem;
+ this._ctx;
+ this._plotWidth;
+ this._plotHeight;
+ this._plotDimensions = {height:null, width:null};
+
+ $.extend(true, this, options);
+
+ var ropts = {fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily};
+ if (this.pt2px) {
+ ropts.pt2px = this.pt2px;
+ }
+
+ if (this.enableFontSupport) {
+ if ($.jqplot.support_canvas_text()) {
+ this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts);
+ }
+
+ else {
+ this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
+ }
+ }
+ else {
+ this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
+ }
+ };
+
+ $.jqplot.CanvasAxisTickRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ this._textRenderer.init({fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily});
+ };
+
+ // return width along the x axis
+ // will check first to see if an element exists.
+ // if not, will return the computed text box width.
+ $.jqplot.CanvasAxisTickRenderer.prototype.getWidth = function(ctx) {
+ if (this._elem) {
+ return this._elem.outerWidth(true);
+ }
+ else {
+ var tr = this._textRenderer;
+ var l = tr.getWidth(ctx);
+ var h = tr.getHeight(ctx);
+ var w = Math.abs(Math.sin(tr.angle)*h) + Math.abs(Math.cos(tr.angle)*l);
+ return w;
+ }
+ };
+
+ // return height along the y axis.
+ $.jqplot.CanvasAxisTickRenderer.prototype.getHeight = function(ctx) {
+ if (this._elem) {
+ return this._elem.outerHeight(true);
+ }
+ else {
+ var tr = this._textRenderer;
+ var l = tr.getWidth(ctx);
+ var h = tr.getHeight(ctx);
+ var w = Math.abs(Math.cos(tr.angle)*h) + Math.abs(Math.sin(tr.angle)*l);
+ return w;
+ }
+ };
+
+ $.jqplot.CanvasAxisTickRenderer.prototype.getAngleRad = function() {
+ var a = this.angle * Math.PI/180;
+ return a;
+ };
+
+
+ $.jqplot.CanvasAxisTickRenderer.prototype.setTick = function(value, axisName, isMinor) {
+ this.value = value;
+ if (isMinor) {
+ this.isMinorTick = true;
+ }
+ return this;
+ };
+
+ $.jqplot.CanvasAxisTickRenderer.prototype.draw = function(ctx, plot) {
+ if (!this.label) {
+ this.label = this.prefix + this.formatter(this.formatString, this.value);
+ }
+
+ // Memory Leaks patch
+ if (this._elem) {
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ window.G_vmlCanvasManager.uninitElement(this._elem.get(0));
+ }
+
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ // create a canvas here, but can't draw on it untill it is appended
+ // to dom for IE compatability.
+
+ var elem = plot.canvasManager.getCanvas();
+
+ this._textRenderer.setText(this.label, ctx);
+ var w = this.getWidth(ctx);
+ var h = this.getHeight(ctx);
+ // canvases seem to need to have width and heigh attributes directly set.
+ elem.width = w;
+ elem.height = h;
+ elem.style.width = w;
+ elem.style.height = h;
+ elem.style.textAlign = 'left';
+ elem.style.position = 'absolute';
+
+ elem = plot.canvasManager.initCanvas(elem);
+
+ this._elem = $(elem);
+ this._elem.css(this._styles);
+ this._elem.addClass('jqplot-'+this.axis+'-tick');
+
+ elem = null;
+ return this._elem;
+ };
+
+ $.jqplot.CanvasAxisTickRenderer.prototype.pack = function() {
+ this._textRenderer.draw(this._elem.get(0).getContext("2d"), this.label);
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasOverlay.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasOverlay.js
new file mode 100644
index 00000000..03766206
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasOverlay.js
@@ -0,0 +1,865 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ var objCounter = 0;
+ // class: $.jqplot.CanvasOverlay
+ $.jqplot.CanvasOverlay = function(opts){
+ var options = opts || {};
+ this.options = {
+ show: $.jqplot.config.enablePlugins,
+ deferDraw: false
+ };
+ // prop: objects
+ this.objects = [];
+ this.objectNames = [];
+ this.canvas = null;
+ this.markerRenderer = new $.jqplot.MarkerRenderer({style:'line'});
+ this.markerRenderer.init();
+ this.highlightObjectIndex = null;
+ if (options.objects) {
+ var objs = options.objects,
+ obj;
+ for (var i=0; i<objs.length; i++) {
+ obj = objs[i];
+ for (var n in obj) {
+ switch (n) {
+ case 'line':
+ this.addLine(obj[n]);
+ break;
+ case 'horizontalLine':
+ this.addHorizontalLine(obj[n]);
+ break;
+ case 'dashedHorizontalLine':
+ this.addDashedHorizontalLine(obj[n]);
+ break;
+ case 'verticalLine':
+ this.addVerticalLine(obj[n]);
+ break;
+ case 'dashedVerticalLine':
+ this.addDashedVerticalLine(obj[n]);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ $.extend(true, this.options, options);
+ };
+
+ // called with scope of a plot object
+ $.jqplot.CanvasOverlay.postPlotInit = function (target, data, opts) {
+ var options = opts || {};
+ // add a canvasOverlay attribute to the plot
+ this.plugins.canvasOverlay = new $.jqplot.CanvasOverlay(options.canvasOverlay);
+ };
+
+
+ function LineBase() {
+ this.uid = null;
+ this.type = null;
+ this.gridStart = null;
+ this.gridStop = null;
+ this.tooltipWidthFactor = 0;
+ this.options = {
+ // prop: name
+ // Optional name for the overlay object.
+ // Can be later used to retrieve the object by name.
+ name: null,
+ // prop: show
+ // true to show (draw), false to not draw.
+ show: true,
+ // prop: lineWidth
+ // Width of the line.
+ lineWidth: 2,
+ // prop: lineCap
+ // Type of ending placed on the line ['round', 'butt', 'square']
+ lineCap: 'round',
+ // prop: color
+ // color of the line
+ color: '#666666',
+ // prop: shadow
+ // wether or not to draw a shadow on the line
+ shadow: true,
+ // prop: shadowAngle
+ // Shadow angle in degrees
+ shadowAngle: 45,
+ // prop: shadowOffset
+ // Shadow offset from line in pixels
+ shadowOffset: 1,
+ // prop: shadowDepth
+ // Number of times shadow is stroked, each stroke offset shadowOffset from the last.
+ shadowDepth: 3,
+ // prop: shadowAlpha
+ // Alpha channel transparency of shadow. 0 = transparent.
+ shadowAlpha: '0.07',
+ // prop: xaxis
+ // X axis to use for positioning/scaling the line.
+ xaxis: 'xaxis',
+ // prop: yaxis
+ // Y axis to use for positioning/scaling the line.
+ yaxis: 'yaxis',
+ // prop: showTooltip
+ // Show a tooltip with data point values.
+ showTooltip: false,
+ // prop: showTooltipPrecision
+ // Controls how close to line cursor must be to show tooltip.
+ // Higher number = closer to line, lower number = farther from line.
+ // 1.0 = cursor must be over line.
+ showTooltipPrecision: 0.6,
+ // prop: tooltipLocation
+ // Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
+ tooltipLocation: 'nw',
+ // prop: fadeTooltip
+ // true = fade in/out tooltip, flase = show/hide tooltip
+ fadeTooltip: true,
+ // prop: tooltipFadeSpeed
+ // 'slow', 'def', 'fast', or number of milliseconds.
+ tooltipFadeSpeed: "fast",
+ // prop: tooltipOffset
+ // Pixel offset of tooltip from the highlight.
+ tooltipOffset: 4,
+ // prop: tooltipFormatString
+ // Format string passed the x and y values of the cursor on the line.
+ // e.g., 'Dogs: %.2f, Cats: %d'.
+ tooltipFormatString: '%d, %d'
+ };
+ }
+
+ /**
+ * Class: Line
+ * A straight line.
+ */
+ function Line(options) {
+ LineBase.call(this);
+ this.type = 'line';
+ var opts = {
+ // prop: start
+ // [x, y] coordinates for the start of the line.
+ start: [],
+ // prop: stop
+ // [x, y] coordinates for the end of the line.
+ stop: []
+ };
+ $.extend(true, this.options, opts, options);
+
+ if (this.options.showTooltipPrecision < 0.01) {
+ this.options.showTooltipPrecision = 0.01;
+ }
+ }
+
+ Line.prototype = new LineBase();
+ Line.prototype.constructor = Line;
+
+
+ /**
+ * Class: HorizontalLine
+ * A straight horizontal line.
+ */
+ function HorizontalLine(options) {
+ LineBase.call(this);
+ this.type = 'horizontalLine';
+ var opts = {
+ // prop: y
+ // y value to position the line
+ y: null,
+ // prop: xmin
+ // x value for the start of the line, null to scale to axis min.
+ xmin: null,
+ // prop: xmax
+ // x value for the end of the line, null to scale to axis max.
+ xmax: null,
+ // prop xOffset
+ // offset ends of the line inside the grid. Number
+ xOffset: '6px', // number or string. Number interpreted as units, string as pixels.
+ xminOffset: null,
+ xmaxOffset: null
+ };
+ $.extend(true, this.options, opts, options);
+
+ if (this.options.showTooltipPrecision < 0.01) {
+ this.options.showTooltipPrecision = 0.01;
+ }
+ }
+
+ HorizontalLine.prototype = new LineBase();
+ HorizontalLine.prototype.constructor = HorizontalLine;
+
+
+ /**
+ * Class: DashedHorizontalLine
+ * A straight dashed horizontal line.
+ */
+ function DashedHorizontalLine(options) {
+ LineBase.call(this);
+ this.type = 'dashedHorizontalLine';
+ var opts = {
+ y: null,
+ xmin: null,
+ xmax: null,
+ xOffset: '6px', // number or string. Number interpreted as units, string as pixels.
+ xminOffset: null,
+ xmaxOffset: null,
+ // prop: dashPattern
+ // Array of line, space settings in pixels.
+ // Default is 8 pixel of line, 8 pixel of space.
+ // Note, limit to a 2 element array b/c of bug with higher order arrays.
+ dashPattern: [8,8]
+ };
+ $.extend(true, this.options, opts, options);
+
+ if (this.options.showTooltipPrecision < 0.01) {
+ this.options.showTooltipPrecision = 0.01;
+ }
+ }
+
+ DashedHorizontalLine.prototype = new LineBase();
+ DashedHorizontalLine.prototype.constructor = DashedHorizontalLine;
+
+
+ /**
+ * Class: VerticalLine
+ * A straight vertical line.
+ */
+ function VerticalLine(options) {
+ LineBase.call(this);
+ this.type = 'verticalLine';
+ var opts = {
+ x: null,
+ ymin: null,
+ ymax: null,
+ yOffset: '6px', // number or string. Number interpreted as units, string as pixels.
+ yminOffset: null,
+ ymaxOffset: null
+ };
+ $.extend(true, this.options, opts, options);
+
+ if (this.options.showTooltipPrecision < 0.01) {
+ this.options.showTooltipPrecision = 0.01;
+ }
+ }
+
+ VerticalLine.prototype = new LineBase();
+ VerticalLine.prototype.constructor = VerticalLine;
+
+
+ /**
+ * Class: DashedVerticalLine
+ * A straight dashed vertical line.
+ */
+ function DashedVerticalLine(options) {
+ LineBase.call(this);
+ this.type = 'dashedVerticalLine';
+ this.start = null;
+ this.stop = null;
+ var opts = {
+ x: null,
+ ymin: null,
+ ymax: null,
+ yOffset: '6px', // number or string. Number interpreted as units, string as pixels.
+ yminOffset: null,
+ ymaxOffset: null,
+ // prop: dashPattern
+ // Array of line, space settings in pixels.
+ // Default is 8 pixel of line, 8 pixel of space.
+ // Note, limit to a 2 element array b/c of bug with higher order arrays.
+ dashPattern: [8,8]
+ };
+ $.extend(true, this.options, opts, options);
+
+ if (this.options.showTooltipPrecision < 0.01) {
+ this.options.showTooltipPrecision = 0.01;
+ }
+ }
+
+ DashedVerticalLine.prototype = new LineBase();
+ DashedVerticalLine.prototype.constructor = DashedVerticalLine;
+
+ $.jqplot.CanvasOverlay.prototype.addLine = function(opts) {
+ var line = new Line(opts);
+ line.uid = objCounter++;
+ this.objects.push(line);
+ this.objectNames.push(line.options.name);
+ };
+
+ $.jqplot.CanvasOverlay.prototype.addHorizontalLine = function(opts) {
+ var line = new HorizontalLine(opts);
+ line.uid = objCounter++;
+ this.objects.push(line);
+ this.objectNames.push(line.options.name);
+ };
+
+ $.jqplot.CanvasOverlay.prototype.addDashedHorizontalLine = function(opts) {
+ var line = new DashedHorizontalLine(opts);
+ line.uid = objCounter++;
+ this.objects.push(line);
+ this.objectNames.push(line.options.name);
+ };
+
+ $.jqplot.CanvasOverlay.prototype.addVerticalLine = function(opts) {
+ var line = new VerticalLine(opts);
+ line.uid = objCounter++;
+ this.objects.push(line);
+ this.objectNames.push(line.options.name);
+ };
+
+ $.jqplot.CanvasOverlay.prototype.addDashedVerticalLine = function(opts) {
+ var line = new DashedVerticalLine(opts);
+ line.uid = objCounter++;
+ this.objects.push(line);
+ this.objectNames.push(line.options.name);
+ };
+
+ $.jqplot.CanvasOverlay.prototype.removeObject = function(idx) {
+ // check if integer, remove by index
+ if ($.type(idx) == 'number') {
+ this.objects.splice(idx, 1);
+ this.objectNames.splice(idx, 1);
+ }
+ // if string, remove by name
+ else {
+ var id = $.inArray(idx, this.objectNames);
+ if (id != -1) {
+ this.objects.splice(id, 1);
+ this.objectNames.splice(id, 1);
+ }
+ }
+ };
+
+ $.jqplot.CanvasOverlay.prototype.getObject = function(idx) {
+ // check if integer, remove by index
+ if ($.type(idx) == 'number') {
+ return this.objects[idx];
+ }
+ // if string, remove by name
+ else {
+ var id = $.inArray(idx, this.objectNames);
+ if (id != -1) {
+ return this.objects[id];
+ }
+ }
+ };
+
+ // Set get as alias for getObject.
+ $.jqplot.CanvasOverlay.prototype.get = $.jqplot.CanvasOverlay.prototype.getObject;
+
+ $.jqplot.CanvasOverlay.prototype.clear = function(plot) {
+ this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(), this.canvas.getHeight());
+ };
+
+ $.jqplot.CanvasOverlay.prototype.draw = function(plot) {
+ var obj,
+ objs = this.objects,
+ mr = this.markerRenderer,
+ start,
+ stop;
+ if (this.options.show) {
+ this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(), this.canvas.getHeight());
+ for (var k=0; k<objs.length; k++) {
+ obj = objs[k];
+ var opts = $.extend(true, {}, obj.options);
+ if (obj.options.show) {
+ // style and shadow properties should be set before
+ // every draw of marker renderer.
+ mr.shadow = obj.options.shadow;
+ obj.tooltipWidthFactor = obj.options.lineWidth / obj.options.showTooltipPrecision;
+ switch (obj.type) {
+ case 'line':
+ // style and shadow properties should be set before
+ // every draw of marker renderer.
+ mr.style = 'line';
+ opts.closePath = false;
+ start = [plot.axes[obj.options.xaxis].series_u2p(obj.options.start[0]), plot.axes[obj.options.yaxis].series_u2p(obj.options.start[1])];
+ stop = [plot.axes[obj.options.xaxis].series_u2p(obj.options.stop[0]), plot.axes[obj.options.yaxis].series_u2p(obj.options.stop[1])];
+ obj.gridStart = start;
+ obj.gridStop = stop;
+ mr.draw(start, stop, this.canvas._ctx, opts);
+ break;
+ case 'horizontalLine':
+
+ // style and shadow properties should be set before
+ // every draw of marker renderer.
+ if (obj.options.y != null) {
+ mr.style = 'line';
+ opts.closePath = false;
+ var xaxis = plot.axes[obj.options.xaxis],
+ xstart,
+ xstop,
+ y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y),
+ xminoff = obj.options.xminOffset || obj.options.xOffset,
+ xmaxoff = obj.options.xmaxOffset || obj.options.xOffset;
+ if (obj.options.xmin != null) {
+ xstart = xaxis.series_u2p(obj.options.xmin);
+ }
+ else if (xminoff != null) {
+ if ($.type(xminoff) == "number") {
+ xstart = xaxis.series_u2p(xaxis.min + xminoff);
+ }
+ else if ($.type(xminoff) == "string") {
+ xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff);
+ }
+ }
+ if (obj.options.xmax != null) {
+ xstop = xaxis.series_u2p(obj.options.xmax);
+ }
+ else if (xmaxoff != null) {
+ if ($.type(xmaxoff) == "number") {
+ xstop = xaxis.series_u2p(xaxis.max - xmaxoff);
+ }
+ else if ($.type(xmaxoff) == "string") {
+ xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff);
+ }
+ }
+ if (xstop != null && xstart != null) {
+ obj.gridStart = [xstart, y];
+ obj.gridStop = [xstop, y];
+ mr.draw([xstart, y], [xstop, y], this.canvas._ctx, opts);
+ }
+ }
+ break;
+
+ case 'dashedHorizontalLine':
+
+ var dashPat = obj.options.dashPattern;
+ var dashPatLen = 0;
+ for (var i=0; i<dashPat.length; i++) {
+ dashPatLen += dashPat[i];
+ }
+
+ // style and shadow properties should be set before
+ // every draw of marker renderer.
+ if (obj.options.y != null) {
+ mr.style = 'line';
+ opts.closePath = false;
+ var xaxis = plot.axes[obj.options.xaxis],
+ xstart,
+ xstop,
+ y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y),
+ xminoff = obj.options.xminOffset || obj.options.xOffset,
+ xmaxoff = obj.options.xmaxOffset || obj.options.xOffset;
+ if (obj.options.xmin != null) {
+ xstart = xaxis.series_u2p(obj.options.xmin);
+ }
+ else if (xminoff != null) {
+ if ($.type(xminoff) == "number") {
+ xstart = xaxis.series_u2p(xaxis.min + xminoff);
+ }
+ else if ($.type(xminoff) == "string") {
+ xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff);
+ }
+ }
+ if (obj.options.xmax != null) {
+ xstop = xaxis.series_u2p(obj.options.xmax);
+ }
+ else if (xmaxoff != null) {
+ if ($.type(xmaxoff) == "number") {
+ xstop = xaxis.series_u2p(xaxis.max - xmaxoff);
+ }
+ else if ($.type(xmaxoff) == "string") {
+ xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff);
+ }
+ }
+ if (xstop != null && xstart != null) {
+ obj.gridStart = [xstart, y];
+ obj.gridStop = [xstop, y];
+ var numDash = Math.ceil((xstop - xstart)/dashPatLen);
+ var b=xstart, e;
+ for (var i=0; i<numDash; i++) {
+ for (var j=0; j<dashPat.length; j+=2) {
+ e = b+dashPat[j];
+ mr.draw([b, y], [e, y], this.canvas._ctx, opts);
+ b += dashPat[j];
+ if (j < dashPat.length-1) {
+ b += dashPat[j+1];
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case 'verticalLine':
+
+ // style and shadow properties should be set before
+ // every draw of marker renderer.
+ if (obj.options.x != null) {
+ mr.style = 'line';
+ opts.closePath = false;
+ var yaxis = plot.axes[obj.options.yaxis],
+ ystart,
+ ystop,
+ x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x),
+ yminoff = obj.options.yminOffset || obj.options.yOffset,
+ ymaxoff = obj.options.ymaxOffset || obj.options.yOffset;
+ if (obj.options.ymin != null) {
+ ystart = yaxis.series_u2p(obj.options.ymin);
+ }
+ else if (yminoff != null) {
+ if ($.type(yminoff) == "number") {
+ ystart = yaxis.series_u2p(yaxis.min - yminoff);
+ }
+ else if ($.type(yminoff) == "string") {
+ ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff);
+ }
+ }
+ if (obj.options.ymax != null) {
+ ystop = yaxis.series_u2p(obj.options.ymax);
+ }
+ else if (ymaxoff != null) {
+ if ($.type(ymaxoff) == "number") {
+ ystop = yaxis.series_u2p(yaxis.max + ymaxoff);
+ }
+ else if ($.type(ymaxoff) == "string") {
+ ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff);
+ }
+ }
+ if (ystop != null && ystart != null) {
+ obj.gridStart = [x, ystart];
+ obj.gridStop = [x, ystop];
+ mr.draw([x, ystart], [x, ystop], this.canvas._ctx, opts);
+ }
+ }
+ break;
+
+ case 'dashedVerticalLine':
+
+ var dashPat = obj.options.dashPattern;
+ var dashPatLen = 0;
+ for (var i=0; i<dashPat.length; i++) {
+ dashPatLen += dashPat[i];
+ }
+
+ // style and shadow properties should be set before
+ // every draw of marker renderer.
+ if (obj.options.x != null) {
+ mr.style = 'line';
+ opts.closePath = false;
+ var yaxis = plot.axes[obj.options.yaxis],
+ ystart,
+ ystop,
+ x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x),
+ yminoff = obj.options.yminOffset || obj.options.yOffset,
+ ymaxoff = obj.options.ymaxOffset || obj.options.yOffset;
+ if (obj.options.ymin != null) {
+ ystart = yaxis.series_u2p(obj.options.ymin);
+ }
+ else if (yminoff != null) {
+ if ($.type(yminoff) == "number") {
+ ystart = yaxis.series_u2p(yaxis.min - yminoff);
+ }
+ else if ($.type(yminoff) == "string") {
+ ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff);
+ }
+ }
+ if (obj.options.ymax != null) {
+ ystop = yaxis.series_u2p(obj.options.ymax);
+ }
+ else if (ymaxoff != null) {
+ if ($.type(ymaxoff) == "number") {
+ ystop = yaxis.series_u2p(yaxis.max + ymaxoff);
+ }
+ else if ($.type(ymaxoff) == "string") {
+ ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff);
+ }
+ }
+
+
+ if (ystop != null && ystart != null) {
+ obj.gridStart = [x, ystart];
+ obj.gridStop = [x, ystop];
+ var numDash = Math.ceil((ystart - ystop)/dashPatLen);
+ var firstDashAdjust = ((numDash * dashPatLen) - (ystart - ystop))/2.0;
+ var b=ystart, e, bs, es;
+ for (var i=0; i<numDash; i++) {
+ for (var j=0; j<dashPat.length; j+=2) {
+ e = b - dashPat[j];
+ if (e < ystop) {
+ e = ystop;
+ }
+ if (b < ystop) {
+ b = ystop;
+ }
+ // es = e;
+ // if (i == 0) {
+ // es += firstDashAdjust;
+ // }
+ mr.draw([x, b], [x, e], this.canvas._ctx, opts);
+ b -= dashPat[j];
+ if (j < dashPat.length-1) {
+ b -= dashPat[j+1];
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ };
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ $.jqplot.CanvasOverlay.postPlotDraw = function() {
+ var co = this.plugins.canvasOverlay;
+ // Memory Leaks patch
+ if (co && co.highlightCanvas) {
+ co.highlightCanvas.resetCanvas();
+ co.highlightCanvas = null;
+ }
+ co.canvas = new $.jqplot.GenericCanvas();
+
+ this.eventCanvas._elem.before(co.canvas.createElement(this._gridPadding, 'jqplot-overlayCanvas-canvas', this._plotDimensions, this));
+ co.canvas.setContext();
+ if (!co.deferDraw) {
+ co.draw(this);
+ }
+
+ var elem = document.createElement('div');
+ co._tooltipElem = $(elem);
+ elem = null;
+ co._tooltipElem.addClass('jqplot-canvasOverlay-tooltip');
+ co._tooltipElem.css({position:'absolute', display:'none'});
+
+ this.eventCanvas._elem.before(co._tooltipElem);
+ this.eventCanvas._elem.bind('mouseleave', { elem: co._tooltipElem }, function (ev) { ev.data.elem.hide(); });
+
+ var co = null;
+ };
+
+
+ function showTooltip(plot, obj, gridpos, datapos) {
+ var co = plot.plugins.canvasOverlay;
+ var elem = co._tooltipElem;
+
+ var opts = obj.options, x, y;
+
+ elem.html($.jqplot.sprintf(opts.tooltipFormatString, datapos[0], datapos[1]));
+
+ switch (opts.tooltipLocation) {
+ case 'nw':
+ x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'n':
+ x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true)/2;
+ y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'ne':
+ x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'e':
+ x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ case 'se':
+ x = gridpos[0] + plot._gridPadding.left + opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset;
+ break;
+ case 's':
+ x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true)/2;
+ y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset;
+ break;
+ case 'sw':
+ x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top + opts.tooltipOffset;
+ break;
+ case 'w':
+ x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ default: // same as 'nw'
+ x = gridpos[0] + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset;
+ y = gridpos[1] + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true);
+ break;
+ }
+
+ elem.css('left', x);
+ elem.css('top', y);
+ if (opts.fadeTooltip) {
+ // Fix for stacked up animations. Thnanks Trevor!
+ elem.stop(true,true).fadeIn(opts.tooltipFadeSpeed);
+ }
+ else {
+ elem.show();
+ }
+ elem = null;
+ }
+
+
+ function isNearLine(point, lstart, lstop, width) {
+ // r is point to test, p and q are end points.
+ var rx = point[0];
+ var ry = point[1];
+ var px = Math.round(lstop[0]);
+ var py = Math.round(lstop[1]);
+ var qx = Math.round(lstart[0]);
+ var qy = Math.round(lstart[1]);
+
+ var l = Math.sqrt(Math.pow(px-qx, 2) + Math.pow(py-qy, 2));
+
+ // scale error term by length of line.
+ var eps = width*l;
+ var res = Math.abs((qx-px) * (ry-py) - (qy-py) * (rx-px));
+ var ret = (res < eps) ? true : false;
+ return ret;
+ }
+
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ var co = plot.plugins.canvasOverlay;
+ var objs = co.objects;
+ var l = objs.length;
+ var obj, haveHighlight=false;
+ var elem;
+ for (var i=0; i<l; i++) {
+ obj = objs[i];
+ if (obj.options.showTooltip) {
+ var n = isNearLine([gridpos.x, gridpos.y], obj.gridStart, obj.gridStop, obj.tooltipWidthFactor);
+ datapos = [plot.axes[obj.options.xaxis].series_p2u(gridpos.x), plot.axes[obj.options.yaxis].series_p2u(gridpos.y)];
+
+ // cases:
+ // near line, no highlighting
+ // near line, highliting on this line
+ // near line, highlighting another line
+ // not near any line, highlighting
+ // not near any line, no highlighting
+
+ // near line, not currently highlighting
+ if (n && co.highlightObjectIndex == null) {
+ switch (obj.type) {
+ case 'line':
+ showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos);
+ break;
+
+ case 'horizontalLine':
+ case 'dashedHorizontalLine':
+ showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]);
+ break;
+
+ case 'verticalLine':
+ case 'dashedVerticalLine':
+ showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);
+ break;
+ default:
+ break;
+ }
+ co.highlightObjectIndex = i;
+ haveHighlight = true;
+ break;
+ }
+
+ // near line, highlighting another line.
+ else if (n && co.highlightObjectIndex !== i) {
+ // turn off tooltip.
+ elem = co._tooltipElem;
+ if (obj.fadeTooltip) {
+ elem.fadeOut(obj.tooltipFadeSpeed);
+ }
+ else {
+ elem.hide();
+ }
+
+ // turn on right tooltip.
+ switch (obj.type) {
+ case 'line':
+ showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos);
+ break;
+
+ case 'horizontalLine':
+ case 'dashedHorizontalLine':
+ showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]);
+ break;
+
+ case 'verticalLine':
+ case 'dashedVerticalLine':
+ showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);
+ break;
+ default:
+ break;
+ }
+
+ co.highlightObjectIndex = i;
+ haveHighlight = true;
+ break;
+ }
+
+ // near line, already highlighting this line, update
+ else if (n) {
+ switch (obj.type) {
+ case 'line':
+ showTooltip(plot, obj, [gridpos.x, gridpos.y], datapos);
+ break;
+
+ case 'horizontalLine':
+ case 'dashedHorizontalLine':
+ showTooltip(plot, obj, [gridpos.x, obj.gridStart[1]], [datapos[0], obj.options.y]);
+ break;
+
+ case 'verticalLine':
+ case 'dashedVerticalLine':
+ showTooltip(plot, obj, [obj.gridStart[0], gridpos.y], [obj.options.x, datapos[1]]);
+ break;
+ default:
+ break;
+ }
+
+ haveHighlight = true;
+ break;
+ }
+ }
+ }
+
+ // check if we are highlighting and not near a line, turn it off.
+ if (!haveHighlight && co.highlightObjectIndex !== null) {
+ elem = co._tooltipElem;
+ obj = co.getObject(co.highlightObjectIndex);
+ if (obj.fadeTooltip) {
+ elem.fadeOut(obj.tooltipFadeSpeed);
+ }
+ else {
+ elem.hide();
+ }
+ co.highlightObjectIndex = null;
+ }
+ }
+
+ $.jqplot.postInitHooks.push($.jqplot.CanvasOverlay.postPlotInit);
+ $.jqplot.postDrawHooks.push($.jqplot.CanvasOverlay.postPlotDraw);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);
+
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasTextRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasTextRenderer.js
new file mode 100644
index 00000000..53f25305
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.canvasTextRenderer.js
@@ -0,0 +1,449 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ * included jsDate library by Chris Leonello:
+ *
+ * Copyright (c) 2010-2012 Chris Leonello
+ *
+ * jsDate is currently available for use in all personal or commercial projects
+ * under both the MIT and GPL version 2.0 licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * jsDate borrows many concepts and ideas from the Date Instance
+ * Methods by Ken Snyder along with some parts of Ken's actual code.
+ *
+ * Ken's origianl Date Instance Methods and copyright notice:
+ *
+ * Ken Snyder (ken d snyder at gmail dot com)
+ * 2008-09-10
+ * version 2.0.2 (http://kendsnyder.com/sandbox/date/)
+ * Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
+ *
+ * jqplotToImage function based on Larry Siden's export-jqplot-to-png.js.
+ * Larry has generously given permission to adapt his code for inclusion
+ * into jqPlot.
+ *
+ * Larry's original code can be found here:
+ *
+ * https://github.com/lsiden/export-jqplot-to-png
+ *
+ *
+ */
+
+(function($) {
+ // This code is a modified version of the canvastext.js code, copyright below:
+ //
+ // This code is released to the public domain by Jim Studt, 2007.
+ // He may keep some sort of up to date copy at http://www.federated.com/~jim/canvastext/
+ //
+ $.jqplot.CanvasTextRenderer = function(options){
+ this.fontStyle = 'normal'; // normal, italic, oblique [not implemented]
+ this.fontVariant = 'normal'; // normal, small caps [not implemented]
+ this.fontWeight = 'normal'; // normal, bold, bolder, lighter, 100 - 900
+ this.fontSize = '10px';
+ this.fontFamily = 'sans-serif';
+ this.fontStretch = 1.0;
+ this.fillStyle = '#666666';
+ this.angle = 0;
+ this.textAlign = 'start';
+ this.textBaseline = 'alphabetic';
+ this.text;
+ this.width;
+ this.height;
+ this.pt2px = 1.28;
+
+ $.extend(true, this, options);
+ this.normalizedFontSize = this.normalizeFontSize(this.fontSize);
+ this.setHeight();
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ this.normalizedFontSize = this.normalizeFontSize(this.fontSize);
+ this.setHeight();
+ };
+
+ // convert css spec into point size
+ // returns float
+ $.jqplot.CanvasTextRenderer.prototype.normalizeFontSize = function(sz) {
+ sz = String(sz);
+ var n = parseFloat(sz);
+ if (sz.indexOf('px') > -1) {
+ return n/this.pt2px;
+ }
+ else if (sz.indexOf('pt') > -1) {
+ return n;
+ }
+ else if (sz.indexOf('em') > -1) {
+ return n*12;
+ }
+ else if (sz.indexOf('%') > -1) {
+ return n*12/100;
+ }
+ // default to pixels;
+ else {
+ return n/this.pt2px;
+ }
+ };
+
+
+ $.jqplot.CanvasTextRenderer.prototype.fontWeight2Float = function(w) {
+ // w = normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
+ // return values adjusted for Hershey font.
+ if (Number(w)) {
+ return w/400;
+ }
+ else {
+ switch (w) {
+ case 'normal':
+ return 1;
+ break;
+ case 'bold':
+ return 1.75;
+ break;
+ case 'bolder':
+ return 2.25;
+ break;
+ case 'lighter':
+ return 0.75;
+ break;
+ default:
+ return 1;
+ break;
+ }
+ }
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.getText = function() {
+ return this.text;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.setText = function(t, ctx) {
+ this.text = t;
+ this.setWidth(ctx);
+ return this;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.getWidth = function(ctx) {
+ return this.width;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.setWidth = function(ctx, w) {
+ if (!w) {
+ this.width = this.measure(ctx, this.text);
+ }
+ else {
+ this.width = w;
+ }
+ return this;
+ };
+
+ // return height in pixels.
+ $.jqplot.CanvasTextRenderer.prototype.getHeight = function(ctx) {
+ return this.height;
+ };
+
+ // w - height in pt
+ // set heigh in px
+ $.jqplot.CanvasTextRenderer.prototype.setHeight = function(w) {
+ if (!w) {
+ //height = this.fontSize /0.75;
+ this.height = this.normalizedFontSize * this.pt2px;
+ }
+ else {
+ this.height = w;
+ }
+ return this;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.letter = function (ch)
+ {
+ return this.letters[ch];
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.ascent = function()
+ {
+ return this.normalizedFontSize;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.descent = function()
+ {
+ return 7.0*this.normalizedFontSize/25.0;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.measure = function(ctx, str)
+ {
+ var total = 0;
+ var len = str.length;
+
+ for (var i = 0; i < len; i++) {
+ var c = this.letter(str.charAt(i));
+ if (c) {
+ total += c.width * this.normalizedFontSize / 25.0 * this.fontStretch;
+ }
+ }
+ return total;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.draw = function(ctx,str)
+ {
+ var x = 0;
+ // leave room at bottom for descenders.
+ var y = this.height*0.72;
+ var total = 0;
+ var len = str.length;
+ var mag = this.normalizedFontSize / 25.0;
+
+ ctx.save();
+ var tx, ty;
+
+ // 1st quadrant
+ if ((-Math.PI/2 <= this.angle && this.angle <= 0) || (Math.PI*3/2 <= this.angle && this.angle <= Math.PI*2)) {
+ tx = 0;
+ ty = -Math.sin(this.angle) * this.width;
+ }
+ // 4th quadrant
+ else if ((0 < this.angle && this.angle <= Math.PI/2) || (-Math.PI*2 <= this.angle && this.angle <= -Math.PI*3/2)) {
+ tx = Math.sin(this.angle) * this.height;
+ ty = 0;
+ }
+ // 2nd quadrant
+ else if ((-Math.PI < this.angle && this.angle < -Math.PI/2) || (Math.PI <= this.angle && this.angle <= Math.PI*3/2)) {
+ tx = -Math.cos(this.angle) * this.width;
+ ty = -Math.sin(this.angle) * this.width - Math.cos(this.angle) * this.height;
+ }
+ // 3rd quadrant
+ else if ((-Math.PI*3/2 < this.angle && this.angle < Math.PI) || (Math.PI/2 < this.angle && this.angle < Math.PI)) {
+ tx = Math.sin(this.angle) * this.height - Math.cos(this.angle)*this.width;
+ ty = -Math.cos(this.angle) * this.height;
+ }
+
+ ctx.strokeStyle = this.fillStyle;
+ ctx.fillStyle = this.fillStyle;
+ ctx.translate(tx, ty);
+ ctx.rotate(this.angle);
+ ctx.lineCap = "round";
+ // multiplier was 2.0
+ var fact = (this.normalizedFontSize > 30) ? 2.0 : 2 + (30 - this.normalizedFontSize)/20;
+ ctx.lineWidth = fact * mag * this.fontWeight2Float(this.fontWeight);
+
+ for ( var i = 0; i < len; i++) {
+ var c = this.letter( str.charAt(i));
+ if ( !c) {
+ continue;
+ }
+
+ ctx.beginPath();
+
+ var penUp = 1;
+ var needStroke = 0;
+ for ( var j = 0; j < c.points.length; j++) {
+ var a = c.points[j];
+ if ( a[0] == -1 && a[1] == -1) {
+ penUp = 1;
+ continue;
+ }
+ if ( penUp) {
+ ctx.moveTo( x + a[0]*mag*this.fontStretch, y - a[1]*mag);
+ penUp = false;
+ } else {
+ ctx.lineTo( x + a[0]*mag*this.fontStretch, y - a[1]*mag);
+ }
+ }
+ ctx.stroke();
+ x += c.width*mag*this.fontStretch;
+ }
+ ctx.restore();
+ return total;
+ };
+
+ $.jqplot.CanvasTextRenderer.prototype.letters = {
+ ' ': { width: 16, points: [] },
+ '!': { width: 10, points: [[5,21],[5,7],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]] },
+ '"': { width: 16, points: [[4,21],[4,14],[-1,-1],[12,21],[12,14]] },
+ '#': { width: 21, points: [[11,25],[4,-7],[-1,-1],[17,25],[10,-7],[-1,-1],[4,12],[18,12],[-1,-1],[3,6],[17,6]] },
+ '$': { width: 20, points: [[8,25],[8,-4],[-1,-1],[12,25],[12,-4],[-1,-1],[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
+ '%': { width: 24, points: [[21,21],[3,0],[-1,-1],[8,21],[10,19],[10,17],[9,15],[7,14],[5,14],[3,16],[3,18],[4,20],[6,21],[8,21],[10,20],[13,19],[16,19],[19,20],[21,21],[-1,-1],[17,7],[15,6],[14,4],[14,2],[16,0],[18,0],[20,1],[21,3],[21,5],[19,7],[17,7]] },
+ '&': { width: 26, points: [[23,12],[23,13],[22,14],[21,14],[20,13],[19,11],[17,6],[15,3],[13,1],[11,0],[7,0],[5,1],[4,2],[3,4],[3,6],[4,8],[5,9],[12,13],[13,14],[14,16],[14,18],[13,20],[11,21],[9,20],[8,18],[8,16],[9,13],[11,10],[16,3],[18,1],[20,0],[22,0],[23,1],[23,2]] },
+ '\'': { width: 10, points: [[5,19],[4,20],[5,21],[6,20],[6,18],[5,16],[4,15]] },
+ '(': { width: 14, points: [[11,25],[9,23],[7,20],[5,16],[4,11],[4,7],[5,2],[7,-2],[9,-5],[11,-7]] },
+ ')': { width: 14, points: [[3,25],[5,23],[7,20],[9,16],[10,11],[10,7],[9,2],[7,-2],[5,-5],[3,-7]] },
+ '*': { width: 16, points: [[8,21],[8,9],[-1,-1],[3,18],[13,12],[-1,-1],[13,18],[3,12]] },
+ '+': { width: 26, points: [[13,18],[13,0],[-1,-1],[4,9],[22,9]] },
+ ',': { width: 10, points: [[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
+ '-': { width: 18, points: [[6,9],[12,9]] },
+ '.': { width: 10, points: [[5,2],[4,1],[5,0],[6,1],[5,2]] },
+ '/': { width: 22, points: [[20,25],[2,-7]] },
+ '0': { width: 20, points: [[9,21],[6,20],[4,17],[3,12],[3,9],[4,4],[6,1],[9,0],[11,0],[14,1],[16,4],[17,9],[17,12],[16,17],[14,20],[11,21],[9,21]] },
+ '1': { width: 20, points: [[6,17],[8,18],[11,21],[11,0]] },
+ '2': { width: 20, points: [[4,16],[4,17],[5,19],[6,20],[8,21],[12,21],[14,20],[15,19],[16,17],[16,15],[15,13],[13,10],[3,0],[17,0]] },
+ '3': { width: 20, points: [[5,21],[16,21],[10,13],[13,13],[15,12],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
+ '4': { width: 20, points: [[13,21],[3,7],[18,7],[-1,-1],[13,21],[13,0]] },
+ '5': { width: 20, points: [[15,21],[5,21],[4,12],[5,13],[8,14],[11,14],[14,13],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
+ '6': { width: 20, points: [[16,18],[15,20],[12,21],[10,21],[7,20],[5,17],[4,12],[4,7],[5,3],[7,1],[10,0],[11,0],[14,1],[16,3],[17,6],[17,7],[16,10],[14,12],[11,13],[10,13],[7,12],[5,10],[4,7]] },
+ '7': { width: 20, points: [[17,21],[7,0],[-1,-1],[3,21],[17,21]] },
+ '8': { width: 20, points: [[8,21],[5,20],[4,18],[4,16],[5,14],[7,13],[11,12],[14,11],[16,9],[17,7],[17,4],[16,2],[15,1],[12,0],[8,0],[5,1],[4,2],[3,4],[3,7],[4,9],[6,11],[9,12],[13,13],[15,14],[16,16],[16,18],[15,20],[12,21],[8,21]] },
+ '9': { width: 20, points: [[16,14],[15,11],[13,9],[10,8],[9,8],[6,9],[4,11],[3,14],[3,15],[4,18],[6,20],[9,21],[10,21],[13,20],[15,18],[16,14],[16,9],[15,4],[13,1],[10,0],[8,0],[5,1],[4,3]] },
+ ':': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]] },
+ ';': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
+ '<': { width: 24, points: [[20,18],[4,9],[20,0]] },
+ '=': { width: 26, points: [[4,12],[22,12],[-1,-1],[4,6],[22,6]] },
+ '>': { width: 24, points: [[4,18],[20,9],[4,0]] },
+ '?': { width: 18, points: [[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],[-1,-1],[9,2],[8,1],[9,0],[10,1],[9,2]] },
+ '@': { width: 27, points: [[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],[-1,-1],[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],[-1,-1],[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],[-1,-1],[19,16],[18,8],[18,6],[19,5]] },
+ 'A': { width: 18, points: [[9,21],[1,0],[-1,-1],[9,21],[17,0],[-1,-1],[4,7],[14,7]] },
+ 'B': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[-1,-1],[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]] },
+ 'C': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]] },
+ 'D': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]] },
+ 'E': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11],[-1,-1],[4,0],[17,0]] },
+ 'F': { width: 18, points: [[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11]] },
+ 'G': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],[-1,-1],[13,8],[18,8]] },
+ 'H': { width: 22, points: [[4,21],[4,0],[-1,-1],[18,21],[18,0],[-1,-1],[4,11],[18,11]] },
+ 'I': { width: 8, points: [[4,21],[4,0]] },
+ 'J': { width: 16, points: [[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]] },
+ 'K': { width: 21, points: [[4,21],[4,0],[-1,-1],[18,21],[4,7],[-1,-1],[9,12],[18,0]] },
+ 'L': { width: 17, points: [[4,21],[4,0],[-1,-1],[4,0],[16,0]] },
+ 'M': { width: 24, points: [[4,21],[4,0],[-1,-1],[4,21],[12,0],[-1,-1],[20,21],[12,0],[-1,-1],[20,21],[20,0]] },
+ 'N': { width: 22, points: [[4,21],[4,0],[-1,-1],[4,21],[18,0],[-1,-1],[18,21],[18,0]] },
+ 'O': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]] },
+ 'P': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]] },
+ 'Q': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],[-1,-1],[12,4],[18,-2]] },
+ 'R': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],[-1,-1],[11,11],[18,0]] },
+ 'S': { width: 20, points: [[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
+ 'T': { width: 16, points: [[8,21],[8,0],[-1,-1],[1,21],[15,21]] },
+ 'U': { width: 22, points: [[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]] },
+ 'V': { width: 18, points: [[1,21],[9,0],[-1,-1],[17,21],[9,0]] },
+ 'W': { width: 24, points: [[2,21],[7,0],[-1,-1],[12,21],[7,0],[-1,-1],[12,21],[17,0],[-1,-1],[22,21],[17,0]] },
+ 'X': { width: 20, points: [[3,21],[17,0],[-1,-1],[17,21],[3,0]] },
+ 'Y': { width: 18, points: [[1,21],[9,11],[9,0],[-1,-1],[17,21],[9,11]] },
+ 'Z': { width: 20, points: [[17,21],[3,0],[-1,-1],[3,21],[17,21],[-1,-1],[3,0],[17,0]] },
+ '[': { width: 14, points: [[4,25],[4,-7],[-1,-1],[5,25],[5,-7],[-1,-1],[4,25],[11,25],[-1,-1],[4,-7],[11,-7]] },
+ '\\': { width: 14, points: [[0,21],[14,-3]] },
+ ']': { width: 14, points: [[9,25],[9,-7],[-1,-1],[10,25],[10,-7],[-1,-1],[3,25],[10,25],[-1,-1],[3,-7],[10,-7]] },
+ '^': { width: 16, points: [[6,15],[8,18],[10,15],[-1,-1],[3,12],[8,17],[13,12],[-1,-1],[8,17],[8,0]] },
+ '_': { width: 16, points: [[0,-2],[16,-2]] },
+ '`': { width: 10, points: [[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]] },
+ 'a': { width: 19, points: [[15,14],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'b': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
+ 'c': { width: 18, points: [[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'd': { width: 19, points: [[15,21],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'e': { width: 18, points: [[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'f': { width: 12, points: [[10,21],[8,21],[6,20],[5,17],[5,0],[-1,-1],[2,14],[9,14]] },
+ 'g': { width: 19, points: [[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'h': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
+ 'i': { width: 8, points: [[3,21],[4,20],[5,21],[4,22],[3,21],[-1,-1],[4,14],[4,0]] },
+ 'j': { width: 10, points: [[5,21],[6,20],[7,21],[6,22],[5,21],[-1,-1],[6,14],[6,-3],[5,-6],[3,-7],[1,-7]] },
+ 'k': { width: 17, points: [[4,21],[4,0],[-1,-1],[14,14],[4,4],[-1,-1],[8,8],[15,0]] },
+ 'l': { width: 8, points: [[4,21],[4,0]] },
+ 'm': { width: 30, points: [[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],[-1,-1],[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]] },
+ 'n': { width: 19, points: [[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
+ 'o': { width: 19, points: [[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]] },
+ 'p': { width: 19, points: [[4,14],[4,-7],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
+ 'q': { width: 19, points: [[15,14],[15,-7],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
+ 'r': { width: 13, points: [[4,14],[4,0],[-1,-1],[4,8],[5,11],[7,13],[9,14],[12,14]] },
+ 's': { width: 17, points: [[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]] },
+ 't': { width: 12, points: [[5,21],[5,4],[6,1],[8,0],[10,0],[-1,-1],[2,14],[9,14]] },
+ 'u': { width: 19, points: [[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],[-1,-1],[15,14],[15,0]] },
+ 'v': { width: 16, points: [[2,14],[8,0],[-1,-1],[14,14],[8,0]] },
+ 'w': { width: 22, points: [[3,14],[7,0],[-1,-1],[11,14],[7,0],[-1,-1],[11,14],[15,0],[-1,-1],[19,14],[15,0]] },
+ 'x': { width: 17, points: [[3,14],[14,0],[-1,-1],[14,14],[3,0]] },
+ 'y': { width: 16, points: [[2,14],[8,0],[-1,-1],[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]] },
+ 'z': { width: 17, points: [[14,14],[3,0],[-1,-1],[3,14],[14,14],[-1,-1],[3,0],[14,0]] },
+ '{': { width: 14, points: [[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],[-1,-1],[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],[-1,-1],[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]] },
+ '|': { width: 8, points: [[4,25],[4,-7]] },
+ '}': { width: 14, points: [[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],[-1,-1],[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],[-1,-1],[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]] },
+ '~': { width: 24, points: [[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],[-1,-1],[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]] }
+ };
+
+ $.jqplot.CanvasFontRenderer = function(options) {
+ options = options || {};
+ if (!options.pt2px) {
+ options.pt2px = 1.5;
+ }
+ $.jqplot.CanvasTextRenderer.call(this, options);
+ };
+
+ $.jqplot.CanvasFontRenderer.prototype = new $.jqplot.CanvasTextRenderer({});
+ $.jqplot.CanvasFontRenderer.prototype.constructor = $.jqplot.CanvasFontRenderer;
+
+ $.jqplot.CanvasFontRenderer.prototype.measure = function(ctx, str)
+ {
+ // var fstyle = this.fontStyle+' '+this.fontVariant+' '+this.fontWeight+' '+this.fontSize+' '+this.fontFamily;
+ var fstyle = this.fontSize+' '+this.fontFamily;
+ ctx.save();
+ ctx.font = fstyle;
+ var w = ctx.measureText(str).width;
+ ctx.restore();
+ return w;
+ };
+
+ $.jqplot.CanvasFontRenderer.prototype.draw = function(ctx, str)
+ {
+ var x = 0;
+ // leave room at bottom for descenders.
+ var y = this.height*0.72;
+ //var y = 12;
+
+ ctx.save();
+ var tx, ty;
+
+ // 1st quadrant
+ if ((-Math.PI/2 <= this.angle && this.angle <= 0) || (Math.PI*3/2 <= this.angle && this.angle <= Math.PI*2)) {
+ tx = 0;
+ ty = -Math.sin(this.angle) * this.width;
+ }
+ // 4th quadrant
+ else if ((0 < this.angle && this.angle <= Math.PI/2) || (-Math.PI*2 <= this.angle && this.angle <= -Math.PI*3/2)) {
+ tx = Math.sin(this.angle) * this.height;
+ ty = 0;
+ }
+ // 2nd quadrant
+ else if ((-Math.PI < this.angle && this.angle < -Math.PI/2) || (Math.PI <= this.angle && this.angle <= Math.PI*3/2)) {
+ tx = -Math.cos(this.angle) * this.width;
+ ty = -Math.sin(this.angle) * this.width - Math.cos(this.angle) * this.height;
+ }
+ // 3rd quadrant
+ else if ((-Math.PI*3/2 < this.angle && this.angle < Math.PI) || (Math.PI/2 < this.angle && this.angle < Math.PI)) {
+ tx = Math.sin(this.angle) * this.height - Math.cos(this.angle)*this.width;
+ ty = -Math.cos(this.angle) * this.height;
+ }
+ ctx.strokeStyle = this.fillStyle;
+ ctx.fillStyle = this.fillStyle;
+ // var fstyle = this.fontStyle+' '+this.fontVariant+' '+this.fontWeight+' '+this.fontSize+' '+this.fontFamily;
+ var fstyle = this.fontSize+' '+this.fontFamily;
+ ctx.font = fstyle;
+ ctx.translate(tx, ty);
+ ctx.rotate(this.angle);
+ ctx.fillText(str, x, y);
+ // ctx.strokeText(str, x, y);
+
+ ctx.restore();
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.categoryAxisRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.categoryAxisRenderer.js
new file mode 100644
index 00000000..4cea2de6
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.categoryAxisRenderer.js
@@ -0,0 +1,673 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * class: $.jqplot.CategoryAxisRenderer
+ * A plugin for jqPlot to render a category style axis, with equal pixel spacing between y data values of a series.
+ *
+ * To use this renderer, include the plugin in your source
+ * > <script type="text/javascript" language="javascript" src="plugins/jqplot.categoryAxisRenderer.js"></script>
+ *
+ * and supply the appropriate options to your plot
+ *
+ * > {axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}}}
+ **/
+ $.jqplot.CategoryAxisRenderer = function(options) {
+ $.jqplot.LinearAxisRenderer.call(this);
+ // prop: sortMergedLabels
+ // True to sort tick labels when labels are created by merging
+ // x axis values from multiple series. That is, say you have
+ // two series like:
+ // > line1 = [[2006, 4], [2008, 9], [2009, 16]];
+ // > line2 = [[2006, 3], [2007, 7], [2008, 6]];
+ // If no label array is specified, tick labels will be collected
+ // from the x values of the series. With sortMergedLabels
+ // set to true, tick labels will be:
+ // > [2006, 2007, 2008, 2009]
+ // With sortMergedLabels set to false, tick labels will be:
+ // > [2006, 2008, 2009, 2007]
+ //
+ // Note, this property is specified on the renderOptions for the
+ // axes when creating a plot:
+ // > axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer, rendererOptions:{sortMergedLabels:true}}}
+ this.sortMergedLabels = false;
+ };
+
+ $.jqplot.CategoryAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.CategoryAxisRenderer.prototype.constructor = $.jqplot.CategoryAxisRenderer;
+
+ $.jqplot.CategoryAxisRenderer.prototype.init = function(options){
+ this.groups = 1;
+ this.groupLabels = [];
+ this._groupLabels = [];
+ this._grouped = false;
+ this._barsPerGroup = null;
+ this.reverse = false;
+ // prop: tickRenderer
+ // A class of a rendering engine for creating the ticks labels displayed on the plot,
+ // See <$.jqplot.AxisTickRenderer>.
+ // this.tickRenderer = $.jqplot.AxisTickRenderer;
+ // this.labelRenderer = $.jqplot.AxisLabelRenderer;
+ $.extend(true, this, {tickOptions:{formatString:'%d'}}, options);
+ var db = this._dataBounds;
+ // Go through all the series attached to this axis and find
+ // the min/max bounds for this axis.
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ if (s.groups) {
+ this.groups = s.groups;
+ }
+ var d = s.data;
+
+ for (var j=0; j<d.length; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ if (d[j][0] < db.min || db.min == null) {
+ db.min = d[j][0];
+ }
+ if (d[j][0] > db.max || db.max == null) {
+ db.max = d[j][0];
+ }
+ }
+ else {
+ if (d[j][1] < db.min || db.min == null) {
+ db.min = d[j][1];
+ }
+ if (d[j][1] > db.max || db.max == null) {
+ db.max = d[j][1];
+ }
+ }
+ }
+ }
+
+ if (this.groupLabels.length) {
+ this.groups = this.groupLabels.length;
+ }
+ };
+
+
+ $.jqplot.CategoryAxisRenderer.prototype.createTicks = function() {
+ // we're are operating on an axis here
+ var ticks = this._ticks;
+ var userTicks = this.ticks;
+ var name = this.name;
+ // databounds were set on axis initialization.
+ var db = this._dataBounds;
+ var dim, interval;
+ var min, max;
+ var pos1, pos2;
+ var tt, i;
+
+ // if we already have ticks, use them.
+ if (userTicks.length) {
+ // adjust with blanks if we have groups
+ if (this.groups > 1 && !this._grouped) {
+ var l = userTicks.length;
+ var skip = parseInt(l/this.groups, 10);
+ var count = 0;
+ for (var i=skip; i<l; i+=skip) {
+ userTicks.splice(i+count, 0, ' ');
+ count++;
+ }
+ this._grouped = true;
+ }
+ this.min = 0.5;
+ this.max = userTicks.length + 0.5;
+ var range = this.max - this.min;
+ this.numberTicks = 2*userTicks.length + 1;
+ for (i=0; i<userTicks.length; i++){
+ tt = this.min + 2 * i * range / (this.numberTicks-1);
+ // need a marker before and after the tick
+ var t = new this.tickRenderer(this.tickOptions);
+ t.showLabel = false;
+ // t.showMark = true;
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+ var t = new this.tickRenderer(this.tickOptions);
+ t.label = userTicks[i];
+ // t.showLabel = true;
+ t.showMark = false;
+ t.showGridline = false;
+ t.setTick(tt+0.5, this.name);
+ this._ticks.push(t);
+ }
+ // now add the last tick at the end
+ var t = new this.tickRenderer(this.tickOptions);
+ t.showLabel = false;
+ // t.showMark = true;
+ t.setTick(tt+1, this.name);
+ this._ticks.push(t);
+ }
+
+ // we don't have any ticks yet, let's make some!
+ else {
+ if (name == 'xaxis' || name == 'x2axis') {
+ dim = this._plotDimensions.width;
+ }
+ else {
+ dim = this._plotDimensions.height;
+ }
+
+ // if min, max and number of ticks specified, user can't specify interval.
+ if (this.min != null && this.max != null && this.numberTicks != null) {
+ this.tickInterval = null;
+ }
+
+ // if max, min, and interval specified and interval won't fit, ignore interval.
+ if (this.min != null && this.max != null && this.tickInterval != null) {
+ if (parseInt((this.max-this.min)/this.tickInterval, 10) != (this.max-this.min)/this.tickInterval) {
+ this.tickInterval = null;
+ }
+ }
+
+ // find out how many categories are in the lines and collect labels
+ var labels = [];
+ var numcats = 0;
+ var min = 0.5;
+ var max, val;
+ var isMerged = false;
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ for (var j=0; j<s.data.length; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ val = s.data[j][0];
+ }
+ else {
+ val = s.data[j][1];
+ }
+ if ($.inArray(val, labels) == -1) {
+ isMerged = true;
+ numcats += 1;
+ labels.push(val);
+ }
+ }
+ }
+
+ if (isMerged && this.sortMergedLabels) {
+ labels.sort(function(a,b) { return a - b; });
+ }
+
+ // keep a reference to these tick labels to use for redrawing plot (see bug #57)
+ this.ticks = labels;
+
+ // now bin the data values to the right lables.
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ for (var j=0; j<s.data.length; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ val = s.data[j][0];
+ }
+ else {
+ val = s.data[j][1];
+ }
+ // for category axis, force the values into category bins.
+ // we should have the value in the label array now.
+ var idx = $.inArray(val, labels)+1;
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ s.data[j][0] = idx;
+ }
+ else {
+ s.data[j][1] = idx;
+ }
+ }
+ }
+
+ // adjust with blanks if we have groups
+ if (this.groups > 1 && !this._grouped) {
+ var l = labels.length;
+ var skip = parseInt(l/this.groups, 10);
+ var count = 0;
+ for (var i=skip; i<l; i+=skip+1) {
+ labels[i] = ' ';
+ }
+ this._grouped = true;
+ }
+
+ max = numcats + 0.5;
+ if (this.numberTicks == null) {
+ this.numberTicks = 2*numcats + 1;
+ }
+
+ var range = max - min;
+ this.min = min;
+ this.max = max;
+ var track = 0;
+
+ // todo: adjust this so more ticks displayed.
+ var maxVisibleTicks = parseInt(3+dim/10, 10);
+ var skip = parseInt(numcats/maxVisibleTicks, 10);
+
+ if (this.tickInterval == null) {
+
+ this.tickInterval = range / (this.numberTicks-1);
+
+ }
+ // if tickInterval is specified, we will ignore any computed maximum.
+ for (var i=0; i<this.numberTicks; i++){
+ tt = this.min + i * this.tickInterval;
+ var t = new this.tickRenderer(this.tickOptions);
+ // if even tick, it isn't a category, it's a divider
+ if (i/2 == parseInt(i/2, 10)) {
+ t.showLabel = false;
+ t.showMark = true;
+ }
+ else {
+ if (skip>0 && track<skip) {
+ t.showLabel = false;
+ track += 1;
+ }
+ else {
+ t.showLabel = true;
+ track = 0;
+ }
+ t.label = t.formatter(t.formatString, labels[(i-1)/2]);
+ t.showMark = false;
+ t.showGridline = false;
+ }
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+ }
+ }
+
+ };
+
+ // called with scope of axis
+ $.jqplot.CategoryAxisRenderer.prototype.draw = function(ctx, plot) {
+ if (this.show) {
+ // populate the axis label and value properties.
+ // createTicks is a method on the renderer, but
+ // call it within the scope of the axis.
+ this.renderer.createTicks.call(this);
+ // fill a div with axes labels in the right direction.
+ // Need to pregenerate each axis to get it's bounds and
+ // position it and the labels correctly on the plot.
+ var dim=0;
+ var temp;
+ // Added for theming.
+ if (this._elem) {
+ // this._elem.empty();
+ // Memory Leaks patch
+ this._elem.emptyForce();
+ }
+
+ this._elem = this._elem || $('<div class="jqplot-axis jqplot-'+this.name+'" style="position:absolute;"></div>');
+
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ this._elem.width(this._plotDimensions.width);
+ }
+ else {
+ this._elem.height(this._plotDimensions.height);
+ }
+
+ // create a _label object.
+ this.labelOptions.axis = this.name;
+ this._label = new this.labelRenderer(this.labelOptions);
+ if (this._label.show) {
+ var elem = this._label.draw(ctx, plot);
+ elem.appendTo(this._elem);
+ }
+
+ var t = this._ticks;
+ for (var i=0; i<t.length; i++) {
+ var tick = t[i];
+ if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
+ var elem = tick.draw(ctx, plot);
+ elem.appendTo(this._elem);
+ }
+ }
+
+ this._groupLabels = [];
+ // now make group labels
+ for (var i=0; i<this.groupLabels.length; i++)
+ {
+ var elem = $('<div style="position:absolute;" class="jqplot-'+this.name+'-groupLabel"></div>');
+ elem.html(this.groupLabels[i]);
+ this._groupLabels.push(elem);
+ elem.appendTo(this._elem);
+ }
+ }
+ return this._elem;
+ };
+
+ // called with scope of axis
+ $.jqplot.CategoryAxisRenderer.prototype.set = function() {
+ var dim = 0;
+ var temp;
+ var w = 0;
+ var h = 0;
+ var lshow = (this._label == null) ? false : this._label.show;
+ if (this.show) {
+ var t = this._ticks;
+ for (var i=0; i<t.length; i++) {
+ var tick = t[i];
+ if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ temp = tick._elem.outerHeight(true);
+ }
+ else {
+ temp = tick._elem.outerWidth(true);
+ }
+ if (temp > dim) {
+ dim = temp;
+ }
+ }
+ }
+
+ var dim2 = 0;
+ for (var i=0; i<this._groupLabels.length; i++) {
+ var l = this._groupLabels[i];
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ temp = l.outerHeight(true);
+ }
+ else {
+ temp = l.outerWidth(true);
+ }
+ if (temp > dim2) {
+ dim2 = temp;
+ }
+ }
+
+ if (lshow) {
+ w = this._label._elem.outerWidth(true);
+ h = this._label._elem.outerHeight(true);
+ }
+ if (this.name == 'xaxis') {
+ dim += dim2 + h;
+ this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});
+ }
+ else if (this.name == 'x2axis') {
+ dim += dim2 + h;
+ this._elem.css({'height':dim+'px', left:'0px', top:'0px'});
+ }
+ else if (this.name == 'yaxis') {
+ dim += dim2 + w;
+ this._elem.css({'width':dim+'px', left:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ else {
+ dim += dim2 + w;
+ this._elem.css({'width':dim+'px', right:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.CategoryAxisRenderer.prototype.pack = function(pos, offsets) {
+ var ticks = this._ticks;
+ var max = this.max;
+ var min = this.min;
+ var offmax = offsets.max;
+ var offmin = offsets.min;
+ var lshow = (this._label == null) ? false : this._label.show;
+ var i;
+
+ for (var p in pos) {
+ this._elem.css(p, pos[p]);
+ }
+
+ this._offsets = offsets;
+ // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
+ var pixellength = offmax - offmin;
+ var unitlength = max - min;
+
+ if (!this.reverse) {
+ // point to unit and unit to point conversions references to Plot DOM element top left corner.
+
+ this.u2p = function(u){
+ return (u - min) * pixellength / unitlength + offmin;
+ };
+
+ this.p2u = function(p){
+ return (p - offmin) * unitlength / pixellength + min;
+ };
+
+ if (this.name == 'xaxis' || this.name == 'x2axis'){
+ this.series_u2p = function(u){
+ return (u - min) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+
+ else {
+ this.series_u2p = function(u){
+ return (u - max) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + max;
+ };
+ }
+ }
+
+ else {
+ // point to unit and unit to point conversions references to Plot DOM element top left corner.
+
+ this.u2p = function(u){
+ return offmin + (max - u) * pixellength / unitlength;
+ };
+
+ this.p2u = function(p){
+ return min + (p - offmin) * unitlength / pixellength;
+ };
+
+ if (this.name == 'xaxis' || this.name == 'x2axis'){
+ this.series_u2p = function(u){
+ return (max - u) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + max;
+ };
+ }
+
+ else {
+ this.series_u2p = function(u){
+ return (min - u) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+
+ }
+
+
+ if (this.show) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ for (i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'xaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ if (temp * t.angle < 0) {
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ }
+ // position at start
+ else {
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'end':
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ case 'start':
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ break;
+ case 'middle':
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ default:
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getWidth()/2;
+ }
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('left', val);
+ t.pack();
+ }
+ }
+
+ var labeledge=['bottom', 0];
+ if (lshow) {
+ var w = this._label._elem.outerWidth(true);
+ this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
+ if (this.name == 'xaxis') {
+ this._label._elem.css('bottom', '0px');
+ labeledge = ['bottom', this._label._elem.outerHeight(true)];
+ }
+ else {
+ this._label._elem.css('top', '0px');
+ labeledge = ['top', this._label._elem.outerHeight(true)];
+ }
+ this._label.pack();
+ }
+
+ // draw the group labels
+ var step = parseInt(this._ticks.length/this.groups, 10);
+ for (i=0; i<this._groupLabels.length; i++) {
+ var mid = 0;
+ var count = 0;
+ for (var j=i*step; j<=(i+1)*step; j++) {
+ if (this._ticks[j]._elem && this._ticks[j].label != " ") {
+ var t = this._ticks[j]._elem;
+ var p = t.position();
+ mid += p.left + t.outerWidth(true)/2;
+ count++;
+ }
+ }
+ mid = mid/count;
+ this._groupLabels[i].css({'left':(mid - this._groupLabels[i].outerWidth(true)/2)});
+ this._groupLabels[i].css(labeledge[0], labeledge[1]);
+ }
+ }
+ else {
+ for (i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'yaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ case 'end':
+ if (temp * t.angle < 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'start':
+ if (t.angle > 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'middle':
+ // if (t.angle > 0) {
+ // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ // }
+ // else {
+ // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ // }
+ shim = -t.getHeight()/2;
+ break;
+ default:
+ shim = -t.getHeight()/2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getHeight()/2;
+ }
+
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('top', val);
+ t.pack();
+ }
+ }
+
+ var labeledge=['left', 0];
+ if (lshow) {
+ var h = this._label._elem.outerHeight(true);
+ this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
+ if (this.name == 'yaxis') {
+ this._label._elem.css('left', '0px');
+ labeledge = ['left', this._label._elem.outerWidth(true)];
+ }
+ else {
+ this._label._elem.css('right', '0px');
+ labeledge = ['right', this._label._elem.outerWidth(true)];
+ }
+ this._label.pack();
+ }
+
+ // draw the group labels, position top here, do left after label position.
+ var step = parseInt(this._ticks.length/this.groups, 10);
+ for (i=0; i<this._groupLabels.length; i++) {
+ var mid = 0;
+ var count = 0;
+ for (var j=i*step; j<=(i+1)*step; j++) {
+ if (this._ticks[j]._elem && this._ticks[j].label != " ") {
+ var t = this._ticks[j]._elem;
+ var p = t.position();
+ mid += p.top + t.outerHeight()/2;
+ count++;
+ }
+ }
+ mid = mid/count;
+ this._groupLabels[i].css({'top':mid - this._groupLabels[i].outerHeight()/2});
+ this._groupLabels[i].css(labeledge[0], labeledge[1]);
+
+ }
+ }
+ }
+ };
+
+
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.ciParser.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.ciParser.js
new file mode 100644
index 00000000..22401dc7
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.ciParser.js
@@ -0,0 +1,116 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.ciParser
+ * Data Renderer function which converts a custom JSON data object into jqPlot data format.
+ * Set this as a callable on the jqplot dataRenderer plot option:
+ *
+ * > plot = $.jqplot('mychart', [data], { dataRenderer: $.jqplot.ciParser, ... });
+ *
+ * Where data is an object in JSON format or a JSON encoded string conforming to the
+ * City Index API spec.
+ *
+ * Note that calling the renderer function is handled internally by jqPlot. The
+ * user does not have to call the function. The parameters described below will
+ * automatically be passed to the ciParser function.
+ *
+ * Parameters:
+ * data - JSON encoded string or object.
+ * plot - reference to jqPlot Plot object.
+ *
+ * Returns:
+ * data array in jqPlot format.
+ *
+ */
+ $.jqplot.ciParser = function (data, plot) {
+ var ret = [],
+ line,
+ temp,
+ i, j, k, kk;
+
+ if (typeof(data) == "string") {
+ data = $.jqplot.JSON.parse(data, handleStrings);
+ }
+
+ else if (typeof(data) == "object") {
+ for (k in data) {
+ for (i=0; i<data[k].length; i++) {
+ for (kk in data[k][i]) {
+ data[k][i][kk] = handleStrings(kk, data[k][i][kk]);
+ }
+ }
+ }
+ }
+
+ else {
+ return null;
+ }
+
+ // function handleStrings
+ // Checks any JSON encoded strings to see if they are
+ // encoded dates. If so, pull out the timestamp.
+ // Expects dates to be represented by js timestamps.
+
+ function handleStrings(key, value) {
+ var a;
+ if (value != null) {
+ if (value.toString().indexOf('Date') >= 0) {
+ //here we will try to extract the ticks from the Date string in the "value" fields of JSON returned data
+ a = /^\/Date\((-?[0-9]+)\)\/$/.exec(value);
+ if (a) {
+ return parseInt(a[1], 10);
+ }
+ }
+ return value;
+ }
+ }
+
+ for (var prop in data) {
+ line = [];
+ temp = data[prop];
+ switch (prop) {
+ case "PriceTicks":
+ for (i=0; i<temp.length; i++) {
+ line.push([temp[i]['TickDate'], temp[i]['Price']]);
+ }
+ break;
+ case "PriceBars":
+ for (i=0; i<temp.length; i++) {
+ line.push([temp[i]['BarDate'], temp[i]['Open'], temp[i]['High'], temp[i]['Low'], temp[i]['Close']]);
+ }
+ break;
+ }
+ ret.push(line);
+ }
+ return ret;
+ };
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.cursor.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.cursor.js
new file mode 100644
index 00000000..0e583682
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.cursor.js
@@ -0,0 +1,1108 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+
+ /**
+ * Class: $.jqplot.Cursor
+ * Plugin class representing the cursor as displayed on the plot.
+ */
+ $.jqplot.Cursor = function(options) {
+ // Group: Properties
+ //
+ // prop: style
+ // CSS spec for cursor style
+ this.style = 'crosshair';
+ this.previousCursor = 'auto';
+ // prop: show
+ // wether to show the cursor or not.
+ this.show = $.jqplot.config.enablePlugins;
+ // prop: showTooltip
+ // show a cursor position tooltip. Location of the tooltip
+ // will be controlled by followMouse and tooltipLocation.
+ this.showTooltip = true;
+ // prop: followMouse
+ // Tooltip follows the mouse, it is not at a fixed location.
+ // Tooltip will show on the grid at the location given by
+ // tooltipLocation, offset from the grid edge by tooltipOffset.
+ this.followMouse = false;
+ // prop: tooltipLocation
+ // Where to position tooltip. If followMouse is true, this is
+ // relative to the cursor, otherwise, it is relative to the grid.
+ // One of 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
+ this.tooltipLocation = 'se';
+ // prop: tooltipOffset
+ // Pixel offset of tooltip from the grid boudaries or cursor center.
+ this.tooltipOffset = 6;
+ // prop: showTooltipGridPosition
+ // show the grid pixel coordinates of the mouse.
+ this.showTooltipGridPosition = false;
+ // prop: showTooltipUnitPosition
+ // show the unit (data) coordinates of the mouse.
+ this.showTooltipUnitPosition = true;
+ // prop: showTooltipDataPosition
+ // Used with showVerticalLine to show intersecting data points in the tooltip.
+ this.showTooltipDataPosition = false;
+ // prop: tooltipFormatString
+ // sprintf format string for the tooltip.
+ // Uses Ash Searle's javascript sprintf implementation
+ // found here: http://hexmen.com/blog/2007/03/printf-sprintf/
+ // See http://perldoc.perl.org/functions/sprintf.html for reference
+ // Note, if showTooltipDataPosition is true, the default tooltipFormatString
+ // will be set to the cursorLegendFormatString, not the default given here.
+ this.tooltipFormatString = '%.4P, %.4P';
+ // prop: useAxesFormatters
+ // Use the x and y axes formatters to format the text in the tooltip.
+ this.useAxesFormatters = true;
+ // prop: tooltipAxisGroups
+ // Show position for the specified axes.
+ // This is an array like [['xaxis', 'yaxis'], ['xaxis', 'y2axis']]
+ // Default is to compute automatically for all visible axes.
+ this.tooltipAxisGroups = [];
+ // prop: zoom
+ // Enable plot zooming.
+ this.zoom = false;
+ // zoomProxy and zoomTarget properties are not directly set by user.
+ // They Will be set through call to zoomProxy method.
+ this.zoomProxy = false;
+ this.zoomTarget = false;
+ // prop: looseZoom
+ // Will expand zoom range to provide more rounded tick values.
+ // Works only with linear, log and date axes.
+ this.looseZoom = true;
+ // prop: clickReset
+ // Will reset plot zoom if single click on plot without drag.
+ this.clickReset = false;
+ // prop: dblClickReset
+ // Will reset plot zoom if double click on plot without drag.
+ this.dblClickReset = true;
+ // prop: showVerticalLine
+ // draw a vertical line across the plot which follows the cursor.
+ // When the line is near a data point, a special legend and/or tooltip can
+ // be updated with the data values.
+ this.showVerticalLine = false;
+ // prop: showHorizontalLine
+ // draw a horizontal line across the plot which follows the cursor.
+ this.showHorizontalLine = false;
+ // prop: constrainZoomTo
+ // 'none', 'x' or 'y'
+ this.constrainZoomTo = 'none';
+ // // prop: autoscaleConstraint
+ // // when a constrained axis is specified, true will
+ // // auatoscale the adjacent axis.
+ // this.autoscaleConstraint = true;
+ this.shapeRenderer = new $.jqplot.ShapeRenderer();
+ this._zoom = {start:[], end:[], started: false, zooming:false, isZoomed:false, axes:{start:{}, end:{}}, gridpos:{}, datapos:{}};
+ this._tooltipElem;
+ this.zoomCanvas;
+ this.cursorCanvas;
+ // prop: intersectionThreshold
+ // pixel distance from data point or marker to consider cursor lines intersecting with point.
+ // If data point markers are not shown, this should be >= 1 or will often miss point intersections.
+ this.intersectionThreshold = 2;
+ // prop: showCursorLegend
+ // Replace the plot legend with an enhanced legend displaying intersection information.
+ this.showCursorLegend = false;
+ // prop: cursorLegendFormatString
+ // Format string used in the cursor legend. If showTooltipDataPosition is true,
+ // this will also be the default format string used by tooltipFormatString.
+ this.cursorLegendFormatString = $.jqplot.Cursor.cursorLegendFormatString;
+ // whether the cursor is over the grid or not.
+ this._oldHandlers = {onselectstart: null, ondrag: null, onmousedown: null};
+ // prop: constrainOutsideZoom
+ // True to limit actual zoom area to edges of grid, even when zooming
+ // outside of plot area. That is, can't zoom out by mousing outside plot.
+ this.constrainOutsideZoom = true;
+ // prop: showTooltipOutsideZoom
+ // True will keep updating the tooltip when zooming of the grid.
+ this.showTooltipOutsideZoom = false;
+ // true if mouse is over grid, false if not.
+ this.onGrid = false;
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.Cursor.cursorLegendFormatString = '%s x:%s, y:%s';
+
+ // called with scope of plot
+ $.jqplot.Cursor.init = function (target, data, opts){
+ // add a cursor attribute to the plot
+ var options = opts || {};
+ this.plugins.cursor = new $.jqplot.Cursor(options.cursor);
+ var c = this.plugins.cursor;
+
+ if (c.show) {
+ $.jqplot.eventListenerHooks.push(['jqplotMouseEnter', handleMouseEnter]);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseLeave', handleMouseLeave]);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMouseMove]);
+
+ if (c.showCursorLegend) {
+ opts.legend = opts.legend || {};
+ opts.legend.renderer = $.jqplot.CursorLegendRenderer;
+ opts.legend.formatString = this.plugins.cursor.cursorLegendFormatString;
+ opts.legend.show = true;
+ }
+
+ if (c.zoom) {
+ $.jqplot.eventListenerHooks.push(['jqplotMouseDown', handleMouseDown]);
+
+ if (c.clickReset) {
+ $.jqplot.eventListenerHooks.push(['jqplotClick', handleClick]);
+ }
+
+ if (c.dblClickReset) {
+ $.jqplot.eventListenerHooks.push(['jqplotDblClick', handleDblClick]);
+ }
+ }
+
+ this.resetZoom = function() {
+ var axes = this.axes;
+ if (!c.zoomProxy) {
+ for (var ax in axes) {
+ axes[ax].reset();
+ axes[ax]._ticks = [];
+ // fake out tick creation algorithm to make sure original auto
+ // computed format string is used if _overrideFormatString is true
+ if (c._zoom.axes[ax] !== undefined) {
+ axes[ax]._autoFormatString = c._zoom.axes[ax].tickFormatString;
+ }
+ }
+ this.redraw();
+ }
+ else {
+ var ctx = this.plugins.cursor.zoomCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx = null;
+ }
+ this.plugins.cursor._zoom.isZoomed = false;
+ this.target.trigger('jqplotResetZoom', [this, this.plugins.cursor]);
+ };
+
+
+ if (c.showTooltipDataPosition) {
+ c.showTooltipUnitPosition = false;
+ c.showTooltipGridPosition = false;
+ if (options.cursor.tooltipFormatString == undefined) {
+ c.tooltipFormatString = $.jqplot.Cursor.cursorLegendFormatString;
+ }
+ }
+ }
+ };
+
+ // called with context of plot
+ $.jqplot.Cursor.postDraw = function() {
+ var c = this.plugins.cursor;
+
+ // Memory Leaks patch
+ if (c.zoomCanvas) {
+ c.zoomCanvas.resetCanvas();
+ c.zoomCanvas = null;
+ }
+
+ if (c.cursorCanvas) {
+ c.cursorCanvas.resetCanvas();
+ c.cursorCanvas = null;
+ }
+
+ if (c._tooltipElem) {
+ c._tooltipElem.emptyForce();
+ c._tooltipElem = null;
+ }
+
+
+ if (c.zoom) {
+ c.zoomCanvas = new $.jqplot.GenericCanvas();
+ this.eventCanvas._elem.before(c.zoomCanvas.createElement(this._gridPadding, 'jqplot-zoom-canvas', this._plotDimensions, this));
+ c.zoomCanvas.setContext();
+ }
+
+ var elem = document.createElement('div');
+ c._tooltipElem = $(elem);
+ elem = null;
+ c._tooltipElem.addClass('jqplot-cursor-tooltip');
+ c._tooltipElem.css({position:'absolute', display:'none'});
+
+
+ if (c.zoomCanvas) {
+ c.zoomCanvas._elem.before(c._tooltipElem);
+ }
+
+ else {
+ this.eventCanvas._elem.before(c._tooltipElem);
+ }
+
+ if (c.showVerticalLine || c.showHorizontalLine) {
+ c.cursorCanvas = new $.jqplot.GenericCanvas();
+ this.eventCanvas._elem.before(c.cursorCanvas.createElement(this._gridPadding, 'jqplot-cursor-canvas', this._plotDimensions, this));
+ c.cursorCanvas.setContext();
+ }
+
+ // if we are showing the positions in unit coordinates, and no axes groups
+ // were specified, create a default set.
+ if (c.showTooltipUnitPosition){
+ if (c.tooltipAxisGroups.length === 0) {
+ var series = this.series;
+ var s;
+ var temp = [];
+ for (var i=0; i<series.length; i++) {
+ s = series[i];
+ var ax = s.xaxis+','+s.yaxis;
+ if ($.inArray(ax, temp) == -1) {
+ temp.push(ax);
+ }
+ }
+ for (var i=0; i<temp.length; i++) {
+ c.tooltipAxisGroups.push(temp[i].split(','));
+ }
+ }
+ }
+ };
+
+ // Group: methods
+ //
+ // method: $.jqplot.Cursor.zoomProxy
+ // links targetPlot to controllerPlot so that plot zooming of
+ // targetPlot will be controlled by zooming on the controllerPlot.
+ // controllerPlot will not actually zoom, but acts as an
+ // overview plot. Note, the zoom options must be set to true for
+ // zoomProxy to work.
+ $.jqplot.Cursor.zoomProxy = function(targetPlot, controllerPlot) {
+ var tc = targetPlot.plugins.cursor;
+ var cc = controllerPlot.plugins.cursor;
+ tc.zoomTarget = true;
+ tc.zoom = true;
+ tc.style = 'auto';
+ tc.dblClickReset = false;
+ cc.zoom = true;
+ cc.zoomProxy = true;
+
+ controllerPlot.target.bind('jqplotZoom', plotZoom);
+ controllerPlot.target.bind('jqplotResetZoom', plotReset);
+
+ function plotZoom(ev, gridpos, datapos, plot, cursor) {
+ tc.doZoom(gridpos, datapos, targetPlot, cursor);
+ }
+
+ function plotReset(ev, plot, cursor) {
+ targetPlot.resetZoom();
+ }
+ };
+
+ $.jqplot.Cursor.prototype.resetZoom = function(plot, cursor) {
+ var axes = plot.axes;
+ var cax = cursor._zoom.axes;
+ if (!plot.plugins.cursor.zoomProxy && cursor._zoom.isZoomed) {
+ for (var ax in axes) {
+ // axes[ax]._ticks = [];
+ // axes[ax].min = cax[ax].min;
+ // axes[ax].max = cax[ax].max;
+ // axes[ax].numberTicks = cax[ax].numberTicks;
+ // axes[ax].tickInterval = cax[ax].tickInterval;
+ // // for date axes
+ // axes[ax].daTickInterval = cax[ax].daTickInterval;
+ axes[ax].reset();
+ axes[ax]._ticks = [];
+ // fake out tick creation algorithm to make sure original auto
+ // computed format string is used if _overrideFormatString is true
+ axes[ax]._autoFormatString = cax[ax].tickFormatString;
+ }
+ plot.redraw();
+ cursor._zoom.isZoomed = false;
+ }
+ else {
+ var ctx = cursor.zoomCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx = null;
+ }
+ plot.target.trigger('jqplotResetZoom', [plot, cursor]);
+ };
+
+ $.jqplot.Cursor.resetZoom = function(plot) {
+ plot.resetZoom();
+ };
+
+ $.jqplot.Cursor.prototype.doZoom = function (gridpos, datapos, plot, cursor) {
+ var c = cursor;
+ var axes = plot.axes;
+ var zaxes = c._zoom.axes;
+ var start = zaxes.start;
+ var end = zaxes.end;
+ var min, max, dp, span,
+ newmin, newmax, curax, _numberTicks, ret;
+ var ctx = plot.plugins.cursor.zoomCanvas._ctx;
+ // don't zoom if zoom area is too small (in pixels)
+ if ((c.constrainZoomTo == 'none' && Math.abs(gridpos.x - c._zoom.start[0]) > 6 && Math.abs(gridpos.y - c._zoom.start[1]) > 6) || (c.constrainZoomTo == 'x' && Math.abs(gridpos.x - c._zoom.start[0]) > 6) || (c.constrainZoomTo == 'y' && Math.abs(gridpos.y - c._zoom.start[1]) > 6)) {
+ if (!plot.plugins.cursor.zoomProxy) {
+ for (var ax in datapos) {
+ // make a copy of the original axes to revert back.
+ if (c._zoom.axes[ax] == undefined) {
+ c._zoom.axes[ax] = {};
+ c._zoom.axes[ax].numberTicks = axes[ax].numberTicks;
+ c._zoom.axes[ax].tickInterval = axes[ax].tickInterval;
+ // for date axes...
+ c._zoom.axes[ax].daTickInterval = axes[ax].daTickInterval;
+ c._zoom.axes[ax].min = axes[ax].min;
+ c._zoom.axes[ax].max = axes[ax].max;
+ c._zoom.axes[ax].tickFormatString = (axes[ax].tickOptions != null) ? axes[ax].tickOptions.formatString : '';
+ }
+
+
+ if ((c.constrainZoomTo == 'none') || (c.constrainZoomTo == 'x' && ax.charAt(0) == 'x') || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'y')) {
+ dp = datapos[ax];
+ if (dp != null) {
+ if (dp > start[ax]) {
+ newmin = start[ax];
+ newmax = dp;
+ }
+ else {
+ span = start[ax] - dp;
+ newmin = dp;
+ newmax = start[ax];
+ }
+
+ curax = axes[ax];
+
+ _numberTicks = null;
+
+ // if aligning this axis, use number of ticks from previous axis.
+ // Do I need to reset somehow if alignTicks is changed and then graph is replotted??
+ if (curax.alignTicks) {
+ if (curax.name === 'x2axis' && plot.axes.xaxis.show) {
+ _numberTicks = plot.axes.xaxis.numberTicks;
+ }
+ else if (curax.name.charAt(0) === 'y' && curax.name !== 'yaxis' && curax.name !== 'yMidAxis' && plot.axes.yaxis.show) {
+ _numberTicks = plot.axes.yaxis.numberTicks;
+ }
+ }
+
+ if (this.looseZoom && (axes[ax].renderer.constructor === $.jqplot.LinearAxisRenderer || axes[ax].renderer.constructor === $.jqplot.LogAxisRenderer )) { //} || axes[ax].renderer.constructor === $.jqplot.DateAxisRenderer)) {
+
+ ret = $.jqplot.LinearTickGenerator(newmin, newmax, curax._scalefact, _numberTicks);
+
+ // if new minimum is less than "true" minimum of axis display, adjust it
+ if (axes[ax].tickInset && ret[0] < axes[ax].min + axes[ax].tickInset * axes[ax].tickInterval) {
+ ret[0] += ret[4];
+ ret[2] -= 1;
+ }
+
+ // if new maximum is greater than "true" max of axis display, adjust it
+ if (axes[ax].tickInset && ret[1] > axes[ax].max - axes[ax].tickInset * axes[ax].tickInterval) {
+ ret[1] -= ret[4];
+ ret[2] -= 1;
+ }
+
+ // for log axes, don't fall below current minimum, this will look bad and can't have 0 in range anyway.
+ if (axes[ax].renderer.constructor === $.jqplot.LogAxisRenderer && ret[0] < axes[ax].min) {
+ // remove a tick and shift min up
+ ret[0] += ret[4];
+ ret[2] -= 1;
+ }
+
+ axes[ax].min = ret[0];
+ axes[ax].max = ret[1];
+ axes[ax]._autoFormatString = ret[3];
+ axes[ax].numberTicks = ret[2];
+ axes[ax].tickInterval = ret[4];
+ // for date axes...
+ axes[ax].daTickInterval = [ret[4]/1000, 'seconds'];
+ }
+ else {
+ axes[ax].min = newmin;
+ axes[ax].max = newmax;
+ axes[ax].tickInterval = null;
+ axes[ax].numberTicks = null;
+ // for date axes...
+ axes[ax].daTickInterval = null;
+ }
+
+ axes[ax]._ticks = [];
+ }
+ }
+
+ // if ((c.constrainZoomTo == 'x' && ax.charAt(0) == 'y' && c.autoscaleConstraint) || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'x' && c.autoscaleConstraint)) {
+ // dp = datapos[ax];
+ // if (dp != null) {
+ // axes[ax].max == null;
+ // axes[ax].min = null;
+ // }
+ // }
+ }
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ plot.redraw();
+ c._zoom.isZoomed = true;
+ ctx = null;
+ }
+ plot.target.trigger('jqplotZoom', [gridpos, datapos, plot, cursor]);
+ }
+ };
+
+ $.jqplot.preInitHooks.push($.jqplot.Cursor.init);
+ $.jqplot.postDrawHooks.push($.jqplot.Cursor.postDraw);
+
+ function updateTooltip(gridpos, datapos, plot) {
+ var c = plot.plugins.cursor;
+ var s = '';
+ var addbr = false;
+ if (c.showTooltipGridPosition) {
+ s = gridpos.x+', '+gridpos.y;
+ addbr = true;
+ }
+ if (c.showTooltipUnitPosition) {
+ var g;
+ for (var i=0; i<c.tooltipAxisGroups.length; i++) {
+ g = c.tooltipAxisGroups[i];
+ if (addbr) {
+ s += '<br />';
+ }
+ if (c.useAxesFormatters) {
+ for (var j=0; j<g.length; j++) {
+ if (j) {
+ s += ', ';
+ }
+ var af = plot.axes[g[j]]._ticks[0].formatter;
+ var afstr = plot.axes[g[j]]._ticks[0].formatString;
+ s += af(afstr, datapos[g[j]]);
+ }
+ }
+ else {
+ s += $.jqplot.sprintf(c.tooltipFormatString, datapos[g[0]], datapos[g[1]]);
+ }
+ addbr = true;
+ }
+ }
+
+ if (c.showTooltipDataPosition) {
+ var series = plot.series;
+ var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y);
+ var addbr = false;
+
+ for (var i = 0; i< series.length; i++) {
+ if (series[i].show) {
+ var idx = series[i].index;
+ var label = series[i].label.toString();
+ var cellid = $.inArray(idx, ret.indices);
+ var sx = undefined;
+ var sy = undefined;
+ if (cellid != -1) {
+ var data = ret.data[cellid].data;
+ if (c.useAxesFormatters) {
+ var xf = series[i]._xaxis._ticks[0].formatter;
+ var yf = series[i]._yaxis._ticks[0].formatter;
+ var xfstr = series[i]._xaxis._ticks[0].formatString;
+ var yfstr = series[i]._yaxis._ticks[0].formatString;
+ sx = xf(xfstr, data[0]);
+ sy = yf(yfstr, data[1]);
+ }
+ else {
+ sx = data[0];
+ sy = data[1];
+ }
+ if (addbr) {
+ s += '<br />';
+ }
+ s += $.jqplot.sprintf(c.tooltipFormatString, label, sx, sy);
+ addbr = true;
+ }
+ }
+ }
+
+ }
+ c._tooltipElem.html(s);
+ }
+
+ function moveLine(gridpos, plot) {
+ var c = plot.plugins.cursor;
+ var ctx = c.cursorCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ if (c.showVerticalLine) {
+ c.shapeRenderer.draw(ctx, [[gridpos.x, 0], [gridpos.x, ctx.canvas.height]]);
+ }
+ if (c.showHorizontalLine) {
+ c.shapeRenderer.draw(ctx, [[0, gridpos.y], [ctx.canvas.width, gridpos.y]]);
+ }
+ var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y);
+ if (c.showCursorLegend) {
+ var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label');
+ for (var i=0; i<cells.length; i++) {
+ var idx = $(cells[i]).data('seriesIndex');
+ var series = plot.series[idx];
+ var label = series.label.toString();
+ var cellid = $.inArray(idx, ret.indices);
+ var sx = undefined;
+ var sy = undefined;
+ if (cellid != -1) {
+ var data = ret.data[cellid].data;
+ if (c.useAxesFormatters) {
+ var xf = series._xaxis._ticks[0].formatter;
+ var yf = series._yaxis._ticks[0].formatter;
+ var xfstr = series._xaxis._ticks[0].formatString;
+ var yfstr = series._yaxis._ticks[0].formatString;
+ sx = xf(xfstr, data[0]);
+ sy = yf(yfstr, data[1]);
+ }
+ else {
+ sx = data[0];
+ sy = data[1];
+ }
+ }
+ if (plot.legend.escapeHtml) {
+ $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy));
+ }
+ else {
+ $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy));
+ }
+ }
+ }
+ ctx = null;
+ }
+
+ function getIntersectingPoints(plot, x, y) {
+ var ret = {indices:[], data:[]};
+ var s, i, d0, d, j, r, p;
+ var threshold;
+ var c = plot.plugins.cursor;
+ for (var i=0; i<plot.series.length; i++) {
+ s = plot.series[i];
+ r = s.renderer;
+ if (s.show) {
+ threshold = c.intersectionThreshold;
+ if (s.showMarker) {
+ threshold += s.markerRenderer.size/2;
+ }
+ for (var j=0; j<s.gridData.length; j++) {
+ p = s.gridData[j];
+ // check vertical line
+ if (c.showVerticalLine) {
+ if (Math.abs(x-p[0]) <= threshold) {
+ ret.indices.push(i);
+ ret.data.push({seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]});
+ }
+ }
+ }
+ }
+ }
+ return ret;
+ }
+
+ function moveTooltip(gridpos, plot) {
+ var c = plot.plugins.cursor;
+ var elem = c._tooltipElem;
+ switch (c.tooltipLocation) {
+ case 'nw':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'n':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
+ var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'ne':
+ var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true);
+ break;
+ case 'e':
+ var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ case 'se':
+ var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
+ break;
+ case 's':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
+ var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
+ break;
+ case 'sw':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
+ break;
+ case 'w':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ default:
+ var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset;
+ var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset;
+ break;
+ }
+
+ elem.css('left', x);
+ elem.css('top', y);
+ elem = null;
+ }
+
+ function positionTooltip(plot) {
+ // fake a grid for positioning
+ var grid = plot._gridPadding;
+ var c = plot.plugins.cursor;
+ var elem = c._tooltipElem;
+ switch (c.tooltipLocation) {
+ case 'nw':
+ var a = grid.left + c.tooltipOffset;
+ var b = grid.top + c.tooltipOffset;
+ elem.css('left', a);
+ elem.css('top', b);
+ break;
+ case 'n':
+ var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2;
+ var b = grid.top + c.tooltipOffset;
+ elem.css('left', a);
+ elem.css('top', b);
+ break;
+ case 'ne':
+ var a = grid.right + c.tooltipOffset;
+ var b = grid.top + c.tooltipOffset;
+ elem.css({right:a, top:b});
+ break;
+ case 'e':
+ var a = grid.right + c.tooltipOffset;
+ var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2;
+ elem.css({right:a, top:b});
+ break;
+ case 'se':
+ var a = grid.right + c.tooltipOffset;
+ var b = grid.bottom + c.tooltipOffset;
+ elem.css({right:a, bottom:b});
+ break;
+ case 's':
+ var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2;
+ var b = grid.bottom + c.tooltipOffset;
+ elem.css({left:a, bottom:b});
+ break;
+ case 'sw':
+ var a = grid.left + c.tooltipOffset;
+ var b = grid.bottom + c.tooltipOffset;
+ elem.css({left:a, bottom:b});
+ break;
+ case 'w':
+ var a = grid.left + c.tooltipOffset;
+ var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2;
+ elem.css({left:a, top:b});
+ break;
+ default: // same as 'se'
+ var a = grid.right - c.tooltipOffset;
+ var b = grid.bottom + c.tooltipOffset;
+ elem.css({right:a, bottom:b});
+ break;
+ }
+ elem = null;
+ }
+
+ function handleClick (ev, gridpos, datapos, neighbor, plot) {
+ ev.preventDefault();
+ ev.stopImmediatePropagation();
+ var c = plot.plugins.cursor;
+ if (c.clickReset) {
+ c.resetZoom(plot, c);
+ }
+ var sel = window.getSelection;
+ if (document.selection && document.selection.empty)
+ {
+ document.selection.empty();
+ }
+ else if (sel && !sel().isCollapsed) {
+ sel().collapse();
+ }
+ return false;
+ }
+
+ function handleDblClick (ev, gridpos, datapos, neighbor, plot) {
+ ev.preventDefault();
+ ev.stopImmediatePropagation();
+ var c = plot.plugins.cursor;
+ if (c.dblClickReset) {
+ c.resetZoom(plot, c);
+ }
+ var sel = window.getSelection;
+ if (document.selection && document.selection.empty)
+ {
+ document.selection.empty();
+ }
+ else if (sel && !sel().isCollapsed) {
+ sel().collapse();
+ }
+ return false;
+ }
+
+ function handleMouseLeave(ev, gridpos, datapos, neighbor, plot) {
+ var c = plot.plugins.cursor;
+ c.onGrid = false;
+ if (c.show) {
+ $(ev.target).css('cursor', c.previousCursor);
+ if (c.showTooltip && !(c._zoom.zooming && c.showTooltipOutsideZoom && !c.constrainOutsideZoom)) {
+ c._tooltipElem.empty();
+ c._tooltipElem.hide();
+ }
+ if (c.zoom) {
+ c._zoom.gridpos = gridpos;
+ c._zoom.datapos = datapos;
+ }
+ if (c.showVerticalLine || c.showHorizontalLine) {
+ var ctx = c.cursorCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx = null;
+ }
+ if (c.showCursorLegend) {
+ var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label');
+ for (var i=0; i<cells.length; i++) {
+ var idx = $(cells[i]).data('seriesIndex');
+ var series = plot.series[idx];
+ var label = series.label.toString();
+ if (plot.legend.escapeHtml) {
+ $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined));
+ }
+ else {
+ $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined));
+ }
+
+ }
+ }
+ }
+ }
+
+ function handleMouseEnter(ev, gridpos, datapos, neighbor, plot) {
+ var c = plot.plugins.cursor;
+ c.onGrid = true;
+ if (c.show) {
+ c.previousCursor = ev.target.style.cursor;
+ ev.target.style.cursor = c.style;
+ if (c.showTooltip) {
+ updateTooltip(gridpos, datapos, plot);
+ if (c.followMouse) {
+ moveTooltip(gridpos, plot);
+ }
+ else {
+ positionTooltip(plot);
+ }
+ c._tooltipElem.show();
+ }
+ if (c.showVerticalLine || c.showHorizontalLine) {
+ moveLine(gridpos, plot);
+ }
+ }
+
+ }
+
+ function handleMouseMove(ev, gridpos, datapos, neighbor, plot) {
+ var c = plot.plugins.cursor;
+ if (c.show) {
+ if (c.showTooltip) {
+ updateTooltip(gridpos, datapos, plot);
+ if (c.followMouse) {
+ moveTooltip(gridpos, plot);
+ }
+ }
+ if (c.showVerticalLine || c.showHorizontalLine) {
+ moveLine(gridpos, plot);
+ }
+ }
+ }
+
+ function getEventPosition(ev) {
+ var plot = ev.data.plot;
+ var go = plot.eventCanvas._elem.offset();
+ var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top};
+ //////
+ // TO DO: handle yMidAxis
+ //////
+ var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null, yMidAxis:null};
+ var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis', 'yMidAxis'];
+ var ax = plot.axes;
+ var n, axis;
+ for (n=11; n>0; n--) {
+ axis = an[n-1];
+ if (ax[axis].show) {
+ dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]);
+ }
+ }
+
+ return {offsets:go, gridPos:gridPos, dataPos:dataPos};
+ }
+
+ function handleZoomMove(ev) {
+ var plot = ev.data.plot;
+ var c = plot.plugins.cursor;
+ // don't do anything if not on grid.
+ if (c.show && c.zoom && c._zoom.started && !c.zoomTarget) {
+ ev.preventDefault();
+ var ctx = c.zoomCanvas._ctx;
+ var positions = getEventPosition(ev);
+ var gridpos = positions.gridPos;
+ var datapos = positions.dataPos;
+ c._zoom.gridpos = gridpos;
+ c._zoom.datapos = datapos;
+ c._zoom.zooming = true;
+ var xpos = gridpos.x;
+ var ypos = gridpos.y;
+ var height = ctx.canvas.height;
+ var width = ctx.canvas.width;
+ if (c.showTooltip && !c.onGrid && c.showTooltipOutsideZoom) {
+ updateTooltip(gridpos, datapos, plot);
+ if (c.followMouse) {
+ moveTooltip(gridpos, plot);
+ }
+ }
+ if (c.constrainZoomTo == 'x') {
+ c._zoom.end = [xpos, height];
+ }
+ else if (c.constrainZoomTo == 'y') {
+ c._zoom.end = [width, ypos];
+ }
+ else {
+ c._zoom.end = [xpos, ypos];
+ }
+ var sel = window.getSelection;
+ if (document.selection && document.selection.empty)
+ {
+ document.selection.empty();
+ }
+ else if (sel && !sel().isCollapsed) {
+ sel().collapse();
+ }
+ drawZoomBox.call(c);
+ ctx = null;
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ var c = plot.plugins.cursor;
+ if(plot.plugins.mobile){
+ $(document).one('vmouseup.jqplot_cursor', {plot:plot}, handleMouseUp);
+ } else {
+ $(document).one('mouseup.jqplot_cursor', {plot:plot}, handleMouseUp);
+ }
+ var axes = plot.axes;
+ if (document.onselectstart != undefined) {
+ c._oldHandlers.onselectstart = document.onselectstart;
+ document.onselectstart = function () { return false; };
+ }
+ if (document.ondrag != undefined) {
+ c._oldHandlers.ondrag = document.ondrag;
+ document.ondrag = function () { return false; };
+ }
+ if (document.onmousedown != undefined) {
+ c._oldHandlers.onmousedown = document.onmousedown;
+ document.onmousedown = function () { return false; };
+ }
+ if (c.zoom) {
+ if (!c.zoomProxy) {
+ var ctx = c.zoomCanvas._ctx;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx = null;
+ }
+ if (c.constrainZoomTo == 'x') {
+ c._zoom.start = [gridpos.x, 0];
+ }
+ else if (c.constrainZoomTo == 'y') {
+ c._zoom.start = [0, gridpos.y];
+ }
+ else {
+ c._zoom.start = [gridpos.x, gridpos.y];
+ }
+ c._zoom.started = true;
+ for (var ax in datapos) {
+ // get zoom starting position.
+ c._zoom.axes.start[ax] = datapos[ax];
+ }
+ if(plot.plugins.mobile){
+ $(document).bind('vmousemove.jqplotCursor', {plot:plot}, handleZoomMove);
+ } else {
+ $(document).bind('mousemove.jqplotCursor', {plot:plot}, handleZoomMove);
+ }
+
+ }
+ }
+
+ function handleMouseUp(ev) {
+ var plot = ev.data.plot;
+ var c = plot.plugins.cursor;
+ if (c.zoom && c._zoom.zooming && !c.zoomTarget) {
+ var xpos = c._zoom.gridpos.x;
+ var ypos = c._zoom.gridpos.y;
+ var datapos = c._zoom.datapos;
+ var height = c.zoomCanvas._ctx.canvas.height;
+ var width = c.zoomCanvas._ctx.canvas.width;
+ var axes = plot.axes;
+
+ if (c.constrainOutsideZoom && !c.onGrid) {
+ if (xpos < 0) { xpos = 0; }
+ else if (xpos > width) { xpos = width; }
+ if (ypos < 0) { ypos = 0; }
+ else if (ypos > height) { ypos = height; }
+
+ for (var axis in datapos) {
+ if (datapos[axis]) {
+ if (axis.charAt(0) == 'x') {
+ datapos[axis] = axes[axis].series_p2u(xpos);
+ }
+ else {
+ datapos[axis] = axes[axis].series_p2u(ypos);
+ }
+ }
+ }
+ }
+
+ if (c.constrainZoomTo == 'x') {
+ ypos = height;
+ }
+ else if (c.constrainZoomTo == 'y') {
+ xpos = width;
+ }
+ c._zoom.end = [xpos, ypos];
+ c._zoom.gridpos = {x:xpos, y:ypos};
+
+ c.doZoom(c._zoom.gridpos, datapos, plot, c);
+ }
+ c._zoom.started = false;
+ c._zoom.zooming = false;
+
+ $(document).unbind('mousemove.jqplotCursor', handleZoomMove);
+
+ if (document.onselectstart != undefined && c._oldHandlers.onselectstart != null){
+ document.onselectstart = c._oldHandlers.onselectstart;
+ c._oldHandlers.onselectstart = null;
+ }
+ if (document.ondrag != undefined && c._oldHandlers.ondrag != null){
+ document.ondrag = c._oldHandlers.ondrag;
+ c._oldHandlers.ondrag = null;
+ }
+ if (document.onmousedown != undefined && c._oldHandlers.onmousedown != null){
+ document.onmousedown = c._oldHandlers.onmousedown;
+ c._oldHandlers.onmousedown = null;
+ }
+
+ }
+
+ function drawZoomBox() {
+ var start = this._zoom.start;
+ var end = this._zoom.end;
+ var ctx = this.zoomCanvas._ctx;
+ var l, t, h, w;
+ if (end[0] > start[0]) {
+ l = start[0];
+ w = end[0] - start[0];
+ }
+ else {
+ l = end[0];
+ w = start[0] - end[0];
+ }
+ if (end[1] > start[1]) {
+ t = start[1];
+ h = end[1] - start[1];
+ }
+ else {
+ t = end[1];
+ h = start[1] - end[1];
+ }
+ ctx.fillStyle = 'rgba(0,0,0,0.2)';
+ ctx.strokeStyle = '#999999';
+ ctx.lineWidth = 1.0;
+ ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx.fillRect(0,0,ctx.canvas.width, ctx.canvas.height);
+ ctx.clearRect(l, t, w, h);
+ // IE won't show transparent fill rect, so stroke a rect also.
+ ctx.strokeRect(l,t,w,h);
+ ctx = null;
+ }
+
+ $.jqplot.CursorLegendRenderer = function(options) {
+ $.jqplot.TableLegendRenderer.call(this, options);
+ this.formatString = '%s';
+ };
+
+ $.jqplot.CursorLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.CursorLegendRenderer.prototype.constructor = $.jqplot.CursorLegendRenderer;
+
+ // called in context of a Legend
+ $.jqplot.CursorLegendRenderer.prototype.draw = function() {
+ if (this._elem) {
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+ if (this.show) {
+ var series = this._series, s;
+ // make a table. one line label per row.
+ var elem = document.createElement('div');
+ this._elem = $(elem);
+ elem = null;
+ this._elem.addClass('jqplot-legend jqplot-cursor-legend');
+ this._elem.css('position', 'absolute');
+
+ var pad = false;
+ for (var i = 0; i< series.length; i++) {
+ s = series[i];
+ if (s.show && s.showLabel) {
+ var lt = $.jqplot.sprintf(this.formatString, s.label.toString());
+ if (lt) {
+ var color = s.color;
+ if (s._stack && !s.fill) {
+ color = '';
+ }
+ addrow.call(this, lt, color, pad, i);
+ pad = true;
+ }
+ // let plugins add more rows to legend. Used by trend line plugin.
+ for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) {
+ var item = $.jqplot.addLegendRowHooks[j].call(this, s);
+ if (item) {
+ addrow.call(this, item.label, item.color, pad);
+ pad = true;
+ }
+ }
+ }
+ }
+ series = s = null;
+ delete series;
+ delete s;
+ }
+
+ function addrow(label, color, pad, idx) {
+ var rs = (pad) ? this.rowSpacing : '0';
+ var tr = $('<tr class="jqplot-legend jqplot-cursor-legend"></tr>').appendTo(this._elem);
+ tr.data('seriesIndex', idx);
+ $('<td class="jqplot-legend jqplot-cursor-legend-swatch" style="padding-top:'+rs+';">'+
+ '<div style="border:1px solid #cccccc;padding:0.2em;">'+
+ '<div class="jqplot-cursor-legend-swatch" style="background-color:'+color+';"></div>'+
+ '</div></td>').appendTo(tr);
+ var td = $('<td class="jqplot-legend jqplot-cursor-legend-label" style="vertical-align:middle;padding-top:'+rs+';"></td>');
+ td.appendTo(tr);
+ td.data('seriesIndex', idx);
+ if (this.escapeHtml) {
+ td.text(label);
+ }
+ else {
+ td.html(label);
+ }
+ tr = null;
+ td = null;
+ }
+ return this._elem;
+ };
+
+})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.dateAxisRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.dateAxisRenderer.js
new file mode 100644
index 00000000..ec4211d4
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.dateAxisRenderer.js
@@ -0,0 +1,737 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.DateAxisRenderer
+ * A plugin for a jqPlot to render an axis as a series of date values.
+ * This renderer has no options beyond those supplied by the <Axis> class.
+ * It supplies it's own tick formatter, so the tickOptions.formatter option
+ * should not be overridden.
+ *
+ * Thanks to Ken Synder for his enhanced Date instance methods which are
+ * included with this code <http://kendsnyder.com/sandbox/date/>.
+ *
+ * To use this renderer, include the plugin in your source
+ * > <script type="text/javascript" language="javascript" src="plugins/jqplot.dateAxisRenderer.js"></script>
+ *
+ * and supply the appropriate options to your plot
+ *
+ * > {axes:{xaxis:{renderer:$.jqplot.DateAxisRenderer}}}
+ *
+ * Dates can be passed into the axis in almost any recognizable value and
+ * will be parsed. They will be rendered on the axis in the format
+ * specified by tickOptions.formatString. e.g. tickOptions.formatString = '%Y-%m-%d'.
+ *
+ * Accecptable format codes
+ * are:
+ *
+ * > Code Result Description
+ * > == Years ==
+ * > %Y 2008 Four-digit year
+ * > %y 08 Two-digit year
+ * > == Months ==
+ * > %m 09 Two-digit month
+ * > %#m 9 One or two-digit month
+ * > %B September Full month name
+ * > %b Sep Abbreviated month name
+ * > == Days ==
+ * > %d 05 Two-digit day of month
+ * > %#d 5 One or two-digit day of month
+ * > %e 5 One or two-digit day of month
+ * > %A Sunday Full name of the day of the week
+ * > %a Sun Abbreviated name of the day of the week
+ * > %w 0 Number of the day of the week (0 = Sunday, 6 = Saturday)
+ * > %o th The ordinal suffix string following the day of the month
+ * > == Hours ==
+ * > %H 23 Hours in 24-hour format (two digits)
+ * > %#H 3 Hours in 24-hour integer format (one or two digits)
+ * > %I 11 Hours in 12-hour format (two digits)
+ * > %#I 3 Hours in 12-hour integer format (one or two digits)
+ * > %p PM AM or PM
+ * > == Minutes ==
+ * > %M 09 Minutes (two digits)
+ * > %#M 9 Minutes (one or two digits)
+ * > == Seconds ==
+ * > %S 02 Seconds (two digits)
+ * > %#S 2 Seconds (one or two digits)
+ * > %s 1206567625723 Unix timestamp (Seconds past 1970-01-01 00:00:00)
+ * > == Milliseconds ==
+ * > %N 008 Milliseconds (three digits)
+ * > %#N 8 Milliseconds (one to three digits)
+ * > == Timezone ==
+ * > %O 360 difference in minutes between local time and GMT
+ * > %Z Mountain Standard Time Name of timezone as reported by browser
+ * > %G -06:00 Hours and minutes between GMT
+ * > == Shortcuts ==
+ * > %F 2008-03-26 %Y-%m-%d
+ * > %T 05:06:30 %H:%M:%S
+ * > %X 05:06:30 %H:%M:%S
+ * > %x 03/26/08 %m/%d/%y
+ * > %D 03/26/08 %m/%d/%y
+ * > %#c Wed Mar 26 15:31:00 2008 %a %b %e %H:%M:%S %Y
+ * > %v 3-Sep-2008 %e-%b-%Y
+ * > %R 15:31 %H:%M
+ * > %r 3:31:00 PM %I:%M:%S %p
+ * > == Characters ==
+ * > %n \n Newline
+ * > %t \t Tab
+ * > %% % Percent Symbol
+ */
+ $.jqplot.DateAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ this.date = new $.jsDate();
+ };
+
+ var second = 1000;
+ var minute = 60 * second;
+ var hour = 60 * minute;
+ var day = 24 * hour;
+ var week = 7 * day;
+
+ // these are less definitive
+ var month = 30.4368499 * day;
+ var year = 365.242199 * day;
+
+ var daysInMonths = [31,28,31,30,31,30,31,30,31,30,31,30];
+ // array of consistent nice intervals. Longer intervals
+ // will depend on days in month, days in year, etc.
+ var niceFormatStrings = ['%M:%S.%#N', '%M:%S.%#N', '%M:%S.%#N', '%M:%S', '%M:%S', '%M:%S', '%M:%S', '%H:%M:%S', '%H:%M:%S', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%a %H:%M', '%a %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%v', '%v', '%v', '%v', '%v', '%v', '%v'];
+ var niceIntervals = [0.1*second, 0.2*second, 0.5*second, second, 2*second, 5*second, 10*second, 15*second, 30*second, minute, 2*minute, 5*minute, 10*minute, 15*minute, 30*minute, hour, 2*hour, 4*hour, 6*hour, 8*hour, 12*hour, day, 2*day, 3*day, 4*day, 5*day, week, 2*week];
+
+ var niceMonthlyIntervals = [];
+
+ function bestDateInterval(min, max, titarget) {
+ // iterate through niceIntervals to find one closest to titarget
+ var badness = Number.MAX_VALUE;
+ var temp, bestTi, bestfmt;
+ for (var i=0, l=niceIntervals.length; i < l; i++) {
+ temp = Math.abs(titarget - niceIntervals[i]);
+ if (temp < badness) {
+ badness = temp;
+ bestTi = niceIntervals[i];
+ bestfmt = niceFormatStrings[i];
+ }
+ }
+
+ return [bestTi, bestfmt];
+ }
+
+ $.jqplot.DateAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.DateAxisRenderer.prototype.constructor = $.jqplot.DateAxisRenderer;
+
+ $.jqplot.DateTickFormatter = function(format, val) {
+ if (!format) {
+ format = '%Y/%m/%d';
+ }
+ return $.jsDate.strftime(val, format);
+ };
+
+ $.jqplot.DateAxisRenderer.prototype.init = function(options){
+ // prop: tickRenderer
+ // A class of a rendering engine for creating the ticks labels displayed on the plot,
+ // See <$.jqplot.AxisTickRenderer>.
+ // this.tickRenderer = $.jqplot.AxisTickRenderer;
+ // this.labelRenderer = $.jqplot.AxisLabelRenderer;
+ this.tickOptions.formatter = $.jqplot.DateTickFormatter;
+ // prop: tickInset
+ // Controls the amount to inset the first and last ticks from
+ // the edges of the grid, in multiples of the tick interval.
+ // 0 is no inset, 0.5 is one half a tick interval, 1 is a full
+ // tick interval, etc.
+ this.tickInset = 0;
+ // prop: drawBaseline
+ // True to draw the axis baseline.
+ this.drawBaseline = true;
+ // prop: baselineWidth
+ // width of the baseline in pixels.
+ this.baselineWidth = null;
+ // prop: baselineColor
+ // CSS color spec for the baseline.
+ this.baselineColor = null;
+ this.daTickInterval = null;
+ this._daTickInterval = null;
+
+ $.extend(true, this, options);
+
+ var db = this._dataBounds,
+ stats,
+ sum,
+ s,
+ d,
+ pd,
+ sd,
+ intv;
+
+ // Go through all the series attached to this axis and find
+ // the min/max bounds for this axis.
+ for (var i=0; i<this._series.length; i++) {
+ stats = {intervals:[], frequencies:{}, sortedIntervals:[], min:null, max:null, mean:null};
+ sum = 0;
+ s = this._series[i];
+ d = s.data;
+ pd = s._plotData;
+ sd = s._stackData;
+ intv = 0;
+
+ for (var j=0; j<d.length; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ d[j][0] = new $.jsDate(d[j][0]).getTime();
+ pd[j][0] = new $.jsDate(d[j][0]).getTime();
+ sd[j][0] = new $.jsDate(d[j][0]).getTime();
+ if ((d[j][0] != null && d[j][0] < db.min) || db.min == null) {
+ db.min = d[j][0];
+ }
+ if ((d[j][0] != null && d[j][0] > db.max) || db.max == null) {
+ db.max = d[j][0];
+ }
+ if (j>0) {
+ intv = Math.abs(d[j][0] - d[j-1][0]);
+ stats.intervals.push(intv);
+ if (stats.frequencies.hasOwnProperty(intv)) {
+ stats.frequencies[intv] += 1;
+ }
+ else {
+ stats.frequencies[intv] = 1;
+ }
+ }
+ sum += intv;
+
+ }
+ else {
+ d[j][1] = new $.jsDate(d[j][1]).getTime();
+ pd[j][1] = new $.jsDate(d[j][1]).getTime();
+ sd[j][1] = new $.jsDate(d[j][1]).getTime();
+ if ((d[j][1] != null && d[j][1] < db.min) || db.min == null) {
+ db.min = d[j][1];
+ }
+ if ((d[j][1] != null && d[j][1] > db.max) || db.max == null) {
+ db.max = d[j][1];
+ }
+ if (j>0) {
+ intv = Math.abs(d[j][1] - d[j-1][1]);
+ stats.intervals.push(intv);
+ if (stats.frequencies.hasOwnProperty(intv)) {
+ stats.frequencies[intv] += 1;
+ }
+ else {
+ stats.frequencies[intv] = 1;
+ }
+ }
+ }
+ sum += intv;
+ }
+
+ if (s.renderer.bands) {
+ if (s.renderer.bands.hiData.length) {
+ var bd = s.renderer.bands.hiData;
+ for (var j=0, l=bd.length; j < l; j++) {
+ if (this.name === 'xaxis' || this.name === 'x2axis') {
+ bd[j][0] = new $.jsDate(bd[j][0]).getTime();
+ if ((bd[j][0] != null && bd[j][0] > db.max) || db.max == null) {
+ db.max = bd[j][0];
+ }
+ }
+ else {
+ bd[j][1] = new $.jsDate(bd[j][1]).getTime();
+ if ((bd[j][1] != null && bd[j][1] > db.max) || db.max == null) {
+ db.max = bd[j][1];
+ }
+ }
+ }
+ }
+ if (s.renderer.bands.lowData.length) {
+ var bd = s.renderer.bands.lowData;
+ for (var j=0, l=bd.length; j < l; j++) {
+ if (this.name === 'xaxis' || this.name === 'x2axis') {
+ bd[j][0] = new $.jsDate(bd[j][0]).getTime();
+ if ((bd[j][0] != null && bd[j][0] < db.min) || db.min == null) {
+ db.min = bd[j][0];
+ }
+ }
+ else {
+ bd[j][1] = new $.jsDate(bd[j][1]).getTime();
+ if ((bd[j][1] != null && bd[j][1] < db.min) || db.min == null) {
+ db.min = bd[j][1];
+ }
+ }
+ }
+ }
+ }
+
+ var tempf = 0,
+ tempn=0;
+ for (var n in stats.frequencies) {
+ stats.sortedIntervals.push({interval:n, frequency:stats.frequencies[n]});
+ }
+ stats.sortedIntervals.sort(function(a, b){
+ return b.frequency - a.frequency;
+ });
+
+ stats.min = $.jqplot.arrayMin(stats.intervals);
+ stats.max = $.jqplot.arrayMax(stats.intervals);
+ stats.mean = sum/d.length;
+ this._intervalStats.push(stats);
+ stats = sum = s = d = pd = sd = null;
+ }
+ db = null;
+
+ };
+
+ // called with scope of an axis
+ $.jqplot.DateAxisRenderer.prototype.reset = function() {
+ this.min = this._options.min;
+ this.max = this._options.max;
+ this.tickInterval = this._options.tickInterval;
+ this.numberTicks = this._options.numberTicks;
+ this._autoFormatString = '';
+ if (this._overrideFormatString && this.tickOptions && this.tickOptions.formatString) {
+ this.tickOptions.formatString = '';
+ }
+ this.daTickInterval = this._daTickInterval;
+ // this._ticks = this.__ticks;
+ };
+
+ $.jqplot.DateAxisRenderer.prototype.createTicks = function(plot) {
+ // we're are operating on an axis here
+ var ticks = this._ticks;
+ var userTicks = this.ticks;
+ var name = this.name;
+ // databounds were set on axis initialization.
+ var db = this._dataBounds;
+ var iv = this._intervalStats;
+ var dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height;
+ var interval;
+ var min, max;
+ var pos1, pos2;
+ var tt, i;
+ var threshold = 30;
+ var insetMult = 1;
+
+ var tickInterval = this.tickInterval;
+
+ // if we already have ticks, use them.
+ // ticks must be in order of increasing value.
+
+ min = ((this.min != null) ? new $.jsDate(this.min).getTime() : db.min);
+ max = ((this.max != null) ? new $.jsDate(this.max).getTime() : db.max);
+
+ // see if we're zooming. if we are, don't use the min and max we're given,
+ // but compute some nice ones. They will be reset later.
+
+ var cursor = plot.plugins.cursor;
+
+ if (cursor && cursor._zoom && cursor._zoom.zooming) {
+ this.min = null;
+ this.max = null;
+ }
+
+ var range = max - min;
+
+ if (this.tickOptions == null || !this.tickOptions.formatString) {
+ this._overrideFormatString = true;
+ }
+
+ if (userTicks.length) {
+ // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
+ for (i=0; i<userTicks.length; i++){
+ var ut = userTicks[i];
+ var t = new this.tickRenderer(this.tickOptions);
+ if (ut.constructor == Array) {
+ t.value = new $.jsDate(ut[0]).getTime();
+ t.label = ut[1];
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(t.value, this.name);
+ this._ticks.push(t);
+ }
+
+ else {
+ t.value = new $.jsDate(ut).getTime();
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(t.value, this.name);
+ this._ticks.push(t);
+ }
+ }
+ this.numberTicks = userTicks.length;
+ this.min = this._ticks[0].value;
+ this.max = this._ticks[this.numberTicks-1].value;
+ this.daTickInterval = [(this.max - this.min) / (this.numberTicks - 1)/1000, 'seconds'];
+ }
+
+ ////////
+ // We don't have any ticks yet, let's make some!
+ ////////
+
+ // special case when there is only one point, make three tick marks to center the point
+ else if (this.min == null && this.max == null && db.min == db.max)
+ {
+ var onePointOpts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null});
+ var delta = 300000;
+ this.min = db.min - delta;
+ this.max = db.max + delta;
+ this.numberTicks = 3;
+
+ for(var i=this.min;i<=this.max;i+= delta)
+ {
+ onePointOpts.value = i;
+
+ var t = new this.tickRenderer(onePointOpts);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+
+ t.showLabel = false;
+ t.showMark = false;
+
+ this._ticks.push(t);
+ }
+
+ if(this.showTicks) {
+ this._ticks[1].showLabel = true;
+ }
+ if(this.showTickMarks) {
+ this._ticks[1].showTickMarks = true;
+ }
+ }
+ // if user specified min and max are null, we set those to make best ticks.
+ else if (this.min == null && this.max == null) {
+
+ var opts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null});
+
+ // want to find a nice interval
+ var nttarget,
+ titarget;
+
+ // if no tickInterval or numberTicks options specified, make a good guess.
+ if (!this.tickInterval && !this.numberTicks) {
+ var tdim = Math.max(dim, threshold+1);
+ // how many ticks to put on the axis?
+ // date labels tend to be long. If ticks not rotated,
+ // don't use too many and have a high spacing factor.
+ // If we are rotating ticks, use a lower factor.
+ var spacingFactor = 115;
+ if (this.tickRenderer === $.jqplot.CanvasAxisTickRenderer && this.tickOptions.angle) {
+ spacingFactor = 115 - 40 * Math.abs(Math.sin(this.tickOptions.angle/180*Math.PI));
+ }
+
+ nttarget = Math.ceil((tdim-threshold)/spacingFactor + 1);
+ titarget = (max - min) / (nttarget - 1);
+ }
+
+ // If tickInterval is specified, we'll try to honor it.
+ // Not gauranteed to get this interval, but we'll get as close as
+ // we can.
+ // tickInterval will be used before numberTicks, that is if
+ // both are specified, numberTicks will be ignored.
+ else if (this.tickInterval) {
+ titarget = this.tickInterval;
+ }
+
+ // if numberTicks specified, try to honor it.
+ // Not gauranteed, but will try to get close.
+ else if (this.numberTicks) {
+ nttarget = this.numberTicks;
+ titarget = (max - min) / (nttarget - 1);
+ }
+
+ // If we can use an interval of 2 weeks or less, pick best one
+ if (titarget <= 19*day) {
+ var ret = bestDateInterval(min, max, titarget);
+ var tempti = ret[0];
+ this._autoFormatString = ret[1];
+
+ min = Math.floor(min/tempti) * tempti;
+ min = new $.jsDate(min);
+ min = min.getTime() + min.getUtcOffset();
+
+ nttarget = Math.ceil((max - min) / tempti) + 1;
+ this.min = min;
+ this.max = min + (nttarget - 1) * tempti;
+
+ // if max is less than max, add an interval
+ if (this.max < max) {
+ this.max += tempti;
+ nttarget += 1;
+ }
+ this.tickInterval = tempti;
+ this.numberTicks = nttarget;
+
+ for (var i=0; i<nttarget; i++) {
+ opts.value = this.min + i * tempti;
+ t = new this.tickRenderer(opts);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ this._ticks.push(t);
+ }
+
+ insetMult = this.tickInterval;
+ }
+
+ // should we use a monthly interval?
+ else if (titarget <= 9 * month) {
+
+ this._autoFormatString = '%v';
+
+ // how many months in an interval?
+ var intv = Math.round(titarget/month);
+ if (intv < 1) {
+ intv = 1;
+ }
+ else if (intv > 6) {
+ intv = 6;
+ }
+
+ // figure out the starting month and ending month.
+ var mstart = new $.jsDate(min).setDate(1).setHours(0,0,0,0);
+
+ // See if max ends exactly on a month
+ var tempmend = new $.jsDate(max);
+ var mend = new $.jsDate(max).setDate(1).setHours(0,0,0,0);
+
+ if (tempmend.getTime() !== mend.getTime()) {
+ mend = mend.add(1, 'month');
+ }
+
+ var nmonths = mend.diff(mstart, 'month');
+
+ nttarget = Math.ceil(nmonths/intv) + 1;
+
+ this.min = mstart.getTime();
+ this.max = mstart.clone().add((nttarget - 1) * intv, 'month').getTime();
+ this.numberTicks = nttarget;
+
+ for (var i=0; i<nttarget; i++) {
+ if (i === 0) {
+ opts.value = mstart.getTime();
+ }
+ else {
+ opts.value = mstart.add(intv, 'month').getTime();
+ }
+ t = new this.tickRenderer(opts);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ this._ticks.push(t);
+ }
+
+ insetMult = intv * month;
+ }
+
+ // use yearly intervals
+ else {
+
+ this._autoFormatString = '%v';
+
+ // how many years in an interval?
+ var intv = Math.round(titarget/year);
+ if (intv < 1) {
+ intv = 1;
+ }
+
+ // figure out the starting and ending years.
+ var mstart = new $.jsDate(min).setMonth(0, 1).setHours(0,0,0,0);
+ var mend = new $.jsDate(max).add(1, 'year').setMonth(0, 1).setHours(0,0,0,0);
+
+ var nyears = mend.diff(mstart, 'year');
+
+ nttarget = Math.ceil(nyears/intv) + 1;
+
+ this.min = mstart.getTime();
+ this.max = mstart.clone().add((nttarget - 1) * intv, 'year').getTime();
+ this.numberTicks = nttarget;
+
+ for (var i=0; i<nttarget; i++) {
+ if (i === 0) {
+ opts.value = mstart.getTime();
+ }
+ else {
+ opts.value = mstart.add(intv, 'year').getTime();
+ }
+ t = new this.tickRenderer(opts);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ this._ticks.push(t);
+ }
+
+ insetMult = intv * year;
+ }
+ }
+
+ ////////
+ // Some option(s) specified, work around that.
+ ////////
+
+ else {
+ if (name == 'xaxis' || name == 'x2axis') {
+ dim = this._plotDimensions.width;
+ }
+ else {
+ dim = this._plotDimensions.height;
+ }
+
+ // if min, max and number of ticks specified, user can't specify interval.
+ if (this.min != null && this.max != null && this.numberTicks != null) {
+ this.tickInterval = null;
+ }
+
+ // if user specified a tick interval, convert to usable.
+ if (this.tickInterval != null)
+ {
+ // if interval is a number or can be converted to one, use it.
+ // Assume it is in SECONDS!!!
+ if (Number(this.tickInterval)) {
+ this.daTickInterval = [Number(this.tickInterval), 'seconds'];
+ }
+ // else, parse out something we can build from.
+ else if (typeof this.tickInterval == "string") {
+ var parts = this.tickInterval.split(' ');
+ if (parts.length == 1) {
+ this.daTickInterval = [1, parts[0]];
+ }
+ else if (parts.length == 2) {
+ this.daTickInterval = [parts[0], parts[1]];
+ }
+ }
+ }
+
+ // if min and max are same, space them out a bit
+ if (min == max) {
+ var adj = 24*60*60*500; // 1/2 day
+ min -= adj;
+ max += adj;
+ }
+
+ range = max - min;
+
+ var optNumTicks = 2 + parseInt(Math.max(0, dim-100)/100, 10);
+
+
+ var rmin, rmax;
+
+ rmin = (this.min != null) ? new $.jsDate(this.min).getTime() : min - range/2*(this.padMin - 1);
+ rmax = (this.max != null) ? new $.jsDate(this.max).getTime() : max + range/2*(this.padMax - 1);
+ this.min = rmin;
+ this.max = rmax;
+ range = this.max - this.min;
+
+ if (this.numberTicks == null){
+ // if tickInterval is specified by user, we will ignore computed maximum.
+ // max will be equal or greater to fit even # of ticks.
+ if (this.daTickInterval != null) {
+ var nc = new $.jsDate(this.max).diff(this.min, this.daTickInterval[1], true);
+ this.numberTicks = Math.ceil(nc/this.daTickInterval[0]) +1;
+ // this.max = new $.jsDate(this.min).add(this.numberTicks-1, this.daTickInterval[1]).getTime();
+ this.max = new $.jsDate(this.min).add((this.numberTicks-1) * this.daTickInterval[0], this.daTickInterval[1]).getTime();
+ }
+ else if (dim > 200) {
+ this.numberTicks = parseInt(3+(dim-200)/100, 10);
+ }
+ else {
+ this.numberTicks = 2;
+ }
+ }
+
+ insetMult = range / (this.numberTicks-1)/1000;
+
+ if (this.daTickInterval == null) {
+ this.daTickInterval = [insetMult, 'seconds'];
+ }
+
+
+ for (var i=0; i<this.numberTicks; i++){
+ var min = new $.jsDate(this.min);
+ tt = min.add(i*this.daTickInterval[0], this.daTickInterval[1]).getTime();
+ var t = new this.tickRenderer(this.tickOptions);
+ // var t = new $.jqplot.AxisTickRenderer(this.tickOptions);
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+ }
+ }
+
+ if (this.tickInset) {
+ this.min = this.min - this.tickInset * insetMult;
+ this.max = this.max + this.tickInset * insetMult;
+ }
+
+ if (this._daTickInterval == null) {
+ this._daTickInterval = this.daTickInterval;
+ }
+
+ ticks = null;
+ };
+
+})(jQuery);
+
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.donutRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.donutRenderer.js
new file mode 100644
index 00000000..621b92ec
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.donutRenderer.js
@@ -0,0 +1,805 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.DonutRenderer
+ * Plugin renderer to draw a donut chart.
+ * x values, if present, will be used as slice labels.
+ * y values give slice size.
+ *
+ * To use this renderer, you need to include the
+ * donut renderer plugin, for example:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.donutRenderer.js"></script>
+ *
+ * Properties described here are passed into the $.jqplot function
+ * as options on the series renderer. For example:
+ *
+ * > plot2 = $.jqplot('chart2', [s1, s2], {
+ * > seriesDefaults: {
+ * > renderer:$.jqplot.DonutRenderer,
+ * > rendererOptions:{
+ * > sliceMargin: 2,
+ * > innerDiameter: 110,
+ * > startAngle: -90
+ * > }
+ * > }
+ * > });
+ *
+ * A donut plot will trigger events on the plot target
+ * according to user interaction. All events return the event object,
+ * the series index, the point (slice) index, and the point data for
+ * the appropriate slice.
+ *
+ * 'jqplotDataMouseOver' - triggered when user mouseing over a slice.
+ * 'jqplotDataHighlight' - triggered the first time user mouses over a slice,
+ * if highlighting is enabled.
+ * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
+ * a highlighted slice.
+ * 'jqplotDataClick' - triggered when the user clicks on a slice.
+ * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if
+ * the "captureRightClick" option is set to true on the plot.
+ */
+ $.jqplot.DonutRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.DonutRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.DonutRenderer.prototype.constructor = $.jqplot.DonutRenderer;
+
+ // called with scope of a series
+ $.jqplot.DonutRenderer.prototype.init = function(options, plot) {
+ // Group: Properties
+ //
+ // prop: diameter
+ // Outer diameter of the donut, auto computed by default
+ this.diameter = null;
+ // prop: innerDiameter
+ // Inner diameter of the donut, auto calculated by default.
+ // If specified will override thickness value.
+ this.innerDiameter = null;
+ // prop: thickness
+ // thickness of the donut, auto computed by default
+ // Overridden by if innerDiameter is specified.
+ this.thickness = null;
+ // prop: padding
+ // padding between the donut and plot edges, legend, etc.
+ this.padding = 20;
+ // prop: sliceMargin
+ // angular spacing between donut slices in degrees.
+ this.sliceMargin = 0;
+ // prop: ringMargin
+ // pixel distance between rings, or multiple series in a donut plot.
+ // null will compute ringMargin based on sliceMargin.
+ this.ringMargin = null;
+ // prop: fill
+ // true or false, wether to fil the slices.
+ this.fill = true;
+ // prop: shadowOffset
+ // offset of the shadow from the slice and offset of
+ // each succesive stroke of the shadow from the last.
+ this.shadowOffset = 2;
+ // prop: shadowAlpha
+ // transparency of the shadow (0 = transparent, 1 = opaque)
+ this.shadowAlpha = 0.07;
+ // prop: shadowDepth
+ // number of strokes to apply to the shadow,
+ // each stroke offset shadowOffset from the last.
+ this.shadowDepth = 5;
+ // prop: highlightMouseOver
+ // True to highlight slice when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over a slice.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColors
+ // an array of colors to use when highlighting a slice.
+ this.highlightColors = [];
+ // prop: dataLabels
+ // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
+ // Defaults to percentage of each pie slice.
+ this.dataLabels = 'percent';
+ // prop: showDataLabels
+ // true to show data labels on slices.
+ this.showDataLabels = false;
+ // prop: dataLabelFormatString
+ // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
+ this.dataLabelFormatString = null;
+ // prop: dataLabelThreshold
+ // Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed.
+ // This applies to all label types, not just to percentage labels.
+ this.dataLabelThreshold = 3;
+ // prop: dataLabelPositionFactor
+ // A Multiplier (0-1) of the pie radius which controls position of label on slice.
+ // Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie.
+ this.dataLabelPositionFactor = 0.4;
+ // prop: dataLabelNudge
+ // Number of pixels to slide the label away from (+) or toward (-) the center of the pie.
+ this.dataLabelNudge = 0;
+ // prop: startAngle
+ // Angle to start drawing donut in degrees.
+ // According to orientation of canvas coordinate system:
+ // 0 = on the positive x axis
+ // -90 = on the positive y axis.
+ // 90 = on the negaive y axis.
+ // 180 or - 180 = on the negative x axis.
+ this.startAngle = 0;
+ this.tickRenderer = $.jqplot.DonutTickRenderer;
+ // Used as check for conditions where donut shouldn't be drawn.
+ this._drawData = true;
+ this._type = 'donut';
+
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
+ options.highlightMouseOver = false;
+ }
+
+ $.extend(true, this, options);
+ if (this.diameter != null) {
+ this.diameter = this.diameter - this.sliceMargin;
+ }
+ this._diameter = null;
+ this._innerDiameter = null;
+ this._radius = null;
+ this._innerRadius = null;
+ this._thickness = null;
+ // references to the previous series in the plot to properly calculate diameters
+ // and thicknesses of nested rings.
+ this._previousSeries = [];
+ this._numberSeries = 1;
+ // array of [start,end] angles arrays, one for each slice. In radians.
+ this._sliceAngles = [];
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+
+ // set highlight colors if none provided
+ if (this.highlightColors.length == 0) {
+ for (var i=0; i<this.seriesColors.length; i++){
+ var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
+ newrgb[j] = parseInt(newrgb[j], 10);
+ }
+ this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
+ }
+ }
+
+ plot.postParseOptionsHooks.addOnce(postParseOptions);
+ plot.postInitHooks.addOnce(postInit);
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
+ plot.postDrawHooks.addOnce(postPlotDraw);
+
+
+ };
+
+ $.jqplot.DonutRenderer.prototype.setGridData = function(plot) {
+ // set gridData property. This will hold angle in radians of each data point.
+ var stack = [];
+ var td = [];
+ var sa = this.startAngle/180*Math.PI;
+ var tot = 0;
+ // don't know if we have any valid data yet, so set plot to not draw.
+ this._drawData = false;
+ for (var i=0; i<this.data.length; i++){
+ if (this.data[i][1] != 0) {
+ // we have data, O.K. to draw.
+ this._drawData = true;
+ }
+ stack.push(this.data[i][1]);
+ td.push([this.data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ tot += this.data[i][1];
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ td[i][2] = this.data[i][1]/tot;
+ }
+ this.gridData = td;
+ };
+
+ $.jqplot.DonutRenderer.prototype.makeGridData = function(data, plot) {
+ var stack = [];
+ var td = [];
+ var tot = 0;
+ var sa = this.startAngle/180*Math.PI;
+ // don't know if we have any valid data yet, so set plot to not draw.
+ this._drawData = false;
+ for (var i=0; i<data.length; i++){
+ if (this.data[i][1] != 0) {
+ // we have data, O.K. to draw.
+ this._drawData = true;
+ }
+ stack.push(data[i][1]);
+ td.push([data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ tot += data[i][1];
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ td[i][2] = data[i][1]/tot;
+ }
+ return td;
+ };
+
+ $.jqplot.DonutRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) {
+ var r = this._diameter / 2;
+ var ri = r - this._thickness;
+ var fill = this.fill;
+ // var lineWidth = this.lineWidth;
+ ctx.save();
+ ctx.translate(this._center[0], this._center[1]);
+ // ctx.translate(this.sliceMargin*Math.cos((ang1+ang2)/2), this.sliceMargin*Math.sin((ang1+ang2)/2));
+
+ if (isShadow) {
+ for (var i=0; i<this.shadowDepth; i++) {
+ ctx.save();
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
+ doDraw();
+ }
+ }
+
+ else {
+ doDraw();
+ }
+
+ function doDraw () {
+ // Fix for IE and Chrome that can't seem to draw circles correctly.
+ // ang2 should always be <= 2 pi since that is the way the data is converted.
+ if (ang2 > 6.282 + this.startAngle) {
+ ang2 = 6.282 + this.startAngle;
+ if (ang1 > ang2) {
+ ang1 = 6.281 + this.startAngle;
+ }
+ }
+ // Fix for IE, where it can't seem to handle 0 degree angles. Also avoids
+ // ugly line on unfilled donuts.
+ if (ang1 >= ang2) {
+ return;
+ }
+ ctx.beginPath();
+ ctx.fillStyle = color;
+ ctx.strokeStyle = color;
+ // ctx.lineWidth = lineWidth;
+ ctx.arc(0, 0, r, ang1, ang2, false);
+ ctx.lineTo(ri*Math.cos(ang2), ri*Math.sin(ang2));
+ ctx.arc(0,0, ri, ang2, ang1, true);
+ ctx.closePath();
+ if (fill) {
+ ctx.fill();
+ }
+ else {
+ ctx.stroke();
+ }
+ }
+
+ if (isShadow) {
+ for (var i=0; i<this.shadowDepth; i++) {
+ ctx.restore();
+ }
+ }
+
+ ctx.restore();
+ };
+
+ // called with scope of series
+ $.jqplot.DonutRenderer.prototype.draw = function (ctx, gd, options, plot) {
+ var i;
+ var opts = (options != undefined) ? options : {};
+ // offset and direction of offset due to legend placement
+ var offx = 0;
+ var offy = 0;
+ var trans = 1;
+ // var colorGenerator = new this.colorGenerator(this.seriesColors);
+ if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
+ var li = options.legendInfo;
+ switch (li.location) {
+ case 'nw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'w':
+ offx = li.width + li.xoffset;
+ break;
+ case 'sw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'ne':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'e':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'se':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'n':
+ offy = li.height + li.yoffset;
+ break;
+ case 's':
+ offy = li.height + li.yoffset;
+ trans = -1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var cw = ctx.canvas.width;
+ var ch = ctx.canvas.height;
+ var w = cw - offx - 2 * this.padding;
+ var h = ch - offy - 2 * this.padding;
+ var mindim = Math.min(w,h);
+ var d = mindim;
+ var ringmargin = (this.ringMargin == null) ? this.sliceMargin * 2.0 : this.ringMargin;
+
+ for (var i=0; i<this._previousSeries.length; i++) {
+ d -= 2.0 * this._previousSeries[i]._thickness + 2.0 * ringmargin;
+ }
+ this._diameter = this.diameter || d;
+ if (this.innerDiameter != null) {
+ var od = (this._numberSeries > 1 && this.index > 0) ? this._previousSeries[0]._diameter : this._diameter;
+ this._thickness = this.thickness || (od - this.innerDiameter - 2.0*ringmargin*this._numberSeries) / this._numberSeries/2.0;
+ }
+ else {
+ this._thickness = this.thickness || mindim / 2 / (this._numberSeries + 1) * 0.85;
+ }
+
+ var r = this._radius = this._diameter/2;
+ this._innerRadius = this._radius - this._thickness;
+ var sa = this.startAngle / 180 * Math.PI;
+ this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy];
+
+ if (this.shadow) {
+ var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
+ for (var i=0; i<gd.length; i++) {
+ var ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
+ // Adjust ang1 and ang2 for sliceMargin
+ ang1 += this.sliceMargin/180*Math.PI;
+ this.renderer.drawSlice.call (this, ctx, ang1, gd[i][1]+sa, shadowColor, true);
+ }
+
+ }
+ for (var i=0; i<gd.length; i++) {
+ var ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
+ // Adjust ang1 and ang2 for sliceMargin
+ ang1 += this.sliceMargin/180*Math.PI;
+ var ang2 = gd[i][1] + sa;
+ this._sliceAngles.push([ang1, ang2]);
+ this.renderer.drawSlice.call (this, ctx, ang1, ang2, this.seriesColors[i], false);
+
+ if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) {
+ var fstr, avgang = (ang1+ang2)/2, label;
+
+ if (this.dataLabels == 'label') {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, gd[i][0]);
+ }
+ else if (this.dataLabels == 'value') {
+ fstr = this.dataLabelFormatString || '%d';
+ label = $.jqplot.sprintf(fstr, this.data[i][1]);
+ }
+ else if (this.dataLabels == 'percent') {
+ fstr = this.dataLabelFormatString || '%d%%';
+ label = $.jqplot.sprintf(fstr, gd[i][2]*100);
+ }
+ else if (this.dataLabels.constructor == Array) {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, this.dataLabels[i]);
+ }
+
+ var fact = this._innerRadius + this._thickness * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
+
+ var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left;
+ var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top;
+
+ var labelelem = $('<span class="jqplot-donut-series jqplot-data-label" style="position:absolute;">' + label + '</span>').insertBefore(plot.eventCanvas._elem);
+ x -= labelelem.width()/2;
+ y -= labelelem.height()/2;
+ x = Math.round(x);
+ y = Math.round(y);
+ labelelem.css({left: x, top: y});
+ }
+ }
+
+ };
+
+ $.jqplot.DonutAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.DonutAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.DonutAxisRenderer.prototype.constructor = $.jqplot.DonutAxisRenderer;
+
+
+ // There are no traditional axes on a donut chart. We just need to provide
+ // dummy objects with properties so the plot will render.
+ // called with scope of axis object.
+ $.jqplot.DonutAxisRenderer.prototype.init = function(options){
+ //
+ this.tickRenderer = $.jqplot.DonutTickRenderer;
+ $.extend(true, this, options);
+ // I don't think I'm going to need _dataBounds here.
+ // have to go Axis scaling in a way to fit chart onto plot area
+ // and provide u2p and p2u functionality for mouse cursor, etc.
+ // for convienence set _dataBounds to 0 and 100 and
+ // set min/max to 0 and 100.
+ this._dataBounds = {min:0, max:100};
+ this.min = 0;
+ this.max = 100;
+ this.showTicks = false;
+ this.ticks = [];
+ this.showMark = false;
+ this.show = false;
+ };
+
+
+
+
+ $.jqplot.DonutLegendRenderer = function(){
+ $.jqplot.TableLegendRenderer.call(this);
+ };
+
+ $.jqplot.DonutLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.DonutLegendRenderer.prototype.constructor = $.jqplot.DonutLegendRenderer;
+
+ /**
+ * Class: $.jqplot.DonutLegendRenderer
+ * Legend Renderer specific to donut plots. Set by default
+ * when user creates a donut plot.
+ */
+ $.jqplot.DonutLegendRenderer.prototype.init = function(options) {
+ // Group: Properties
+ //
+ // prop: numberRows
+ // Maximum number of rows in the legend. 0 or null for unlimited.
+ this.numberRows = null;
+ // prop: numberColumns
+ // Maximum number of columns in the legend. 0 or null for unlimited.
+ this.numberColumns = null;
+ $.extend(true, this, options);
+ };
+
+ // called with context of legend
+ $.jqplot.DonutLegendRenderer.prototype.draw = function() {
+ var legend = this;
+ if (this.show) {
+ var series = this._series;
+ var ss = 'position:absolute;';
+ ss += (this.background) ? 'background:'+this.background+';' : '';
+ ss += (this.border) ? 'border:'+this.border+';' : '';
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
+ ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
+ ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
+ ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
+ ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
+ // Donut charts legends don't go by number of series, but by number of data points
+ // in the series. Refactor things here for that.
+
+ var pad = false,
+ reverse = false,
+ nr, nc;
+ var s = series[0];
+ var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
+
+ if (s.show) {
+ var pd = s.data;
+ if (this.numberRows) {
+ nr = this.numberRows;
+ if (!this.numberColumns){
+ nc = Math.ceil(pd.length/nr);
+ }
+ else{
+ nc = this.numberColumns;
+ }
+ }
+ else if (this.numberColumns) {
+ nc = this.numberColumns;
+ nr = Math.ceil(pd.length/this.numberColumns);
+ }
+ else {
+ nr = pd.length;
+ nc = 1;
+ }
+
+ var i, j, tr, td1, td2, lt, rs, color;
+ var idx = 0;
+
+ for (i=0; i<nr; i++) {
+ if (reverse){
+ tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
+ }
+ else{
+ tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
+ }
+ for (j=0; j<nc; j++) {
+ if (idx < pd.length){
+ lt = this.labels[idx] || pd[idx][0].toString();
+ color = colorGenerator.next();
+ if (!reverse){
+ if (i>0){
+ pad = true;
+ }
+ else{
+ pad = false;
+ }
+ }
+ else{
+ if (i == nr -1){
+ pad = false;
+ }
+ else{
+ pad = true;
+ }
+ }
+ rs = (pad) ? this.rowSpacing : '0';
+
+ td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
+ '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
+ '</div></td>');
+ td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
+ if (this.escapeHtml){
+ td2.text(lt);
+ }
+ else {
+ td2.html(lt);
+ }
+ if (reverse) {
+ td2.prependTo(tr);
+ td1.prependTo(tr);
+ }
+ else {
+ td1.appendTo(tr);
+ td2.appendTo(tr);
+ }
+ pad = true;
+ }
+ idx++;
+ }
+ }
+ }
+ }
+ return this._elem;
+ };
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.legend = options.legend || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ // only set these if there is a donut series
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.DonutRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.DonutRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.DonutAxisRenderer;
+ options.legend.renderer = $.jqplot.DonutLegendRenderer;
+ options.legend.preDraw = true;
+ options.seriesDefaults.pointLabels = {show: false};
+ }
+ }
+
+ // called with scope of plot.
+ function postInit(target, data, options) {
+ // if multiple series, add a reference to the previous one so that
+ // donut rings can nest.
+ for (var i=1; i<this.series.length; i++) {
+ if (!this.series[i]._previousSeries.length){
+ for (var j=0; j<i; j++) {
+ if (this.series[i].renderer.constructor == $.jqplot.DonutRenderer && this.series[j].renderer.constructor == $.jqplot.DonutRenderer) {
+ this.series[i]._previousSeries.push(this.series[j]);
+ }
+ }
+ }
+ }
+ for (i=0; i<this.series.length; i++) {
+ if (this.series[i].renderer.constructor == $.jqplot.DonutRenderer) {
+ this.series[i]._numberSeries = this.series.length;
+ // don't allow mouseover and mousedown at same time.
+ if (this.series[i].highlightMouseOver) {
+ this.series[i].highlightMouseDown = false;
+ }
+ }
+ }
+ }
+
+ var postParseOptionsRun = false;
+ // called with scope of plot
+ function postParseOptions(options) {
+ for (var i=0; i<this.series.length; i++) {
+ this.series[i].seriesColors = this.seriesColors;
+ this.series[i].colorGenerator = $.jqplot.colorGenerator;
+ }
+ }
+
+ function highlight (plot, sidx, pidx) {
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.donutRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.donutRenderer.highlightedSeriesIndex = sidx;
+ s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColors[pidx], false);
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.donutRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.donutRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ }
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.donutRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.donutRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
+ var idx = plot.plugins.donutRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ }
+
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt = jQuery.Event('jqplotDataClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var idx = plot.plugins.donutRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ var evt = jQuery.Event('jqplotDataRightClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.donutRenderer && this.plugins.donutRenderer.highlightCanvas) {
+ this.plugins.donutRenderer.highlightCanvas.resetCanvas();
+ this.plugins.donutRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.donutRenderer = {highlightedSeriesIndex:null};
+ this.plugins.donutRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+ // do we have any data labels? if so, put highlight canvas before those
+ // Fix for broken jquery :first selector with canvas (VML) elements.
+ var labels = $(this.targetId+' .jqplot-data-label');
+ if (labels.length) {
+ $(labels[0]).before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-donutRenderer-highlight-canvas', this._plotDimensions, this));
+ }
+ // else put highlight canvas before event canvas.
+ else {
+ this.eventCanvas._elem.before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-donutRenderer-highlight-canvas', this._plotDimensions, this));
+ }
+ var hctx = this.plugins.donutRenderer.highlightCanvas.setContext();
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+
+ $.jqplot.DonutTickRenderer = function() {
+ $.jqplot.AxisTickRenderer.call(this);
+ };
+
+ $.jqplot.DonutTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
+ $.jqplot.DonutTickRenderer.prototype.constructor = $.jqplot.DonutTickRenderer;
+
+})(jQuery);
+
+ \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.dragable.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.dragable.js
new file mode 100644
index 00000000..00419518
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.dragable.js
@@ -0,0 +1,225 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+
+ /**
+ * Class: $.jqplot.Dragable
+ * Plugin to make plotted points dragable by the user.
+ */
+ $.jqplot.Dragable = function(options) {
+ // Group: Properties
+ this.markerRenderer = new $.jqplot.MarkerRenderer({shadow:false});
+ this.shapeRenderer = new $.jqplot.ShapeRenderer();
+ this.isDragging = false;
+ this.isOver = false;
+ this._ctx;
+ this._elem;
+ this._point;
+ this._gridData;
+ // prop: color
+ // CSS color spec for the dragged point (and adjacent line segment or bar).
+ this.color;
+ // prop: constrainTo
+ // Constrain dragging motion to an axis or to none.
+ // Allowable values are 'none', 'x', 'y'
+ this.constrainTo = 'none'; // 'x', 'y', or 'none';
+ $.extend(true, this, options);
+ };
+
+ function DragCanvas() {
+ $.jqplot.GenericCanvas.call(this);
+ this.isDragging = false;
+ this.isOver = false;
+ this._neighbor;
+ this._cursors = [];
+ }
+
+ DragCanvas.prototype = new $.jqplot.GenericCanvas();
+ DragCanvas.prototype.constructor = DragCanvas;
+
+
+ // called within scope of series
+ $.jqplot.Dragable.parseOptions = function (defaults, opts) {
+ var options = opts || {};
+ this.plugins.dragable = new $.jqplot.Dragable(options.dragable);
+ // since this function is called before series options are parsed,
+ // we can set this here and it will be overridden if needed.
+ this.isDragable = $.jqplot.config.enablePlugins;
+ };
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ // add a new DragCanvas object to the plot plugins to handle drawing on this new canvas.
+ $.jqplot.Dragable.postPlotDraw = function() {
+ // Memory Leaks patch
+ if (this.plugins.dragable && this.plugins.dragable.highlightCanvas) {
+ this.plugins.dragable.highlightCanvas.resetCanvas();
+ this.plugins.dragable.highlightCanvas = null;
+ }
+
+ this.plugins.dragable = {previousCursor:'auto', isOver:false};
+ this.plugins.dragable.dragCanvas = new DragCanvas();
+
+ this.eventCanvas._elem.before(this.plugins.dragable.dragCanvas.createElement(this._gridPadding, 'jqplot-dragable-canvas', this._plotDimensions, this));
+ var dctx = this.plugins.dragable.dragCanvas.setContext();
+ };
+
+ //$.jqplot.preInitHooks.push($.jqplot.Dragable.init);
+ $.jqplot.preParseSeriesOptionsHooks.push($.jqplot.Dragable.parseOptions);
+ $.jqplot.postDrawHooks.push($.jqplot.Dragable.postPlotDraw);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseDown', handleDown]);
+ $.jqplot.eventListenerHooks.push(['jqplotMouseUp', handleUp]);
+
+
+ function initDragPoint(plot, neighbor) {
+ var s = plot.series[neighbor.seriesIndex];
+ var drag = s.plugins.dragable;
+
+ // first, init the mark renderer for the dragged point
+ var smr = s.markerRenderer;
+ var mr = drag.markerRenderer;
+ mr.style = smr.style;
+ mr.lineWidth = smr.lineWidth + 2.5;
+ mr.size = smr.size + 5;
+ if (!drag.color) {
+ var rgba = $.jqplot.getColorComponents(smr.color);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var alpha = (rgba[3] >= 0.6) ? rgba[3]*0.6 : rgba[3]*(2-rgba[3]);
+ drag.color = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+alpha+')';
+ }
+ mr.color = drag.color;
+ mr.init();
+
+ var start = (neighbor.pointIndex > 0) ? neighbor.pointIndex - 1 : 0;
+ var end = neighbor.pointIndex+2;
+ drag._gridData = s.gridData.slice(start, end);
+ }
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (plot.plugins.dragable.dragCanvas.isDragging) {
+ var dc = plot.plugins.dragable.dragCanvas;
+ var dp = dc._neighbor;
+ var s = plot.series[dp.seriesIndex];
+ var drag = s.plugins.dragable;
+ var gd = s.gridData;
+
+ // compute the new grid position with any constraints.
+ var x = (drag.constrainTo == 'y') ? dp.gridData[0] : gridpos.x;
+ var y = (drag.constrainTo == 'x') ? dp.gridData[1] : gridpos.y;
+
+ // compute data values for any listeners.
+ var xu = s._xaxis.series_p2u(x);
+ var yu = s._yaxis.series_p2u(y);
+
+ // clear the canvas then redraw effect at new position.
+ var ctx = dc._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+
+ // adjust our gridData for the new mouse position
+ if (dp.pointIndex > 0) {
+ drag._gridData[1] = [x, y];
+ }
+ else {
+ drag._gridData[0] = [x, y];
+ }
+ plot.series[dp.seriesIndex].draw(dc._ctx, {gridData:drag._gridData, shadow:false, preventJqPlotSeriesDrawTrigger:true, color:drag.color, markerOptions:{color:drag.color, shadow:false}, trendline:{show:false}});
+ plot.target.trigger('jqplotSeriesPointChange', [dp.seriesIndex, dp.pointIndex, [xu,yu], [x,y]]);
+ }
+ else if (neighbor != null) {
+ var series = plot.series[neighbor.seriesIndex];
+ if (series.isDragable) {
+ var dc = plot.plugins.dragable.dragCanvas;
+ if (!dc.isOver) {
+ dc._cursors.push(ev.target.style.cursor);
+ ev.target.style.cursor = "pointer";
+ }
+ dc.isOver = true;
+ }
+ }
+ else if (neighbor == null) {
+ var dc = plot.plugins.dragable.dragCanvas;
+ if (dc.isOver) {
+ ev.target.style.cursor = dc._cursors.pop();
+ dc.isOver = false;
+ }
+ }
+ }
+
+ function handleDown(ev, gridpos, datapos, neighbor, plot) {
+ var dc = plot.plugins.dragable.dragCanvas;
+ dc._cursors.push(ev.target.style.cursor);
+ if (neighbor != null) {
+ var s = plot.series[neighbor.seriesIndex];
+ var drag = s.plugins.dragable;
+ if (s.isDragable && !dc.isDragging) {
+ dc._neighbor = neighbor;
+ dc.isDragging = true;
+ initDragPoint(plot, neighbor);
+ drag.markerRenderer.draw(s.gridData[neighbor.pointIndex][0], s.gridData[neighbor.pointIndex][1], dc._ctx);
+ ev.target.style.cursor = "move";
+ plot.target.trigger('jqplotDragStart', [neighbor.seriesIndex, neighbor.pointIndex, gridpos, datapos]);
+ }
+ }
+ // Just in case of a hickup, we'll clear the drag canvas and reset.
+ else {
+ var ctx = dc._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ dc.isDragging = false;
+ }
+ }
+
+ function handleUp(ev, gridpos, datapos, neighbor, plot) {
+ if (plot.plugins.dragable.dragCanvas.isDragging) {
+ var dc = plot.plugins.dragable.dragCanvas;
+ // clear the canvas
+ var ctx = dc._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ dc.isDragging = false;
+ // redraw the series canvas at the new point.
+ var dp = dc._neighbor;
+ var s = plot.series[dp.seriesIndex];
+ var drag = s.plugins.dragable;
+ // compute the new grid position with any constraints.
+ var x = (drag.constrainTo == 'y') ? dp.data[0] : datapos[s.xaxis];
+ var y = (drag.constrainTo == 'x') ? dp.data[1] : datapos[s.yaxis];
+ // var x = datapos[s.xaxis];
+ // var y = datapos[s.yaxis];
+ s.data[dp.pointIndex][0] = x;
+ s.data[dp.pointIndex][1] = y;
+ plot.drawSeries({preventJqPlotSeriesDrawTrigger:true}, dp.seriesIndex);
+ dc._neighbor = null;
+ ev.target.style.cursor = dc._cursors.pop();
+ plot.target.trigger('jqplotDragStop', [gridpos, datapos]);
+ }
+ }
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.enhancedLegendRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.enhancedLegendRenderer.js
new file mode 100644
index 00000000..effa111a
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.enhancedLegendRenderer.js
@@ -0,0 +1,305 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ // class $.jqplot.EnhancedLegendRenderer
+ // Legend renderer which can specify the number of rows and/or columns in the legend.
+ $.jqplot.EnhancedLegendRenderer = function(){
+ $.jqplot.TableLegendRenderer.call(this);
+ };
+
+ $.jqplot.EnhancedLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.EnhancedLegendRenderer.prototype.constructor = $.jqplot.EnhancedLegendRenderer;
+
+ // called with scope of legend.
+ $.jqplot.EnhancedLegendRenderer.prototype.init = function(options) {
+ // prop: numberRows
+ // Maximum number of rows in the legend. 0 or null for unlimited.
+ this.numberRows = null;
+ // prop: numberColumns
+ // Maximum number of columns in the legend. 0 or null for unlimited.
+ this.numberColumns = null;
+ // prop: seriesToggle
+ // false to not enable series on/off toggling on the legend.
+ // true or a fadein/fadeout speed (number of milliseconds or 'fast', 'normal', 'slow')
+ // to enable show/hide of series on click of legend item.
+ this.seriesToggle = 'normal';
+ // prop: seriesToggleReplot
+ // True to replot the chart after toggling series on/off.
+ // This will set the series show property to false.
+ // This allows for rescaling or other maniplation of chart.
+ // Set to an options object (e.g. {resetAxes: true}) for replot options.
+ this.seriesToggleReplot = false;
+ // prop: disableIEFading
+ // true to toggle series with a show/hide method only and not allow fading in/out.
+ // This is to overcome poor performance of fade in some versions of IE.
+ this.disableIEFading = true;
+ $.extend(true, this, options);
+
+ if (this.seriesToggle) {
+ $.jqplot.postDrawHooks.push(postDraw);
+ }
+ };
+
+ // called with scope of legend
+ $.jqplot.EnhancedLegendRenderer.prototype.draw = function(offsets, plot) {
+ var legend = this;
+ if (this.show) {
+ var series = this._series;
+ var s;
+ var ss = 'position:absolute;';
+ ss += (this.background) ? 'background:'+this.background+';' : '';
+ ss += (this.border) ? 'border:'+this.border+';' : '';
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
+ ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
+ ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
+ ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
+ ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
+ if (this.seriesToggle) {
+ this._elem.css('z-index', '3');
+ }
+
+ var pad = false,
+ reverse = false,
+ nr, nc;
+ if (this.numberRows) {
+ nr = this.numberRows;
+ if (!this.numberColumns){
+ nc = Math.ceil(series.length/nr);
+ }
+ else{
+ nc = this.numberColumns;
+ }
+ }
+ else if (this.numberColumns) {
+ nc = this.numberColumns;
+ nr = Math.ceil(series.length/this.numberColumns);
+ }
+ else {
+ nr = series.length;
+ nc = 1;
+ }
+
+ var i, j, tr, td1, td2, lt, rs, div, div0, div1;
+ var idx = 0;
+ // check to see if we need to reverse
+ for (i=series.length-1; i>=0; i--) {
+ if (nc == 1 && series[i]._stack || series[i].renderer.constructor == $.jqplot.BezierCurveRenderer){
+ reverse = true;
+ }
+ }
+
+ for (i=0; i<nr; i++) {
+ tr = $(document.createElement('tr'));
+ tr.addClass('jqplot-table-legend');
+ if (reverse){
+ tr.prependTo(this._elem);
+ }
+ else{
+ tr.appendTo(this._elem);
+ }
+ for (j=0; j<nc; j++) {
+ if (idx < series.length && (series[idx].show || series[idx].showLabel)){
+ s = series[idx];
+ lt = this.labels[idx] || s.label.toString();
+ if (lt) {
+ var color = s.color;
+ if (!reverse){
+ if (i>0){
+ pad = true;
+ }
+ else{
+ pad = false;
+ }
+ }
+ else{
+ if (i == nr -1){
+ pad = false;
+ }
+ else{
+ pad = true;
+ }
+ }
+ rs = (pad) ? this.rowSpacing : '0';
+
+ td1 = $(document.createElement('td'));
+ td1.addClass('jqplot-table-legend jqplot-table-legend-swatch');
+ td1.css({textAlign: 'center', paddingTop: rs});
+
+ div0 = $(document.createElement('div'));
+ div0.addClass('jqplot-table-legend-swatch-outline');
+ div1 = $(document.createElement('div'));
+ div1.addClass('jqplot-table-legend-swatch');
+ div1.css({backgroundColor: color, borderColor: color});
+
+ td1.append(div0.append(div1));
+
+ td2 = $(document.createElement('td'));
+ td2.addClass('jqplot-table-legend jqplot-table-legend-label');
+ td2.css('paddingTop', rs);
+
+ // td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
+ // '<div><div class="jqplot-table-legend-swatch" style="background-color:'+color+';border-color:'+color+';"></div>'+
+ // '</div></td>');
+ // td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
+ if (this.escapeHtml){
+ td2.text(lt);
+ }
+ else {
+ td2.html(lt);
+ }
+ if (reverse) {
+ if (this.showLabels) {td2.prependTo(tr);}
+ if (this.showSwatches) {td1.prependTo(tr);}
+ }
+ else {
+ if (this.showSwatches) {td1.appendTo(tr);}
+ if (this.showLabels) {td2.appendTo(tr);}
+ }
+
+ if (this.seriesToggle) {
+
+ // add an overlay for clicking series on/off
+ // div0 = $(document.createElement('div'));
+ // div0.addClass('jqplot-table-legend-overlay');
+ // div0.css({position:'relative', left:0, top:0, height:'100%', width:'100%'});
+ // tr.append(div0);
+
+ var speed;
+ if (typeof(this.seriesToggle) === 'string' || typeof(this.seriesToggle) === 'number') {
+ if (!$.jqplot.use_excanvas || !this.disableIEFading) {
+ speed = this.seriesToggle;
+ }
+ }
+ if (this.showSwatches) {
+ td1.bind('click', {series:s, speed:speed, plot: plot, replot:this.seriesToggleReplot}, handleToggle);
+ td1.addClass('jqplot-seriesToggle');
+ }
+ if (this.showLabels) {
+ td2.bind('click', {series:s, speed:speed, plot: plot, replot:this.seriesToggleReplot}, handleToggle);
+ td2.addClass('jqplot-seriesToggle');
+ }
+
+ // for series that are already hidden, add the hidden class
+ if (!s.show && s.showLabel) {
+ td1.addClass('jqplot-series-hidden');
+ td2.addClass('jqplot-series-hidden');
+ }
+ }
+
+ pad = true;
+ }
+ }
+ idx++;
+ }
+
+ td1 = td2 = div0 = div1 = null;
+ }
+ }
+ return this._elem;
+ };
+
+ var handleToggle = function (ev) {
+ var d = ev.data,
+ s = d.series,
+ replot = d.replot,
+ plot = d.plot,
+ speed = d.speed,
+ sidx = s.index,
+ showing = false;
+
+ if (s.canvas._elem.is(':hidden') || !s.show) {
+ showing = true;
+ }
+
+ var doLegendToggle = function() {
+
+ if (replot) {
+ var opts = {};
+
+ if ($.isPlainObject(replot)) {
+ $.extend(true, opts, replot);
+ }
+
+ plot.replot(opts);
+ // if showing, there was no canvas element to fade in, so hide here
+ // and then do a fade in.
+ if (showing && speed) {
+ var s = plot.series[sidx];
+
+ if (s.shadowCanvas._elem) {
+ s.shadowCanvas._elem.hide().fadeIn(speed);
+ }
+ s.canvas._elem.hide().fadeIn(speed);
+ s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).hide().fadeIn(speed);
+ }
+
+ }
+
+ else {
+ var s = plot.series[sidx];
+
+ if (s.canvas._elem.is(':hidden') || !s.show) {
+ // Not sure if there is a better way to check for showSwatches and showLabels === true.
+ // Test for "undefined" since default values for both showSwatches and showLables is true.
+ if (typeof plot.options.legend.showSwatches === 'undefined' || plot.options.legend.showSwatches === true) {
+ plot.legend._elem.find('td').eq(sidx * 2).addClass('jqplot-series-hidden');
+ }
+ if (typeof plot.options.legend.showLabels === 'undefined' || plot.options.legend.showLabels === true) {
+ plot.legend._elem.find('td').eq((sidx * 2) + 1).addClass('jqplot-series-hidden');
+ }
+ }
+ else {
+ if (typeof plot.options.legend.showSwatches === 'undefined' || plot.options.legend.showSwatches === true) {
+ plot.legend._elem.find('td').eq(sidx * 2).removeClass('jqplot-series-hidden');
+ }
+ if (typeof plot.options.legend.showLabels === 'undefined' || plot.options.legend.showLabels === true) {
+ plot.legend._elem.find('td').eq((sidx * 2) + 1).removeClass('jqplot-series-hidden');
+ }
+ }
+
+ }
+
+ };
+
+ s.toggleDisplay(ev, doLegendToggle);
+ };
+
+ // called with scope of plot.
+ var postDraw = function () {
+ if (this.legend.renderer.constructor == $.jqplot.EnhancedLegendRenderer && this.legend.seriesToggle){
+ var e = this.legend._elem.detach();
+ this.eventCanvas._elem.after(e);
+ }
+ };
+})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.funnelRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.funnelRenderer.js
new file mode 100644
index 00000000..c72660cc
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.funnelRenderer.js
@@ -0,0 +1,943 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.FunnelRenderer
+ * Plugin renderer to draw a funnel chart.
+ * x values, if present, will be used as labels.
+ * y values give area size.
+ *
+ * Funnel charts will draw a single series
+ * only.
+ *
+ * To use this renderer, you need to include the
+ * funnel renderer plugin, for example:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.funnelRenderer.js"></script>
+ *
+ * Properties described here are passed into the $.jqplot function
+ * as options on the series renderer. For example:
+ *
+ * > plot2 = $.jqplot('chart2', [s1, s2], {
+ * > seriesDefaults: {
+ * > renderer:$.jqplot.FunnelRenderer,
+ * > rendererOptions:{
+ * > sectionMargin: 12,
+ * > widthRatio: 0.3
+ * > }
+ * > }
+ * > });
+ *
+ * IMPORTANT
+ *
+ * *The funnel renderer will reorder data in descending order* so the largest value in
+ * the data set is first and displayed on top of the funnel. Data will then
+ * be displayed in descending order down the funnel. The area of each funnel
+ * section will correspond to the value of each data point relative to the sum
+ * of all values. That is section area is proportional to section value divided by
+ * sum of all section values.
+ *
+ * If your data is not in descending order when passed into the plot, *it will be
+ * reordered* when stored in the series.data property. A copy of the unordered
+ * data is kept in the series._unorderedData property.
+ *
+ * A funnel plot will trigger events on the plot target
+ * according to user interaction. All events return the event object,
+ * the series index, the point (section) index, and the point data for
+ * the appropriate section. *Note* the point index will referr to the ordered
+ * data, not the original unordered data.
+ *
+ * 'jqplotDataMouseOver' - triggered when mousing over a section.
+ * 'jqplotDataHighlight' - triggered the first time user mouses over a section,
+ * if highlighting is enabled.
+ * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
+ * a highlighted section.
+ * 'jqplotDataClick' - triggered when the user clicks on a section.
+ * 'jqplotDataRightClick' - tiggered when the user right clicks on a section if
+ * the "captureRightClick" option is set to true on the plot.
+ */
+ $.jqplot.FunnelRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.FunnelRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.FunnelRenderer.prototype.constructor = $.jqplot.FunnelRenderer;
+
+ // called with scope of a series
+ $.jqplot.FunnelRenderer.prototype.init = function(options, plot) {
+ // Group: Properties
+ //
+ // prop: padding
+ // padding between the funnel and plot edges, legend, etc.
+ this.padding = {top: 20, right: 20, bottom: 20, left: 20};
+ // prop: sectionMargin
+ // spacing between funnel sections in pixels.
+ this.sectionMargin = 6;
+ // prop: fill
+ // true or false, wether to fill the areas.
+ this.fill = true;
+ // prop: shadowOffset
+ // offset of the shadow from the area and offset of
+ // each succesive stroke of the shadow from the last.
+ this.shadowOffset = 2;
+ // prop: shadowAlpha
+ // transparency of the shadow (0 = transparent, 1 = opaque)
+ this.shadowAlpha = 0.07;
+ // prop: shadowDepth
+ // number of strokes to apply to the shadow,
+ // each stroke offset shadowOffset from the last.
+ this.shadowDepth = 5;
+ // prop: highlightMouseOver
+ // True to highlight area when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on a area.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over a area.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColors
+ // array of colors to use when highlighting an area.
+ this.highlightColors = [];
+ // prop: widthRatio
+ // The ratio of the width of the top of the funnel to the bottom.
+ // a ratio of 0 will make an upside down pyramid.
+ this.widthRatio = 0.2;
+ // prop: lineWidth
+ // width of line if areas are stroked and not filled.
+ this.lineWidth = 2;
+ // prop: dataLabels
+ // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
+ // Defaults to percentage of each pie slice.
+ this.dataLabels = 'percent';
+ // prop: showDataLabels
+ // true to show data labels on slices.
+ this.showDataLabels = false;
+ // prop: dataLabelFormatString
+ // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
+ this.dataLabelFormatString = null;
+ // prop: dataLabelThreshold
+ // Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed.
+ // This applies to all label types, not just to percentage labels.
+ this.dataLabelThreshold = 3;
+ this._type = 'funnel';
+
+ this.tickRenderer = $.jqplot.FunnelTickRenderer;
+
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
+ options.highlightMouseOver = false;
+ }
+
+ $.extend(true, this, options);
+
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+
+ // lengths of bases, or horizontal sides of areas of trapezoid.
+ this._bases = [];
+ // total area
+ this._atot;
+ // areas of segments.
+ this._areas = [];
+ // vertical lengths of segments.
+ this._lengths = [];
+ // angle of the funnel to vertical.
+ this._angle;
+ this._dataIndices = [];
+
+ // sort data
+ this._unorderedData = $.extend(true, [], this.data);
+ var idxs = $.extend(true, [], this.data);
+ for (var i=0; i<idxs.length; i++) {
+ idxs[i].push(i);
+ }
+ this.data.sort( function (a, b) { return b[1] - a[1]; } );
+ idxs.sort( function (a, b) { return b[1] - a[1]; });
+ for (var i=0; i<idxs.length; i++) {
+ this._dataIndices.push(idxs[i][2]);
+ }
+
+ // set highlight colors if none provided
+ if (this.highlightColors.length == 0) {
+ for (var i=0; i<this.seriesColors.length; i++){
+ var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.4 * (255 - newrgb[j]);
+ newrgb[j] = parseInt(newrgb[j], 10);
+ }
+ this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
+ }
+ }
+
+ plot.postParseOptionsHooks.addOnce(postParseOptions);
+ plot.postInitHooks.addOnce(postInit);
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
+ plot.postDrawHooks.addOnce(postPlotDraw);
+
+ };
+
+ // gridData will be of form [label, percentage of total]
+ $.jqplot.FunnelRenderer.prototype.setGridData = function(plot) {
+ // set gridData property. This will hold angle in radians of each data point.
+ var sum = 0;
+ var td = [];
+ for (var i=0; i<this.data.length; i++){
+ sum += this.data[i][1];
+ td.push([this.data[i][0], this.data[i][1]]);
+ }
+
+ // normalize y values, so areas are proportional.
+ for (var i=0; i<td.length; i++) {
+ td[i][1] = td[i][1]/sum;
+ }
+
+ this._bases = new Array(td.length + 1);
+ this._lengths = new Array(td.length);
+
+ this.gridData = td;
+ };
+
+ $.jqplot.FunnelRenderer.prototype.makeGridData = function(data, plot) {
+ // set gridData property. This will hold angle in radians of each data point.
+ var sum = 0;
+ var td = [];
+ for (var i=0; i<this.data.length; i++){
+ sum += this.data[i][1];
+ td.push([this.data[i][0], this.data[i][1]]);
+ }
+
+ // normalize y values, so areas are proportional.
+ for (var i=0; i<td.length; i++) {
+ td[i][1] = td[i][1]/sum;
+ }
+
+ this._bases = new Array(td.length + 1);
+ this._lengths = new Array(td.length);
+
+ return td;
+ };
+
+ $.jqplot.FunnelRenderer.prototype.drawSection = function (ctx, vertices, color, isShadow) {
+ var fill = this.fill;
+ var lineWidth = this.lineWidth;
+ ctx.save();
+
+ if (isShadow) {
+ for (var i=0; i<this.shadowDepth; i++) {
+ ctx.save();
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
+ doDraw();
+ }
+ }
+
+ else {
+ doDraw();
+ }
+
+ function doDraw () {
+ ctx.beginPath();
+ ctx.fillStyle = color;
+ ctx.strokeStyle = color;
+ ctx.lineWidth = lineWidth;
+ ctx.moveTo(vertices[0][0], vertices[0][1]);
+ for (var i=1; i<4; i++) {
+ ctx.lineTo(vertices[i][0], vertices[i][1]);
+ }
+ ctx.closePath();
+ if (fill) {
+ ctx.fill();
+ }
+ else {
+ ctx.stroke();
+ }
+ }
+
+ if (isShadow) {
+ for (var i=0; i<this.shadowDepth; i++) {
+ ctx.restore();
+ }
+ }
+
+ ctx.restore();
+ };
+
+ // called with scope of series
+ $.jqplot.FunnelRenderer.prototype.draw = function (ctx, gd, options, plot) {
+ var i;
+ var opts = (options != undefined) ? options : {};
+ // offset and direction of offset due to legend placement
+ var offx = 0;
+ var offy = 0;
+ var trans = 1;
+ this._areas = [];
+ // var colorGenerator = new this.colorGenerator(this.seriesColors);
+ if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
+ var li = options.legendInfo;
+ switch (li.location) {
+ case 'nw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'w':
+ offx = li.width + li.xoffset;
+ break;
+ case 'sw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'ne':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'e':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'se':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'n':
+ offy = li.height + li.yoffset;
+ break;
+ case 's':
+ offy = li.height + li.yoffset;
+ trans = -1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ var loff = (trans==1) ? this.padding.left + offx : this.padding.left;
+ var toff = (trans==1) ? this.padding.top + offy : this.padding.top;
+ var roff = (trans==-1) ? this.padding.right + offx : this.padding.right;
+ var boff = (trans==-1) ? this.padding.bottom + offy : this.padding.bottom;
+
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var cw = ctx.canvas.width;
+ var ch = ctx.canvas.height;
+ this._bases[0] = cw - loff - roff;
+ var ltot = this._length = ch - toff - boff;
+
+ var hend = this._bases[0]*this.widthRatio;
+ this._atot = ltot/2 * (this._bases[0] + this._bases[0]*this.widthRatio);
+
+ this._angle = Math.atan((this._bases[0] - hend)/2/ltot);
+
+ for (i=0; i<gd.length; i++) {
+ this._areas.push(gd[i][1] * this._atot);
+ }
+
+
+ var guess, err, count, lsum=0;
+ var tolerance = 0.0001;
+
+ for (i=0; i<this._areas.length; i++) {
+ guess = this._areas[i]/this._bases[i];
+ err = 999999;
+ this._lengths[i] = guess;
+ count = 0;
+ while (err > this._lengths[i]*tolerance && count < 100) {
+ this._lengths[i] = this._areas[i]/(this._bases[i] - this._lengths[i] * Math.tan(this._angle));
+ err = Math.abs(this._lengths[i] - guess);
+ this._bases[i+1] = this._bases[i] - (2*this._lengths[i]*Math.tan(this._angle));
+ guess = this._lengths[i];
+ count++;
+ }
+ lsum += this._lengths[i];
+ }
+
+ // figure out vertices of each section
+ this._vertices = new Array(gd.length);
+
+ // these are 4 coners of entire trapezoid
+ var p0 = [loff, toff],
+ p1 = [loff+this._bases[0], toff],
+ p2 = [loff + (this._bases[0] - this._bases[this._bases.length-1])/2, toff + this._length],
+ p3 = [p2[0] + this._bases[this._bases.length-1], p2[1]];
+
+ // equations of right and left sides, returns x, y values given height of section (y value)
+ function findleft (l) {
+ var m = (p0[1] - p2[1])/(p0[0] - p2[0]);
+ var b = p0[1] - m*p0[0];
+ var y = l + p0[1];
+
+ return [(y - b)/m, y];
+ }
+
+ function findright (l) {
+ var m = (p1[1] - p3[1])/(p1[0] - p3[0]);
+ var b = p1[1] - m*p1[0];
+ var y = l + p1[1];
+
+ return [(y - b)/m, y];
+ }
+
+ var x = offx, y = offy;
+ var h=0, adj=0;
+
+ for (i=0; i<gd.length; i++) {
+ this._vertices[i] = new Array();
+ var v = this._vertices[i];
+ var sm = this.sectionMargin;
+ if (i == 0) {
+ adj = 0;
+ }
+ if (i == 1) {
+ adj = sm/3;
+ }
+ else if (i > 0 && i < gd.length-1) {
+ adj = sm/2;
+ }
+ else if (i == gd.length -1) {
+ adj = 2*sm/3;
+ }
+ v.push(findleft(h+adj));
+ v.push(findright(h+adj));
+ h += this._lengths[i];
+ if (i == 0) {
+ adj = -2*sm/3;
+ }
+ else if (i > 0 && i < gd.length-1) {
+ adj = -sm/2;
+ }
+ else if (i == gd.length - 1) {
+ adj = 0;
+ }
+ v.push(findright(h+adj));
+ v.push(findleft(h+adj));
+
+ }
+
+ if (this.shadow) {
+ var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
+ for (var i=0; i<gd.length; i++) {
+ this.renderer.drawSection.call (this, ctx, this._vertices[i], shadowColor, true);
+ }
+
+ }
+ for (var i=0; i<gd.length; i++) {
+ var v = this._vertices[i];
+ this.renderer.drawSection.call (this, ctx, v, this.seriesColors[i]);
+
+ if (this.showDataLabels && gd[i][1]*100 >= this.dataLabelThreshold) {
+ var fstr, label;
+
+ if (this.dataLabels == 'label') {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, gd[i][0]);
+ }
+ else if (this.dataLabels == 'value') {
+ fstr = this.dataLabelFormatString || '%d';
+ label = $.jqplot.sprintf(fstr, this.data[i][1]);
+ }
+ else if (this.dataLabels == 'percent') {
+ fstr = this.dataLabelFormatString || '%d%%';
+ label = $.jqplot.sprintf(fstr, gd[i][1]*100);
+ }
+ else if (this.dataLabels.constructor == Array) {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, this.dataLabels[this._dataIndices[i]]);
+ }
+
+ var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
+
+ var x = (v[0][0] + v[1][0])/2 + this.canvas._offsets.left;
+ var y = (v[1][1] + v[2][1])/2 + this.canvas._offsets.top;
+
+ var labelelem = $('<span class="jqplot-funnel-series jqplot-data-label" style="position:absolute;">' + label + '</span>').insertBefore(plot.eventCanvas._elem);
+ x -= labelelem.width()/2;
+ y -= labelelem.height()/2;
+ x = Math.round(x);
+ y = Math.round(y);
+ labelelem.css({left: x, top: y});
+ }
+
+ }
+
+ };
+
+ $.jqplot.FunnelAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.FunnelAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.FunnelAxisRenderer.prototype.constructor = $.jqplot.FunnelAxisRenderer;
+
+
+ // There are no traditional axes on a funnel chart. We just need to provide
+ // dummy objects with properties so the plot will render.
+ // called with scope of axis object.
+ $.jqplot.FunnelAxisRenderer.prototype.init = function(options){
+ //
+ this.tickRenderer = $.jqplot.FunnelTickRenderer;
+ $.extend(true, this, options);
+ // I don't think I'm going to need _dataBounds here.
+ // have to go Axis scaling in a way to fit chart onto plot area
+ // and provide u2p and p2u functionality for mouse cursor, etc.
+ // for convienence set _dataBounds to 0 and 100 and
+ // set min/max to 0 and 100.
+ this._dataBounds = {min:0, max:100};
+ this.min = 0;
+ this.max = 100;
+ this.showTicks = false;
+ this.ticks = [];
+ this.showMark = false;
+ this.show = false;
+ };
+
+
+
+ /**
+ * Class: $.jqplot.FunnelLegendRenderer
+ * Legend Renderer specific to funnel plots. Set by default
+ * when the user creates a funnel plot.
+ */
+ $.jqplot.FunnelLegendRenderer = function(){
+ $.jqplot.TableLegendRenderer.call(this);
+ };
+
+ $.jqplot.FunnelLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.FunnelLegendRenderer.prototype.constructor = $.jqplot.FunnelLegendRenderer;
+
+ $.jqplot.FunnelLegendRenderer.prototype.init = function(options) {
+ // Group: Properties
+ //
+ // prop: numberRows
+ // Maximum number of rows in the legend. 0 or null for unlimited.
+ this.numberRows = null;
+ // prop: numberColumns
+ // Maximum number of columns in the legend. 0 or null for unlimited.
+ this.numberColumns = null;
+ $.extend(true, this, options);
+ };
+
+ // called with context of legend
+ $.jqplot.FunnelLegendRenderer.prototype.draw = function() {
+ var legend = this;
+ if (this.show) {
+ var series = this._series;
+ var ss = 'position:absolute;';
+ ss += (this.background) ? 'background:'+this.background+';' : '';
+ ss += (this.border) ? 'border:'+this.border+';' : '';
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
+ ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
+ ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
+ ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
+ ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
+ // Funnel charts legends don't go by number of series, but by number of data points
+ // in the series. Refactor things here for that.
+
+ var pad = false,
+ reverse = false,
+ nr, nc;
+ var s = series[0];
+ var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
+
+ if (s.show) {
+ var pd = s.data;
+ if (this.numberRows) {
+ nr = this.numberRows;
+ if (!this.numberColumns){
+ nc = Math.ceil(pd.length/nr);
+ }
+ else{
+ nc = this.numberColumns;
+ }
+ }
+ else if (this.numberColumns) {
+ nc = this.numberColumns;
+ nr = Math.ceil(pd.length/this.numberColumns);
+ }
+ else {
+ nr = pd.length;
+ nc = 1;
+ }
+
+ var i, j, tr, td1, td2, lt, rs, color;
+ var idx = 0;
+
+ for (i=0; i<nr; i++) {
+ if (reverse){
+ tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
+ }
+ else{
+ tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
+ }
+ for (j=0; j<nc; j++) {
+ if (idx < pd.length){
+ lt = this.labels[idx] || pd[idx][0].toString();
+ color = colorGenerator.next();
+ if (!reverse){
+ if (i>0){
+ pad = true;
+ }
+ else{
+ pad = false;
+ }
+ }
+ else{
+ if (i == nr -1){
+ pad = false;
+ }
+ else{
+ pad = true;
+ }
+ }
+ rs = (pad) ? this.rowSpacing : '0';
+
+ td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
+ '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
+ '</div></td>');
+ td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
+ if (this.escapeHtml){
+ td2.text(lt);
+ }
+ else {
+ td2.html(lt);
+ }
+ if (reverse) {
+ td2.prependTo(tr);
+ td1.prependTo(tr);
+ }
+ else {
+ td1.appendTo(tr);
+ td2.appendTo(tr);
+ }
+ pad = true;
+ }
+ idx++;
+ }
+ }
+ }
+ }
+ return this._elem;
+ };
+
+ // $.jqplot.FunnelLegendRenderer.prototype.pack = function(offsets) {
+ // if (this.show) {
+ // // fake a grid for positioning
+ // var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};
+ // if (this.placement == 'insideGrid') {
+ // switch (this.location) {
+ // case 'nw':
+ // var a = grid._left + this.xoffset;
+ // var b = grid._top + this.yoffset;
+ // this._elem.css('left', a);
+ // this._elem.css('top', b);
+ // break;
+ // case 'n':
+ // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ // var b = grid._top + this.yoffset;
+ // this._elem.css('left', a);
+ // this._elem.css('top', b);
+ // break;
+ // case 'ne':
+ // var a = offsets.right + this.xoffset;
+ // var b = grid._top + this.yoffset;
+ // this._elem.css({right:a, top:b});
+ // break;
+ // case 'e':
+ // var a = offsets.right + this.xoffset;
+ // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ // this._elem.css({right:a, top:b});
+ // break;
+ // case 'se':
+ // var a = offsets.right + this.xoffset;
+ // var b = offsets.bottom + this.yoffset;
+ // this._elem.css({right:a, bottom:b});
+ // break;
+ // case 's':
+ // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ // var b = offsets.bottom + this.yoffset;
+ // this._elem.css({left:a, bottom:b});
+ // break;
+ // case 'sw':
+ // var a = grid._left + this.xoffset;
+ // var b = offsets.bottom + this.yoffset;
+ // this._elem.css({left:a, bottom:b});
+ // break;
+ // case 'w':
+ // var a = grid._left + this.xoffset;
+ // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ // this._elem.css({left:a, top:b});
+ // break;
+ // default: // same as 'se'
+ // var a = grid._right - this.xoffset;
+ // var b = grid._bottom + this.yoffset;
+ // this._elem.css({right:a, bottom:b});
+ // break;
+ // }
+ //
+ // }
+ // else {
+ // switch (this.location) {
+ // case 'nw':
+ // var a = this._plotDimensions.width - grid._left + this.xoffset;
+ // var b = grid._top + this.yoffset;
+ // this._elem.css('right', a);
+ // this._elem.css('top', b);
+ // break;
+ // case 'n':
+ // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ // var b = this._plotDimensions.height - grid._top + this.yoffset;
+ // this._elem.css('left', a);
+ // this._elem.css('bottom', b);
+ // break;
+ // case 'ne':
+ // var a = this._plotDimensions.width - offsets.right + this.xoffset;
+ // var b = grid._top + this.yoffset;
+ // this._elem.css({left:a, top:b});
+ // break;
+ // case 'e':
+ // var a = this._plotDimensions.width - offsets.right + this.xoffset;
+ // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ // this._elem.css({left:a, top:b});
+ // break;
+ // case 'se':
+ // var a = this._plotDimensions.width - offsets.right + this.xoffset;
+ // var b = offsets.bottom + this.yoffset;
+ // this._elem.css({left:a, bottom:b});
+ // break;
+ // case 's':
+ // var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ // var b = this._plotDimensions.height - offsets.bottom + this.yoffset;
+ // this._elem.css({left:a, top:b});
+ // break;
+ // case 'sw':
+ // var a = this._plotDimensions.width - grid._left + this.xoffset;
+ // var b = offsets.bottom + this.yoffset;
+ // this._elem.css({right:a, bottom:b});
+ // break;
+ // case 'w':
+ // var a = this._plotDimensions.width - grid._left + this.xoffset;
+ // var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ // this._elem.css({right:a, top:b});
+ // break;
+ // default: // same as 'se'
+ // var a = grid._right - this.xoffset;
+ // var b = grid._bottom + this.yoffset;
+ // this._elem.css({right:a, bottom:b});
+ // break;
+ // }
+ // }
+ // }
+ // };
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.legend = options.legend || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ // only set these if there is a funnel series
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.FunnelRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.FunnelRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.FunnelAxisRenderer;
+ options.legend.renderer = $.jqplot.FunnelLegendRenderer;
+ options.legend.preDraw = true;
+ options.sortData = false;
+ options.seriesDefaults.pointLabels = {show: false};
+ }
+ }
+
+ function postInit(target, data, options) {
+ // if multiple series, add a reference to the previous one so that
+ // funnel rings can nest.
+ for (var i=0; i<this.series.length; i++) {
+ if (this.series[i].renderer.constructor == $.jqplot.FunnelRenderer) {
+ // don't allow mouseover and mousedown at same time.
+ if (this.series[i].highlightMouseOver) {
+ this.series[i].highlightMouseDown = false;
+ }
+ }
+ }
+ }
+
+ // called with scope of plot
+ function postParseOptions(options) {
+ for (var i=0; i<this.series.length; i++) {
+ this.series[i].seriesColors = this.seriesColors;
+ this.series[i].colorGenerator = $.jqplot.colorGenerator;
+ }
+ }
+
+ function highlight (plot, sidx, pidx) {
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.funnelRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.funnelRenderer.highlightedSeriesIndex = sidx;
+ s.renderer.drawSection.call(s, canvas._ctx, s._vertices[pidx], s.highlightColors[pidx], false);
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.funnelRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.funnelRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ }
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.funnelRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.funnelRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
+ var idx = plot.plugins.funnelRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ }
+
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt = jQuery.Event('jqplotDataClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var idx = plot.plugins.funnelRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ var evt = jQuery.Event('jqplotDataRightClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.funnelRenderer && this.plugins.funnelRenderer.highlightCanvas) {
+ this.plugins.funnelRenderer.highlightCanvas.resetCanvas();
+ this.plugins.funnelRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.funnelRenderer = {};
+ this.plugins.funnelRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ // do we have any data labels? if so, put highlight canvas before those
+ var labels = $(this.targetId+' .jqplot-data-label');
+ if (labels.length) {
+ $(labels[0]).before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-funnelRenderer-highlight-canvas', this._plotDimensions, this));
+ }
+ // else put highlight canvas before event canvas.
+ else {
+ this.eventCanvas._elem.before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-funnelRenderer-highlight-canvas', this._plotDimensions, this));
+ }
+ var hctx = this.plugins.funnelRenderer.highlightCanvas.setContext();
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+
+ $.jqplot.FunnelTickRenderer = function() {
+ $.jqplot.AxisTickRenderer.call(this);
+ };
+
+ $.jqplot.FunnelTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
+ $.jqplot.FunnelTickRenderer.prototype.constructor = $.jqplot.FunnelTickRenderer;
+
+})(jQuery);
+
+ \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.highlighter.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.highlighter.js
new file mode 100644
index 00000000..2e8c5da9
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.highlighter.js
@@ -0,0 +1,465 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);
+
+ /**
+ * Class: $.jqplot.Highlighter
+ * Plugin which will highlight data points when they are moused over.
+ *
+ * To use this plugin, include the js
+ * file in your source:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.highlighter.js"></script>
+ *
+ * A tooltip providing information about the data point is enabled by default.
+ * To disable the tooltip, set "showTooltip" to false.
+ *
+ * You can control what data is displayed in the tooltip with various
+ * options. The "tooltipAxes" option controls wether the x, y or both
+ * data values are displayed.
+ *
+ * Some chart types (e.g. hi-low-close) have more than one y value per
+ * data point. To display the additional values in the tooltip, set the
+ * "yvalues" option to the desired number of y values present (3 for a hlc chart).
+ *
+ * By default, data values will be formatted with the same formatting
+ * specifiers as used to format the axis ticks. A custom format code
+ * can be supplied with the tooltipFormatString option. This will apply
+ * to all values in the tooltip.
+ *
+ * For more complete control, the "formatString" option can be set. This
+ * Allows conplete control over tooltip formatting. Values are passed to
+ * the format string in an order determined by the "tooltipAxes" and "yvalues"
+ * options. So, if you have a hi-low-close chart and you just want to display
+ * the hi-low-close values in the tooltip, you could set a formatString like:
+ *
+ * > highlighter: {
+ * > tooltipAxes: 'y',
+ * > yvalues: 3,
+ * > formatString:'<table class="jqplot-highlighter">
+ * > <tr><td>hi:</td><td>%s</td></tr>
+ * > <tr><td>low:</td><td>%s</td></tr>
+ * > <tr><td>close:</td><td>%s</td></tr></table>'
+ * > }
+ *
+ */
+ $.jqplot.Highlighter = function(options) {
+ // Group: Properties
+ //
+ //prop: show
+ // true to show the highlight.
+ this.show = $.jqplot.config.enablePlugins;
+ // prop: markerRenderer
+ // Renderer used to draw the marker of the highlighted point.
+ // Renderer will assimilate attributes from the data point being highlighted,
+ // so no attributes need set on the renderer directly.
+ // Default is to turn off shadow drawing on the highlighted point.
+ this.markerRenderer = new $.jqplot.MarkerRenderer({shadow:false});
+ // prop: showMarker
+ // true to show the marker
+ this.showMarker = true;
+ // prop: lineWidthAdjust
+ // Pixels to add to the lineWidth of the highlight.
+ this.lineWidthAdjust = 2.5;
+ // prop: sizeAdjust
+ // Pixels to add to the overall size of the highlight.
+ this.sizeAdjust = 5;
+ // prop: showTooltip
+ // Show a tooltip with data point values.
+ this.showTooltip = true;
+ // prop: tooltipLocation
+ // Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
+ this.tooltipLocation = 'nw';
+ // prop: fadeTooltip
+ // true = fade in/out tooltip, flase = show/hide tooltip
+ this.fadeTooltip = true;
+ // prop: tooltipFadeSpeed
+ // 'slow', 'def', 'fast', or number of milliseconds.
+ this.tooltipFadeSpeed = "fast";
+ // prop: tooltipOffset
+ // Pixel offset of tooltip from the highlight.
+ this.tooltipOffset = 2;
+ // prop: tooltipAxes
+ // Which axes to display in tooltip, 'x', 'y' or 'both', 'xy' or 'yx'
+ // 'both' and 'xy' are equivalent, 'yx' reverses order of labels.
+ this.tooltipAxes = 'both';
+ // prop; tooltipSeparator
+ // String to use to separate x and y axes in tooltip.
+ this.tooltipSeparator = ', ';
+ // prop; tooltipContentEditor
+ // Function used to edit/augment/replace the formatted tooltip contents.
+ // Called as str = tooltipContentEditor(str, seriesIndex, pointIndex)
+ // where str is the generated tooltip html and seriesIndex and pointIndex identify
+ // the data point being highlighted. Should return the html for the tooltip contents.
+ this.tooltipContentEditor = null;
+ // prop: useAxesFormatters
+ // Use the x and y axes formatters to format the text in the tooltip.
+ this.useAxesFormatters = true;
+ // prop: tooltipFormatString
+ // sprintf format string for the tooltip.
+ // Uses Ash Searle's javascript sprintf implementation
+ // found here: http://hexmen.com/blog/2007/03/printf-sprintf/
+ // See http://perldoc.perl.org/functions/sprintf.html for reference.
+ // Additional "p" and "P" format specifiers added by Chris Leonello.
+ this.tooltipFormatString = '%.5P';
+ // prop: formatString
+ // alternative to tooltipFormatString
+ // will format the whole tooltip text, populating with x, y values as
+ // indicated by tooltipAxes option. So, you could have a tooltip like:
+ // 'Date: %s, number of cats: %d' to format the whole tooltip at one go.
+ // If useAxesFormatters is true, values will be formatted according to
+ // Axes formatters and you can populate your tooltip string with
+ // %s placeholders.
+ this.formatString = null;
+ // prop: yvalues
+ // Number of y values to expect in the data point array.
+ // Typically this is 1. Certain plots, like OHLC, will
+ // have more y values in each data point array.
+ this.yvalues = 1;
+ // prop: bringSeriesToFront
+ // This option requires jQuery 1.4+
+ // True to bring the series of the highlighted point to the front
+ // of other series.
+ this.bringSeriesToFront = false;
+ this._tooltipElem;
+ this.isHighlighting = false;
+ this.currentNeighbor = null;
+
+ $.extend(true, this, options);
+ };
+
+ var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];
+ var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7};
+ var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e'];
+
+ // axis.renderer.tickrenderer.formatter
+
+ // called with scope of plot
+ $.jqplot.Highlighter.init = function (target, data, opts){
+ var options = opts || {};
+ // add a highlighter attribute to the plot
+ this.plugins.highlighter = new $.jqplot.Highlighter(options.highlighter);
+ };
+
+ // called within scope of series
+ $.jqplot.Highlighter.parseOptions = function (defaults, options) {
+ // Add a showHighlight option to the series
+ // and set it to true by default.
+ this.showHighlight = true;
+ };
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ $.jqplot.Highlighter.postPlotDraw = function() {
+ // Memory Leaks patch
+ if (this.plugins.highlighter && this.plugins.highlighter.highlightCanvas) {
+ this.plugins.highlighter.highlightCanvas.resetCanvas();
+ this.plugins.highlighter.highlightCanvas = null;
+ }
+
+ if (this.plugins.highlighter && this.plugins.highlighter._tooltipElem) {
+ this.plugins.highlighter._tooltipElem.emptyForce();
+ this.plugins.highlighter._tooltipElem = null;
+ }
+
+ this.plugins.highlighter.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ this.eventCanvas._elem.before(this.plugins.highlighter.highlightCanvas.createElement(this._gridPadding, 'jqplot-highlight-canvas', this._plotDimensions, this));
+ this.plugins.highlighter.highlightCanvas.setContext();
+
+ var elem = document.createElement('div');
+ this.plugins.highlighter._tooltipElem = $(elem);
+ elem = null;
+ this.plugins.highlighter._tooltipElem.addClass('jqplot-highlighter-tooltip');
+ this.plugins.highlighter._tooltipElem.css({position:'absolute', display:'none'});
+
+ this.eventCanvas._elem.before(this.plugins.highlighter._tooltipElem);
+ };
+
+ $.jqplot.preInitHooks.push($.jqplot.Highlighter.init);
+ $.jqplot.preParseSeriesOptionsHooks.push($.jqplot.Highlighter.parseOptions);
+ $.jqplot.postDrawHooks.push($.jqplot.Highlighter.postPlotDraw);
+
+ function draw(plot, neighbor) {
+ var hl = plot.plugins.highlighter;
+ var s = plot.series[neighbor.seriesIndex];
+ var smr = s.markerRenderer;
+ var mr = hl.markerRenderer;
+ mr.style = smr.style;
+ mr.lineWidth = smr.lineWidth + hl.lineWidthAdjust;
+ mr.size = smr.size + hl.sizeAdjust;
+ var rgba = $.jqplot.getColorComponents(smr.color);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var alpha = (rgba[3] >= 0.6) ? rgba[3]*0.6 : rgba[3]*(2-rgba[3]);
+ mr.color = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+alpha+')';
+ mr.init();
+ mr.draw(s.gridData[neighbor.pointIndex][0], s.gridData[neighbor.pointIndex][1], hl.highlightCanvas._ctx);
+ }
+
+ function showTooltip(plot, series, neighbor) {
+ // neighbor looks like: {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}
+ // gridData should be x,y pixel coords on the grid.
+ // add the plot._gridPadding to that to get x,y in the target.
+ var hl = plot.plugins.highlighter;
+ var elem = hl._tooltipElem;
+ var serieshl = series.highlighter || {};
+
+ var opts = $.extend(true, {}, hl, serieshl);
+
+ if (opts.useAxesFormatters) {
+ var xf = series._xaxis._ticks[0].formatter;
+ var yf = series._yaxis._ticks[0].formatter;
+ var xfstr = series._xaxis._ticks[0].formatString;
+ var yfstr = series._yaxis._ticks[0].formatString;
+ var str;
+ var xstr = xf(xfstr, neighbor.data[0]);
+ var ystrs = [];
+ for (var i=1; i<opts.yvalues+1; i++) {
+ ystrs.push(yf(yfstr, neighbor.data[i]));
+ }
+ if (typeof opts.formatString === 'string') {
+ switch (opts.tooltipAxes) {
+ case 'both':
+ case 'xy':
+ ystrs.unshift(xstr);
+ ystrs.unshift(opts.formatString);
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
+ break;
+ case 'yx':
+ ystrs.push(xstr);
+ ystrs.unshift(opts.formatString);
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
+ break;
+ case 'x':
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString, xstr]);
+ break;
+ case 'y':
+ ystrs.unshift(opts.formatString);
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
+ break;
+ default: // same as xy
+ ystrs.unshift(xstr);
+ ystrs.unshift(opts.formatString);
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
+ break;
+ }
+ }
+ else {
+ switch (opts.tooltipAxes) {
+ case 'both':
+ case 'xy':
+ str = xstr;
+ for (var i=0; i<ystrs.length; i++) {
+ str += opts.tooltipSeparator + ystrs[i];
+ }
+ break;
+ case 'yx':
+ str = '';
+ for (var i=0; i<ystrs.length; i++) {
+ str += ystrs[i] + opts.tooltipSeparator;
+ }
+ str += xstr;
+ break;
+ case 'x':
+ str = xstr;
+ break;
+ case 'y':
+ str = ystrs.join(opts.tooltipSeparator);
+ break;
+ default: // same as 'xy'
+ str = xstr;
+ for (var i=0; i<ystrs.length; i++) {
+ str += opts.tooltipSeparator + ystrs[i];
+ }
+ break;
+
+ }
+ }
+ }
+ else {
+ var str;
+ if (typeof opts.formatString === 'string') {
+ str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString].concat(neighbor.data));
+ }
+
+ else {
+ if (opts.tooltipAxes == 'both' || opts.tooltipAxes == 'xy') {
+ str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]);
+ }
+ else if (opts.tooltipAxes == 'yx') {
+ str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]);
+ }
+ else if (opts.tooltipAxes == 'x') {
+ str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]);
+ }
+ else if (opts.tooltipAxes == 'y') {
+ str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]);
+ }
+ }
+ }
+ if ($.isFunction(opts.tooltipContentEditor)) {
+ // args str, seriesIndex, pointIndex are essential so the hook can look up
+ // extra data for the point.
+ str = opts.tooltipContentEditor(str, neighbor.seriesIndex, neighbor.pointIndex, plot);
+ }
+ elem.html(str);
+ var gridpos = {x:neighbor.gridData[0], y:neighbor.gridData[1]};
+ var ms = 0;
+ var fact = 0.707;
+ if (series.markerRenderer.show == true) {
+ ms = (series.markerRenderer.size + opts.sizeAdjust)/2;
+ }
+
+ var loc = locations;
+ if (series.fillToZero && series.fill && neighbor.data[1] < 0) {
+ loc = oppositeLocations;
+ }
+
+ switch (loc[locationIndicies[opts.tooltipLocation]]) {
+ case 'nw':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
+ var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
+ break;
+ case 'n':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
+ var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - ms;
+ break;
+ case 'ne':
+ var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms;
+ var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
+ break;
+ case 'e':
+ var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + ms;
+ var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ case 'se':
+ var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms;
+ var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms;
+ break;
+ case 's':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
+ var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + ms;
+ break;
+ case 'sw':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
+ var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms;
+ break;
+ case 'w':
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - ms;
+ var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
+ break;
+ default: // same as 'nw'
+ var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
+ var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
+ break;
+ }
+ elem.css('left', x);
+ elem.css('top', y);
+ if (opts.fadeTooltip) {
+ // Fix for stacked up animations. Thnanks Trevor!
+ elem.stop(true,true).fadeIn(opts.tooltipFadeSpeed);
+ }
+ else {
+ elem.show();
+ }
+ elem = null;
+
+ }
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ var hl = plot.plugins.highlighter;
+ var c = plot.plugins.cursor;
+ if (hl.show) {
+ if (neighbor == null && hl.isHighlighting) {
+ var evt = jQuery.Event('jqplotHighlighterUnhighlight');
+ plot.target.trigger(evt);
+
+ var ctx = hl.highlightCanvas._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ if (hl.fadeTooltip) {
+ hl._tooltipElem.fadeOut(hl.tooltipFadeSpeed);
+ }
+ else {
+ hl._tooltipElem.hide();
+ }
+ if (hl.bringSeriesToFront) {
+ plot.restorePreviousSeriesOrder();
+ }
+ hl.isHighlighting = false;
+ hl.currentNeighbor = null;
+ ctx = null;
+ }
+ else if (neighbor != null && plot.series[neighbor.seriesIndex].showHighlight && !hl.isHighlighting) {
+ var evt = jQuery.Event('jqplotHighlighterHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data, plot];
+ plot.target.trigger(evt, ins);
+
+ hl.isHighlighting = true;
+ hl.currentNeighbor = neighbor;
+ if (hl.showMarker) {
+ draw(plot, neighbor);
+ }
+ if (hl.showTooltip && (!c || !c._zoom.started)) {
+ showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor);
+ }
+ if (hl.bringSeriesToFront) {
+ plot.moveSeriesToFront(neighbor.seriesIndex);
+ }
+ }
+ // check to see if we're highlighting the wrong point.
+ else if (neighbor != null && hl.isHighlighting && hl.currentNeighbor != neighbor) {
+ // highlighting the wrong point.
+
+ // if new series allows highlighting, highlight new point.
+ if (plot.series[neighbor.seriesIndex].showHighlight) {
+ var ctx = hl.highlightCanvas._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ hl.isHighlighting = true;
+ hl.currentNeighbor = neighbor;
+ if (hl.showMarker) {
+ draw(plot, neighbor);
+ }
+ if (hl.showTooltip && (!c || !c._zoom.started)) {
+ showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor);
+ }
+ if (hl.bringSeriesToFront) {
+ plot.moveSeriesToFront(neighbor.seriesIndex);
+ }
+ }
+ }
+ }
+ }
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.json2.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.json2.js
new file mode 100644
index 00000000..46fb942b
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.json2.js
@@ -0,0 +1,475 @@
+/*
+ 2010-11-01 Chris Leonello
+
+ Slightly modified version of the original json2.js to put JSON
+ functions under the $.jqplot namespace.
+
+ licensing and orignal comments follow:
+
+ http://www.JSON.org/json2.js
+ 2010-08-25
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
+
+
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
+
+ $.jqplot.JSON.stringify(value, replacer, space)
+ value any JavaScript value, usually an object or array.
+
+ replacer an optional parameter that determines how object
+ values are stringified for objects. It can be a
+ function or an array of strings.
+
+ space an optional parameter that specifies the indentation
+ of nested structures. If it is omitted, the text will
+ be packed without extra whitespace. If it is a number,
+ it will specify the number of spaces to indent at each
+ level. If it is a string (such as '\t' or '&nbsp;'),
+ it contains the characters used to indent at each level.
+
+ This method produces a JSON text from a JavaScript value.
+
+ When an object value is found, if the object contains a toJSON
+ method, its toJSON method will be called and the result will be
+ stringified. A toJSON method does not serialize: it returns the
+ value represented by the name/value pair that should be serialized,
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the value
+
+ For example, this would serialize Dates as ISO strings.
+
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ You can provide an optional replacer method. It will be passed the
+ key and value of each member, with this bound to the containing
+ object. The value that is returned from your method will be
+ serialized. If your method returns undefined, then the member will
+ be excluded from the serialization.
+
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
+ stringified.
+
+ Values that do not have JSON representations, such as undefined or
+ functions, will not be serialized. Such values in objects will be
+ dropped; in arrays they will be replaced with null. You can use
+ a replacer function to replace those with JSON values.
+ $.jqplot.JSON.stringify(undefined) returns undefined.
+
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
+
+ If the space parameter is a non-empty string, then that string will
+ be used for indentation. If the space parameter is a number, then
+ the indentation will be that many spaces.
+
+ Example:
+
+ text = $.jqplot.JSON.stringify(['e', {pluribus: 'unum'}]);
+ // text is '["e",{"pluribus":"unum"}]'
+
+
+ text = $.jqplot.JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+ text = $.jqplot.JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
+
+ $.jqplot.JSON.parse(text, reviver)
+ This method parses a JSON text to produce an object or array.
+ It can throw a SyntaxError exception.
+
+ The optional reviver parameter is a function that can filter and
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
+
+ Example:
+
+ // Parse the text. Values that look like ISO date strings will
+ // be converted to Date objects.
+
+ myData = $.jqplot.JSON.parse(text, function (key, value) {
+ var a;
+ if (typeof value === 'string') {
+ a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+ if (a) {
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+ +a[5], +a[6]));
+ }
+ }
+ return value;
+ });
+
+ myData = $.jqplot.JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
+
+
+ This is a reference implementation. You are free to copy, modify, or
+ redistribute.
+*/
+
+(function($) {
+
+ $.jqplot.JSON = window.JSON;
+
+ if (!window.JSON) {
+ $.jqplot.JSON = {};
+ }
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ if (typeof Date.prototype.toJSON !== 'function') {
+
+ Date.prototype.toJSON = function (key) {
+
+ return isFinite(this.valueOf()) ?
+ this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z' : null;
+ };
+
+ String.prototype.toJSON =
+ Number.prototype.toJSON =
+ Boolean.prototype.toJSON = function (key) {
+ return this.valueOf();
+ };
+ }
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
+
+
+ function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+ escapable.lastIndex = 0;
+ return escapable.test(string) ?
+ '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string' ? c :
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' :
+ '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+// Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+// What happens next depends on the value's type.
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value) ? String(value) : 'null';
+
+ case 'boolean':
+ case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+ return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+ case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+// Is the value an array?
+
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+ v = partial.length === 0 ? '[]' :
+ gap ? '[\n' + gap +
+ partial.join(',\n' + gap) + '\n' +
+ mind + ']' :
+ '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ k = rep[i];
+ if (typeof k === 'string') {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+ v = partial.length === 0 ? '{}' :
+ gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+ mind + '}' : '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+ if (typeof $.jqplot.JSON.stringify !== 'function') {
+ $.jqplot.JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('$.jqplot.JSON.stringify');
+ }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+ return str('', {'': value});
+ };
+ }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+ if (typeof $.jqplot.JSON.parse !== 'function') {
+ $.jqplot.JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+ text = String(text);
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function' ?
+ walk({'': j}, '') : j;
+ }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('$.jqplot.JSON.parse');
+ };
+ }
+})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.logAxisRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.logAxisRenderer.js
new file mode 100644
index 00000000..8d358ec7
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.logAxisRenderer.js
@@ -0,0 +1,529 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * class: $.jqplot.LogAxisRenderer
+ * A plugin for a jqPlot to render a logarithmic axis.
+ *
+ * To use this renderer, include the plugin in your source
+ * > <script type="text/javascript" language="javascript" src="plugins/jqplot.logAxisRenderer.js"></script>
+ *
+ * and supply the appropriate options to your plot
+ *
+ * > {axes:{xaxis:{renderer:$.jqplot.LogAxisRenderer}}}
+ **/
+ $.jqplot.LogAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ // prop: axisDefaults
+ // Default properties which will be applied directly to the series.
+ //
+ // Group: Properties
+ //
+ // Properties
+ //
+ // base - the logarithmic base, commonly 2, 10 or Math.E
+ // tickDistribution - Deprecated. "power" distribution of ticks
+ // always used. Option has no effect.
+ this.axisDefaults = {
+ base : 10,
+ tickDistribution :'power'
+ };
+ };
+
+ $.jqplot.LogAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.LogAxisRenderer.prototype.constructor = $.jqplot.LogAxisRenderer;
+
+ $.jqplot.LogAxisRenderer.prototype.init = function(options) {
+ // prop: drawBaseline
+ // True to draw the axis baseline.
+ this.drawBaseline = true;
+ // prop: minorTicks
+ // Number of ticks to add between "major" ticks.
+ // Major ticks are ticks supplied by user or auto computed.
+ // Minor ticks cannot be created by user.
+ this.minorTicks = 'auto';
+ this._scalefact = 1.0;
+
+ $.extend(true, this, options);
+
+ this._autoFormatString = '%d';
+ this._overrideFormatString = false;
+
+ for (var d in this.renderer.axisDefaults) {
+ if (this[d] == null) {
+ this[d] = this.renderer.axisDefaults[d];
+ }
+ }
+
+ this.resetDataBounds();
+ };
+
+ $.jqplot.LogAxisRenderer.prototype.createTicks = function(plot) {
+ // we're are operating on an axis here
+ var ticks = this._ticks;
+ var userTicks = this.ticks;
+ var name = this.name;
+ var db = this._dataBounds;
+ var dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height;
+ var interval;
+ var min, max;
+ var pos1, pos2;
+ var tt, i;
+
+ var threshold = 30;
+ // For some reason scalefactor is screwing up ticks.
+ this._scalefact = (Math.max(dim, threshold+1) - threshold)/300;
+
+ // if we already have ticks, use them.
+ // ticks must be in order of increasing value.
+ if (userTicks.length) {
+ // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
+ for (i=0; i<userTicks.length; i++){
+ var ut = userTicks[i];
+ var t = new this.tickRenderer(this.tickOptions);
+ if (ut.constructor == Array) {
+ t.value = ut[0];
+ t.label = ut[1];
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(ut[0], this.name);
+ this._ticks.push(t);
+ }
+
+ else if ($.isPlainObject(ut)) {
+ $.extend(true, t, ut);
+ t.axis = this.name;
+ this._ticks.push(t);
+ }
+
+ else {
+ t.value = ut;
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(ut, this.name);
+ this._ticks.push(t);
+ }
+ }
+ this.numberTicks = userTicks.length;
+ this.min = this._ticks[0].value;
+ this.max = this._ticks[this.numberTicks-1].value;
+ }
+
+ // we don't have any ticks yet, let's make some!
+ else if (this.min == null && this.max == null) {
+ min = db.min * (2 - this.padMin);
+ max = db.max * this.padMax;
+
+ // if min and max are same, space them out a bit
+ if (min == max) {
+ var adj = 0.05;
+ min = min*(1-adj);
+ max = max*(1+adj);
+ }
+
+ // perform some checks
+ if (this.min != null && this.min <= 0) {
+ throw('log axis minimum must be greater than 0');
+ }
+ if (this.max != null && this.max <= 0) {
+ throw('log axis maximum must be greater than 0');
+ }
+
+ function findCeil (val) {
+ var order = Math.pow(10, Math.floor(Math.log(val)/Math.LN10));
+ return Math.ceil(val/order) * order;
+ }
+
+ function findFloor(val) {
+ var order = Math.pow(10, Math.floor(Math.log(val)/Math.LN10));
+ return Math.floor(val/order) * order;
+ }
+
+ // var range = max - min;
+ var rmin, rmax;
+
+ // for power distribution, open up range to get a nice power of axis.renderer.base.
+ // power distribution won't respect the user's min/max settings.
+ rmin = Math.pow(this.base, Math.floor(Math.log(min)/Math.log(this.base)));
+ rmax = Math.pow(this.base, Math.ceil(Math.log(max)/Math.log(this.base)));
+
+ // // if min and max are same, space them out a bit
+ // if (rmin === rmax) {
+ // var adj = 0.05;
+ // rmin = rmin*(1-adj);
+ // rmax = rmax*(1+adj);
+ // }
+
+ var order = Math.round(Math.log(rmin)/Math.LN10);
+
+ if (this.tickOptions == null || !this.tickOptions.formatString) {
+ this._overrideFormatString = true;
+ }
+
+ this.min = rmin;
+ this.max = rmax;
+ var range = this.max - this.min;
+
+ var minorTicks = (this.minorTicks === 'auto') ? 0 : this.minorTicks;
+ var numberTicks;
+ if (this.numberTicks == null){
+ if (dim > 140) {
+ numberTicks = Math.round(Math.log(this.max/this.min)/Math.log(this.base) + 1);
+ if (numberTicks < 2) {
+ numberTicks = 2;
+ }
+ if (minorTicks === 0) {
+ var temp = dim/(numberTicks - 1);
+ if (temp < 100) {
+ minorTicks = 0;
+ }
+ else if (temp < 190) {
+ minorTicks = 1;
+ }
+ else if (temp < 250) {
+ minorTicks = 3;
+ }
+ else if (temp < 600) {
+ minorTicks = 4;
+ }
+ else {
+ minorTicks = 9;
+ }
+ }
+ }
+ else {
+ numberTicks = 2;
+ if (minorTicks === 0) {
+ minorTicks = 1;
+ }
+ minorTicks = 0;
+ }
+ }
+ else {
+ numberTicks = this.numberTicks;
+ }
+
+ if (order >= 0 && minorTicks !== 3) {
+ this._autoFormatString = '%d';
+ }
+ // Adjust format string for case with 3 ticks where we'll have like 1, 2.5, 5, 7.5, 10
+ else if (order <= 0 && minorTicks === 3) {
+ var temp = -(order - 1);
+ this._autoFormatString = '%.'+ Math.abs(order-1) + 'f';
+ }
+
+ // Adjust format string for values less than 1.
+ else if (order < 0) {
+ var temp = -order;
+ this._autoFormatString = '%.'+ Math.abs(order) + 'f';
+ }
+
+ else {
+ this._autoFormatString = '%d';
+ }
+
+ var to, t, val, tt1, spread, interval;
+ for (var i=0; i<numberTicks; i++){
+ tt = Math.pow(this.base, i - numberTicks + 1) * this.max;
+
+ t = new this.tickRenderer(this.tickOptions);
+
+ if (this._overrideFormatString) {
+ t.formatString = this._autoFormatString;
+ }
+
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+
+ if (minorTicks && i<numberTicks-1) {
+ tt1 = Math.pow(this.base, i - numberTicks + 2) * this.max;
+ spread = tt1 - tt;
+ interval = tt1 / (minorTicks+1);
+ for (var j=minorTicks-1; j>=0; j--) {
+ val = tt1-interval*(j+1);
+ t = new this.tickRenderer(this.tickOptions);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(val, this.name);
+ this._ticks.push(t);
+ }
+ }
+ }
+ }
+
+ // min and max are set as would be the case with zooming
+ else if (this.min != null && this.max != null) {
+ var opts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null});
+ var nt, ti;
+ // don't have an interval yet, pick one that gives the most
+ // "round" ticks we can get.
+ if (this.numberTicks == null && this.tickInterval == null) {
+ // var threshold = 30;
+ var tdim = Math.max(dim, threshold+1);
+ var nttarget = Math.ceil((tdim-threshold)/35 + 1);
+
+ var ret = $.jqplot.LinearTickGenerator.bestConstrainedInterval(this.min, this.max, nttarget);
+
+ this._autoFormatString = ret[3];
+ nt = ret[2];
+ ti = ret[4];
+
+ for (var i=0; i<nt; i++) {
+ opts.value = this.min + i * ti;
+ t = new this.tickRenderer(opts);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ this._ticks.push(t);
+ }
+ }
+
+ // for loose zoom, number ticks and interval are also set.
+ else if (this.numberTicks != null && this.tickInterval != null) {
+ nt = this.numberTicks;
+ for (var i=0; i<nt; i++) {
+ opts.value = this.min + i * this.tickInterval;
+ t = new this.tickRenderer(opts);
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ t.formatString = this._autoFormatString;
+ }
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ this._ticks.push(t);
+ }
+ }
+ }
+ };
+
+ $.jqplot.LogAxisRenderer.prototype.pack = function(pos, offsets) {
+ var lb = parseInt(this.base, 10);
+ var ticks = this._ticks;
+ var trans = function (v) { return Math.log(v)/Math.log(lb); };
+ var invtrans = function (v) { return Math.pow(Math.E, (Math.log(lb)*v)); };
+ var max = trans(this.max);
+ var min = trans(this.min);
+ var offmax = offsets.max;
+ var offmin = offsets.min;
+ var lshow = (this._label == null) ? false : this._label.show;
+
+ for (var p in pos) {
+ this._elem.css(p, pos[p]);
+ }
+
+ this._offsets = offsets;
+ // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
+ var pixellength = offmax - offmin;
+ var unitlength = max - min;
+
+ // point to unit and unit to point conversions references to Plot DOM element top left corner.
+ this.p2u = function(p){
+ return invtrans((p - offmin) * unitlength / pixellength + min);
+ };
+
+ this.u2p = function(u){
+ return (trans(u) - min) * pixellength / unitlength + offmin;
+ };
+
+ if (this.name == 'xaxis' || this.name == 'x2axis'){
+ this.series_u2p = function(u){
+ return (trans(u) - min) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return invtrans(p * unitlength / pixellength + min);
+ };
+ }
+ // yaxis is max at top of canvas.
+ else {
+ this.series_u2p = function(u){
+ return (trans(u) - max) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return invtrans(p * unitlength / pixellength + max);
+ };
+ }
+
+ if (this.show) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ if (t.angle < 0) {
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ }
+ // position at start
+ else {
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'end':
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ case 'start':
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ break;
+ case 'middle':
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ default:
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getWidth()/2;
+ }
+ // var shim = t.getWidth()/2;
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('left', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var w = this._label._elem.outerWidth(true);
+ this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
+ if (this.name == 'xaxis') {
+ this._label._elem.css('bottom', '0px');
+ }
+ else {
+ this._label._elem.css('top', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ else {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ case 'end':
+ if (t.angle < 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'start':
+ if (t.angle > 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'middle':
+ // if (t.angle > 0) {
+ // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ // }
+ // else {
+ // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ // }
+ shim = -t.getHeight()/2;
+ break;
+ default:
+ shim = -t.getHeight()/2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getHeight()/2;
+ }
+
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('top', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var h = this._label._elem.outerHeight(true);
+ this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
+ if (this.name == 'yaxis') {
+ this._label._elem.css('left', '0px');
+ }
+ else {
+ this._label._elem.css('right', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ }
+ };
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoAxisRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoAxisRenderer.js
new file mode 100644
index 00000000..694de41d
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoAxisRenderer.js
@@ -0,0 +1,611 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ // class: $.jqplot.MekkoAxisRenderer
+ // An axis renderer for a Mekko chart.
+ // Should be used with a Mekko chart where the mekkoRenderer is used on the series.
+ // Displays the Y axis as a range from 0 to 1 (0 to 100%) and the x axis with a tick
+ // for each series scaled to the sum of all the y values.
+ $.jqplot.MekkoAxisRenderer = function() {
+ };
+
+ // called with scope of axis object.
+ $.jqplot.MekkoAxisRenderer.prototype.init = function(options){
+ // prop: tickMode
+ // How to space the ticks on the axis.
+ // 'bar' will place a tick at the width of each bar.
+ // This is the default for the x axis.
+ // 'even' will place ticks at even intervals. This is
+ // the default for x2 axis and y axis. y axis cannot be changed.
+ this.tickMode;
+ // prop: barLabelRenderer
+ // renderer to use to draw labels under each bar.
+ this.barLabelRenderer = $.jqplot.AxisLabelRenderer;
+ // prop: barLabels
+ // array of labels to put under each bar.
+ this.barLabels = this.barLabels || [];
+ // prop: barLabelOptions
+ // options object to pass to the bar label renderer.
+ this.barLabelOptions = {};
+ this.tickOptions = $.extend(true, {showGridline:false}, this.tickOptions);
+ this._barLabels = [];
+ $.extend(true, this, options);
+ if (this.name == 'yaxis') {
+ this.tickOptions.formatString = this.tickOptions.formatString || "%d\%";
+ }
+ var db = this._dataBounds;
+ db.min = 0;
+ // for y axes, scale always go from 0 to 1 (0 to 100%)
+ if (this.name == 'yaxis' || this.name == 'y2axis') {
+ db.max = 100;
+ this.tickMode = 'even';
+ }
+ // For x axes, scale goes from 0 to sum of all y values.
+ else if (this.name == 'xaxis'){
+ this.tickMode = (this.tickMode == null) ? 'bar' : this.tickMode;
+ for (var i=0; i<this._series.length; i++) {
+ db.max += this._series[i]._sumy;
+ }
+ }
+ else if (this.name == 'x2axis'){
+ this.tickMode = (this.tickMode == null) ? 'even' : this.tickMode;
+ for (var i=0; i<this._series.length; i++) {
+ db.max += this._series[i]._sumy;
+ }
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.MekkoAxisRenderer.prototype.draw = function(ctx, plot) {
+ if (this.show) {
+ // populate the axis label and value properties.
+ // createTicks is a method on the renderer, but
+ // call it within the scope of the axis.
+ this.renderer.createTicks.call(this);
+ // fill a div with axes labels in the right direction.
+ // Need to pregenerate each axis to get it's bounds and
+ // position it and the labels correctly on the plot.
+ var dim=0;
+ var temp;
+
+ var elem = document.createElement('div');
+ this._elem = $(elem);
+ this._elem.addClass('jqplot-axis jqplot-'+this.name);
+ this._elem.css('position', 'absolute');
+ elem = null;
+
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ this._elem.width(this._plotDimensions.width);
+ }
+ else {
+ this._elem.height(this._plotDimensions.height);
+ }
+
+ // draw the axis label
+ // create a _label object.
+ this.labelOptions.axis = this.name;
+ this._label = new this.labelRenderer(this.labelOptions);
+ if (this._label.show) {
+ this._elem.append(this._label.draw(ctx));
+ }
+
+ var t, tick, elem;
+ if (this.showTicks) {
+ t = this._ticks;
+ for (var i=0; i<t.length; i++) {
+ tick = t[i];
+ if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
+ this._elem.append(tick.draw(ctx));
+ }
+ }
+ }
+
+ // draw the series labels
+ for (i=0; i<this.barLabels.length; i++) {
+ this.barLabelOptions.axis = this.name;
+ this.barLabelOptions.label = this.barLabels[i];
+ this._barLabels.push(new this.barLabelRenderer(this.barLabelOptions));
+ if (this.tickMode != 'bar') {
+ this._barLabels[i].show = false;
+ }
+ if (this._barLabels[i].show) {
+ var elem = this._barLabels[i].draw(ctx, plot);
+ elem.removeClass('jqplot-'+this.name+'-label');
+ elem.addClass('jqplot-'+this.name+'-tick');
+ elem.addClass('jqplot-mekko-barLabel');
+ elem.appendTo(this._elem);
+ elem = null;
+ }
+ }
+
+ }
+ return this._elem;
+ };
+
+ // called with scope of an axis
+ $.jqplot.MekkoAxisRenderer.prototype.reset = function() {
+ this.min = this._min;
+ this.max = this._max;
+ this.tickInterval = this._tickInterval;
+ this.numberTicks = this._numberTicks;
+ // this._ticks = this.__ticks;
+ };
+
+ // called with scope of axis
+ $.jqplot.MekkoAxisRenderer.prototype.set = function() {
+ var dim = 0;
+ var temp;
+ var w = 0;
+ var h = 0;
+ var lshow = (this._label == null) ? false : this._label.show;
+ if (this.show && this.showTicks) {
+ var t = this._ticks;
+ for (var i=0; i<t.length; i++) {
+ var tick = t[i];
+ if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ temp = tick._elem.outerHeight(true);
+ }
+ else {
+ temp = tick._elem.outerWidth(true);
+ }
+ if (temp > dim) {
+ dim = temp;
+ }
+ }
+ }
+
+ if (lshow) {
+ w = this._label._elem.outerWidth(true);
+ h = this._label._elem.outerHeight(true);
+ }
+ if (this.name == 'xaxis') {
+ dim = dim + h;
+ this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});
+ }
+ else if (this.name == 'x2axis') {
+ dim = dim + h;
+ this._elem.css({'height':dim+'px', left:'0px', top:'0px'});
+ }
+ else if (this.name == 'yaxis') {
+ dim = dim + w;
+ this._elem.css({'width':dim+'px', left:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ else {
+ dim = dim + w;
+ this._elem.css({'width':dim+'px', right:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.MekkoAxisRenderer.prototype.createTicks = function() {
+ // we're are operating on an axis here
+ var ticks = this._ticks;
+ var userTicks = this.ticks;
+ var name = this.name;
+ // databounds were set on axis initialization.
+ var db = this._dataBounds;
+ var dim, interval;
+ var min, max;
+ var pos1, pos2;
+ var t, tt, i, j;
+
+ // if we already have ticks, use them.
+ // ticks must be in order of increasing value.
+
+ if (userTicks.length) {
+ // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
+ for (i=0; i<userTicks.length; i++){
+ var ut = userTicks[i];
+ var t = new this.tickRenderer(this.tickOptions);
+ if (ut.constructor == Array) {
+ t.value = ut[0];
+ t.label = ut[1];
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(ut[0], this.name);
+ this._ticks.push(t);
+ }
+
+ else {
+ t.value = ut;
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(ut, this.name);
+ this._ticks.push(t);
+ }
+ }
+ this.numberTicks = userTicks.length;
+ this.min = this._ticks[0].value;
+ this.max = this._ticks[this.numberTicks-1].value;
+ this.tickInterval = (this.max - this.min) / (this.numberTicks - 1);
+ }
+
+ // we don't have any ticks yet, let's make some!
+ else {
+ if (name == 'xaxis' || name == 'x2axis') {
+ dim = this._plotDimensions.width;
+ }
+ else {
+ dim = this._plotDimensions.height;
+ }
+
+ // if min, max and number of ticks specified, user can't specify interval.
+ if (this.min != null && this.max != null && this.numberTicks != null) {
+ this.tickInterval = null;
+ }
+
+ min = (this.min != null) ? this.min : db.min;
+ max = (this.max != null) ? this.max : db.max;
+
+ // if min and max are same, space them out a bit.+
+ if (min == max) {
+ var adj = 0.05;
+ if (min > 0) {
+ adj = Math.max(Math.log(min)/Math.LN10, 0.05);
+ }
+ min -= adj;
+ max += adj;
+ }
+
+ var range = max - min;
+ var rmin, rmax;
+ var temp, prev, curr;
+ var ynumticks = [3,5,6,11,21];
+
+ // yaxis divide ticks in nice intervals from 0 to 1.
+ if (this.name == 'yaxis' || this.name == 'y2axis') {
+ this.min = 0;
+ this.max = 100;
+ // user didn't specify number of ticks.
+ if (!this.numberTicks){
+ if (this.tickInterval) {
+ this.numberTicks = 3 + Math.ceil(range / this.tickInterval);
+ }
+ else {
+ temp = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
+ for (i=0; i<ynumticks.length; i++) {
+ curr = temp/ynumticks[i];
+ if (curr == 1) {
+ this.numberTicks = ynumticks[i];
+ break;
+ }
+ else if (curr > 1) {
+ prev = curr;
+ continue;
+ }
+ else if (curr < 1) {
+ // was prev or is curr closer to one?
+ if (Math.abs(prev - 1) < Math.abs(curr - 1)) {
+ this.numberTicks = ynumticks[i-1];
+ break;
+ }
+ else {
+ this.numberTicks = ynumticks[i];
+ break;
+ }
+ }
+ else if (i == ynumticks.length -1) {
+ this.numberTicks = ynumticks[i];
+ }
+ }
+ this.tickInterval = range / (this.numberTicks - 1);
+ }
+ }
+
+ // user did specify number of ticks.
+ else {
+ this.tickInterval = range / (this.numberTicks - 1);
+ }
+
+ for (var i=0; i<this.numberTicks; i++){
+ tt = this.min + i * this.tickInterval;
+ t = new this.tickRenderer(this.tickOptions);
+ // var t = new $.jqplot.AxisTickRenderer(this.tickOptions);
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+ }
+ }
+
+ // for x axes, have number ot ticks equal to number of series and ticks placed
+ // at sum of y values for each series.
+ else if (this.tickMode == 'bar') {
+ this.min = 0;
+ this.numberTicks = this._series.length + 1;
+ t = new this.tickRenderer(this.tickOptions);
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(0, this.name);
+ this._ticks.push(t);
+
+ temp = 0;
+
+ for (i=1; i<this.numberTicks; i++){
+ temp += this._series[i-1]._sumy;
+ t = new this.tickRenderer(this.tickOptions);
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(temp, this.name);
+ this._ticks.push(t);
+ }
+ this.max = this.max || temp;
+
+ // if user specified a max and it is greater than sum, add a tick
+ if (this.max > temp) {
+ t = new this.tickRenderer(this.tickOptions);
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(this.max, this.name);
+ this._ticks.push(t);
+
+ }
+ }
+
+ else if (this.tickMode == 'even') {
+ this.min = 0;
+ this.max = this.max || db.max;
+ // get a desired number of ticks
+ var nt = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
+ range = this.max - this.min;
+ this.numberTicks = nt;
+ this.tickInterval = range / (this.numberTicks - 1);
+
+ for (i=0; i<this.numberTicks; i++){
+ tt = this.min + i * this.tickInterval;
+ t = new this.tickRenderer(this.tickOptions);
+ // var t = new $.jqplot.AxisTickRenderer(this.tickOptions);
+ if (!this.showTicks) {
+ t.showLabel = false;
+ t.showMark = false;
+ }
+ else if (!this.showTickMarks) {
+ t.showMark = false;
+ }
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+ }
+
+ }
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.MekkoAxisRenderer.prototype.pack = function(pos, offsets) {
+ var ticks = this._ticks;
+ var max = this.max;
+ var min = this.min;
+ var offmax = offsets.max;
+ var offmin = offsets.min;
+ var lshow = (this._label == null) ? false : this._label.show;
+
+ for (var p in pos) {
+ this._elem.css(p, pos[p]);
+ }
+
+ this._offsets = offsets;
+ // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
+ var pixellength = offmax - offmin;
+ var unitlength = max - min;
+
+ // point to unit and unit to point conversions references to Plot DOM element top left corner.
+ this.p2u = function(p){
+ return (p - offmin) * unitlength / pixellength + min;
+ };
+
+ this.u2p = function(u){
+ return (u - min) * pixellength / unitlength + offmin;
+ };
+
+ if (this.name == 'xaxis' || this.name == 'x2axis'){
+ this.series_u2p = function(u){
+ return (u - min) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+
+ else {
+ this.series_u2p = function(u){
+ return (u - max) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + max;
+ };
+ }
+
+ if (this.show) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'xaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ if (temp * t.angle < 0) {
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ }
+ // position at start
+ else {
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'end':
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ case 'start':
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ break;
+ case 'middle':
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ default:
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getWidth()/2;
+ }
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('left', val);
+ t.pack();
+ }
+ }
+ var w;
+ if (lshow) {
+ w = this._label._elem.outerWidth(true);
+ this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
+ if (this.name == 'xaxis') {
+ this._label._elem.css('bottom', '0px');
+ }
+ else {
+ this._label._elem.css('top', '0px');
+ }
+ this._label.pack();
+ }
+ // now show the labels under the bars.
+ var b, l, r;
+ for (var i=0; i<this.barLabels.length; i++) {
+ b = this._barLabels[i];
+ if (b.show) {
+ w = b.getWidth();
+ l = this._ticks[i].getLeft() + this._ticks[i].getWidth();
+ r = this._ticks[i+1].getLeft();
+ b._elem.css('left', (r+l-w)/2+'px');
+ b._elem.css('top', this._ticks[i]._elem.css('top'));
+ b.pack();
+ }
+ }
+ }
+ else {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'yaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ case 'end':
+ if (temp * t.angle < 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'start':
+ if (t.angle > 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'middle':
+ shim = -t.getHeight()/2;
+ break;
+ default:
+ shim = -t.getHeight()/2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getHeight()/2;
+ }
+
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('top', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var h = this._label._elem.outerHeight(true);
+ this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
+ if (this.name == 'yaxis') {
+ this._label._elem.css('left', '0px');
+ }
+ else {
+ this._label._elem.css('right', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ }
+ };
+})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoRenderer.js
new file mode 100644
index 00000000..893e2b98
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.mekkoRenderer.js
@@ -0,0 +1,437 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.MekkoRenderer
+ * Draws a Mekko style chart which shows 3 dimensional data on a 2 dimensional graph.
+ * the <$.jqplot.MekkoAxisRenderer> should be used with mekko charts. The mekko renderer
+ * overrides the default legend renderer with it's own $.jqplot.MekkoLegendRenderer
+ * which allows more flexibility to specify number of rows and columns in the legend.
+ *
+ * Data is specified per bar in the chart. You can specify data as an array of y values, or as
+ * an array of [label, value] pairs. Note that labels are used only on the first series.
+ * Labels on subsequent series are ignored:
+ *
+ * > bar1 = [['shirts', 8],['hats', 14],['shoes', 6],['gloves', 16],['dolls', 12]];
+ * > bar2 = [15,6,9,13,6];
+ * > bar3 = [['grumpy',4],['sneezy',2],['happy',7],['sleepy',9],['doc',7]];
+ *
+ * If you want to place labels for each bar under the axis, you use the barLabels option on
+ * the axes. The bar labels can be styled with the ".jqplot-mekko-barLabel" css class.
+ *
+ * > barLabels = ['Mickey Mouse', 'Donald Duck', 'Goofy'];
+ * > axes:{xaxis:{barLabels:barLabels}}
+ *
+ */
+
+
+ $.jqplot.MekkoRenderer = function(){
+ this.shapeRenderer = new $.jqplot.ShapeRenderer();
+ // prop: borderColor
+ // color of the borders between areas on the chart
+ this.borderColor = null;
+ // prop: showBorders
+ // True to draw borders lines between areas on the chart.
+ // False will draw borders lines with the same color as the area.
+ this.showBorders = true;
+ };
+
+ // called with scope of series.
+ $.jqplot.MekkoRenderer.prototype.init = function(options, plot) {
+ this.fill = false;
+ this.fillRect = true;
+ this.strokeRect = true;
+ this.shadow = false;
+ // width of bar on x axis.
+ this._xwidth = 0;
+ this._xstart = 0;
+ $.extend(true, this.renderer, options);
+ // set the shape renderer options
+ var opts = {lineJoin:'miter', lineCap:'butt', isarc:false, fillRect:this.fillRect, strokeRect:this.strokeRect};
+ this.renderer.shapeRenderer.init(opts);
+ plot.axes.x2axis._series.push(this);
+ this._type = 'mekko';
+ };
+
+ // Method: setGridData
+ // converts the user data values to grid coordinates and stores them
+ // in the gridData array. Will convert user data into appropriate
+ // rectangles.
+ // Called with scope of a series.
+ $.jqplot.MekkoRenderer.prototype.setGridData = function(plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var data = this._plotData;
+ this.gridData = [];
+ // figure out width on x axis.
+ // this._xwidth = this._sumy / plot._sumy * this.canvas.getWidth();
+ this._xwidth = xp(this._sumy) - xp(0);
+ if (this.index>0) {
+ this._xstart = plot.series[this.index-1]._xstart + plot.series[this.index-1]._xwidth;
+ }
+ var totheight = this.canvas.getHeight();
+ var sumy = 0;
+ var cury;
+ var curheight;
+ for (var i=0; i<data.length; i++) {
+ if (data[i] != null) {
+ sumy += data[i][1];
+ cury = totheight - (sumy / this._sumy * totheight);
+ curheight = data[i][1] / this._sumy * totheight;
+ this.gridData.push([this._xstart, cury, this._xwidth, curheight]);
+ }
+ }
+ };
+
+ // Method: makeGridData
+ // converts any arbitrary data values to grid coordinates and
+ // returns them. This method exists so that plugins can use a series'
+ // linerenderer to generate grid data points without overwriting the
+ // grid data associated with that series.
+ // Called with scope of a series.
+ $.jqplot.MekkoRenderer.prototype.makeGridData = function(data, plot) {
+ // recalculate the grid data
+ // figure out width on x axis.
+ var xp = this._xaxis.series_u2p;
+ var totheight = this.canvas.getHeight();
+ var sumy = 0;
+ var cury;
+ var curheight;
+ var gd = [];
+ for (var i=0; i<data.length; i++) {
+ if (data[i] != null) {
+ sumy += data[i][1];
+ cury = totheight - (sumy / this._sumy * totheight);
+ curheight = data[i][1] / this._sumy * totheight;
+ gd.push([this._xstart, cury, this._xwidth, curheight]);
+ }
+ }
+ return gd;
+ };
+
+
+ // called within scope of series.
+ $.jqplot.MekkoRenderer.prototype.draw = function(ctx, gd, options) {
+ var i;
+ var opts = (options != undefined) ? options : {};
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
+ ctx.save();
+ if (gd.length) {
+ if (showLine) {
+ for (i=0; i<gd.length; i++){
+ opts.fillStyle = colorGenerator.next();
+ if (this.renderer.showBorders) {
+ opts.strokeStyle = this.renderer.borderColor;
+ }
+ else {
+ opts.strokeStyle = opts.fillStyle;
+ }
+ this.renderer.shapeRenderer.draw(ctx, gd[i], opts);
+ }
+ }
+ }
+
+ ctx.restore();
+ };
+
+ $.jqplot.MekkoRenderer.prototype.drawShadow = function(ctx, gd, options) {
+ // This is a no-op, no shadows on mekko charts.
+ };
+
+ /**
+ * Class: $.jqplot.MekkoLegendRenderer
+ * Legend renderer used by mekko charts with options for
+ * controlling number or rows and columns as well as placement
+ * outside of plot area.
+ *
+ */
+ $.jqplot.MekkoLegendRenderer = function(){
+ //
+ };
+
+ $.jqplot.MekkoLegendRenderer.prototype.init = function(options) {
+ // prop: numberRows
+ // Maximum number of rows in the legend. 0 or null for unlimited.
+ this.numberRows = null;
+ // prop: numberColumns
+ // Maximum number of columns in the legend. 0 or null for unlimited.
+ this.numberColumns = null;
+ // this will override the placement option on the Legend object
+ this.placement = "outside";
+ $.extend(true, this, options);
+ };
+
+ // called with scope of legend
+ $.jqplot.MekkoLegendRenderer.prototype.draw = function() {
+ var legend = this;
+ if (this.show) {
+ var series = this._series;
+ var ss = 'position:absolute;';
+ ss += (this.background) ? 'background:'+this.background+';' : '';
+ ss += (this.border) ? 'border:'+this.border+';' : '';
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
+ // Mekko charts legends don't go by number of series, but by number of data points
+ // in the series. Refactor things here for that.
+
+ var pad = false,
+ reverse = true, // mekko charts are always stacked, so reverse
+ nr, nc;
+ var s = series[0];
+ var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
+
+ if (s.show) {
+ var pd = s.data;
+ if (this.numberRows) {
+ nr = this.numberRows;
+ if (!this.numberColumns){
+ nc = Math.ceil(pd.length/nr);
+ }
+ else{
+ nc = this.numberColumns;
+ }
+ }
+ else if (this.numberColumns) {
+ nc = this.numberColumns;
+ nr = Math.ceil(pd.length/this.numberColumns);
+ }
+ else {
+ nr = pd.length;
+ nc = 1;
+ }
+
+ var i, j, tr, td1, td2, lt, rs, color;
+ var idx = 0;
+
+ for (i=0; i<nr; i++) {
+ if (reverse){
+ tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
+ }
+ else{
+ tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
+ }
+ for (j=0; j<nc; j++) {
+ if (idx < pd.length) {
+ lt = this.labels[idx] || pd[idx][0].toString();
+ color = colorGenerator.next();
+ if (!reverse){
+ if (i>0){
+ pad = true;
+ }
+ else{
+ pad = false;
+ }
+ }
+ else{
+ if (i == nr -1){
+ pad = false;
+ }
+ else{
+ pad = true;
+ }
+ }
+ rs = (pad) ? this.rowSpacing : '0';
+
+ td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
+ '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
+ '</div></td>');
+ td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
+ if (this.escapeHtml){
+ td2.text(lt);
+ }
+ else {
+ td2.html(lt);
+ }
+ if (reverse) {
+ td2.prependTo(tr);
+ td1.prependTo(tr);
+ }
+ else {
+ td1.appendTo(tr);
+ td2.appendTo(tr);
+ }
+ pad = true;
+ }
+ idx++;
+ }
+ }
+
+ tr = null;
+ td1 = null;
+ td2 = null;
+ }
+ }
+ return this._elem;
+ };
+
+ $.jqplot.MekkoLegendRenderer.prototype.pack = function(offsets) {
+ if (this.show) {
+ // fake a grid for positioning
+ var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};
+ if (this.placement == 'insideGrid') {
+ switch (this.location) {
+ case 'nw':
+ var a = grid._left + this.xoffset;
+ var b = grid._top + this.yoffset;
+ this._elem.css('left', a);
+ this._elem.css('top', b);
+ break;
+ case 'n':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = grid._top + this.yoffset;
+ this._elem.css('left', a);
+ this._elem.css('top', b);
+ break;
+ case 'ne':
+ var a = offsets.right + this.xoffset;
+ var b = grid._top + this.yoffset;
+ this._elem.css({right:a, top:b});
+ break;
+ case 'e':
+ var a = offsets.right + this.xoffset;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({right:a, top:b});
+ break;
+ case 'se':
+ var a = offsets.right + this.xoffset;
+ var b = offsets.bottom + this.yoffset;
+ this._elem.css({right:a, bottom:b});
+ break;
+ case 's':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = offsets.bottom + this.yoffset;
+ this._elem.css({left:a, bottom:b});
+ break;
+ case 'sw':
+ var a = grid._left + this.xoffset;
+ var b = offsets.bottom + this.yoffset;
+ this._elem.css({left:a, bottom:b});
+ break;
+ case 'w':
+ var a = grid._left + this.xoffset;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({left:a, top:b});
+ break;
+ default: // same as 'se'
+ var a = grid._right - this.xoffset;
+ var b = grid._bottom + this.yoffset;
+ this._elem.css({right:a, bottom:b});
+ break;
+ }
+
+ }
+ else {
+ switch (this.location) {
+ case 'nw':
+ var a = this._plotDimensions.width - grid._left + this.xoffset;
+ var b = grid._top + this.yoffset;
+ this._elem.css('right', a);
+ this._elem.css('top', b);
+ break;
+ case 'n':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = this._plotDimensions.height - grid._top + this.yoffset;
+ this._elem.css('left', a);
+ this._elem.css('bottom', b);
+ break;
+ case 'ne':
+ var a = this._plotDimensions.width - offsets.right + this.xoffset;
+ var b = grid._top + this.yoffset;
+ this._elem.css({left:a, top:b});
+ break;
+ case 'e':
+ var a = this._plotDimensions.width - offsets.right + this.xoffset;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({left:a, top:b});
+ break;
+ case 'se':
+ var a = this._plotDimensions.width - offsets.right + this.xoffset;
+ var b = offsets.bottom + this.yoffset;
+ this._elem.css({left:a, bottom:b});
+ break;
+ case 's':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = this._plotDimensions.height - offsets.bottom + this.yoffset;
+ this._elem.css({left:a, top:b});
+ break;
+ case 'sw':
+ var a = this._plotDimensions.width - grid._left + this.xoffset;
+ var b = offsets.bottom + this.yoffset;
+ this._elem.css({right:a, bottom:b});
+ break;
+ case 'w':
+ var a = this._plotDimensions.width - grid._left + this.xoffset;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({right:a, top:b});
+ break;
+ default: // same as 'se'
+ var a = grid._right - this.xoffset;
+ var b = grid._bottom + this.yoffset;
+ this._elem.css({right:a, bottom:b});
+ break;
+ }
+ }
+ }
+ };
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.legend = options.legend || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.MekkoRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.MekkoRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.MekkoAxisRenderer;
+ options.legend.renderer = $.jqplot.MekkoLegendRenderer;
+ options.legend.preDraw = true;
+ }
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.meterGaugeRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.meterGaugeRenderer.js
new file mode 100644
index 00000000..10a40949
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.meterGaugeRenderer.js
@@ -0,0 +1,1030 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.MeterGaugeRenderer
+ * Plugin renderer to draw a meter gauge chart.
+ *
+ * Data consists of a single series with 1 data point to position the gauge needle.
+ *
+ * To use this renderer, you need to include the
+ * meter gauge renderer plugin, for example:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.meterGaugeRenderer.js"></script>
+ *
+ * Properties described here are passed into the $.jqplot function
+ * as options on the series renderer. For example:
+ *
+ * > plot0 = $.jqplot('chart0',[[18]],{
+ * > title: 'Network Speed',
+ * > seriesDefaults: {
+ * > renderer: $.jqplot.MeterGaugeRenderer,
+ * > rendererOptions: {
+ * > label: 'MB/s'
+ * > }
+ * > }
+ * > });
+ *
+ * A meterGauge plot does not support events.
+ */
+ $.jqplot.MeterGaugeRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.MeterGaugeRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.MeterGaugeRenderer.prototype.constructor = $.jqplot.MeterGaugeRenderer;
+
+ // called with scope of a series
+ $.jqplot.MeterGaugeRenderer.prototype.init = function(options) {
+ // Group: Properties
+ //
+ // prop: diameter
+ // Outer diameter of the meterGauge, auto computed by default
+ this.diameter = null;
+ // prop: padding
+ // padding between the meterGauge and plot edges, auto
+ // calculated by default.
+ this.padding = null;
+ // prop: shadowOffset
+ // offset of the shadow from the gauge ring and offset of
+ // each succesive stroke of the shadow from the last.
+ this.shadowOffset = 2;
+ // prop: shadowAlpha
+ // transparency of the shadow (0 = transparent, 1 = opaque)
+ this.shadowAlpha = 0.07;
+ // prop: shadowDepth
+ // number of strokes to apply to the shadow,
+ // each stroke offset shadowOffset from the last.
+ this.shadowDepth = 4;
+ // prop: background
+ // background color of the inside of the gauge.
+ this.background = "#efefef";
+ // prop: ringColor
+ // color of the outer ring, hub, and needle of the gauge.
+ this.ringColor = "#BBC6D0";
+ // needle color not implemented yet.
+ this.needleColor = "#C3D3E5";
+ // prop: tickColor
+ // color of the tick marks around the gauge.
+ this.tickColor = "989898";
+ // prop: ringWidth
+ // width of the ring around the gauge. Auto computed by default.
+ this.ringWidth = null;
+ // prop: min
+ // Minimum value on the gauge. Auto computed by default
+ this.min;
+ // prop: max
+ // Maximum value on the gauge. Auto computed by default
+ this.max;
+ // prop: ticks
+ // Array of tick values. Auto computed by default.
+ this.ticks = [];
+ // prop: showTicks
+ // true to show ticks around gauge.
+ this.showTicks = true;
+ // prop: showTickLabels
+ // true to show tick labels next to ticks.
+ this.showTickLabels = true;
+ // prop: label
+ // A gauge label like 'kph' or 'Volts'
+ this.label = null;
+ // prop: labelHeightAdjust
+ // Number of Pixels to offset the label up (-) or down (+) from its default position.
+ this.labelHeightAdjust = 0;
+ // prop: labelPosition
+ // Where to position the label, either 'inside' or 'bottom'.
+ this.labelPosition = 'inside';
+ // prop: intervals
+ // Array of ranges to be drawn around the gauge.
+ // Array of form:
+ // > [value1, value2, ...]
+ // indicating the values for the first, second, ... intervals.
+ this.intervals = [];
+ // prop: intervalColors
+ // Array of colors to use for the intervals.
+ this.intervalColors = [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"];
+ // prop: intervalInnerRadius
+ // Radius of the inner circle of the interval ring.
+ this.intervalInnerRadius = null;
+ // prop: intervalOuterRadius
+ // Radius of the outer circle of the interval ring.
+ this.intervalOuterRadius = null;
+ this.tickRenderer = $.jqplot.MeterGaugeTickRenderer;
+ // ticks spaced every 1, 2, 2.5, 5, 10, 20, .1, .2, .25, .5, etc.
+ this.tickPositions = [1, 2, 2.5, 5, 10];
+ // prop: tickSpacing
+ // Degrees between ticks. This is a target number, if
+ // incompatible span and ticks are supplied, a suitable
+ // spacing close to this value will be computed.
+ this.tickSpacing = 30;
+ this.numberMinorTicks = null;
+ // prop: hubRadius
+ // Radius of the hub at the bottom center of gauge which the needle attaches to.
+ // Auto computed by default
+ this.hubRadius = null;
+ // prop: tickPadding
+ // padding of the tick marks to the outer ring and the tick labels to marks.
+ // Auto computed by default.
+ this.tickPadding = null;
+ // prop: needleThickness
+ // Maximum thickness the needle. Auto computed by default.
+ this.needleThickness = null;
+ // prop: needlePad
+ // Padding between needle and inner edge of the ring when the needle is at the min or max gauge value.
+ this.needlePad = 6;
+ // prop: pegNeedle
+ // True will stop needle just below/above the min/max values if data is below/above min/max,
+ // as if the meter is "pegged".
+ this.pegNeedle = true;
+ this._type = 'meterGauge';
+
+ $.extend(true, this, options);
+ this.type = null;
+ this.numberTicks = null;
+ this.tickInterval = null;
+ // span, the sweep (in degrees) from min to max. This gauge is
+ // a semi-circle.
+ this.span = 180;
+ // get rid of this nonsense
+ // this.innerSpan = this.span;
+ if (this.type == 'circular') {
+ this.semiCircular = false;
+ }
+ else if (this.type != 'circular') {
+ this.semiCircular = true;
+ }
+ else {
+ this.semiCircular = (this.span <= 180) ? true : false;
+ }
+ this._tickPoints = [];
+ // reference to label element.
+ this._labelElem = null;
+
+ // start the gauge at the beginning of the span
+ this.startAngle = (90 + (360 - this.span)/2) * Math.PI/180;
+ this.endAngle = (90 - (360 - this.span)/2) * Math.PI/180;
+
+ this.setmin = !!(this.min == null);
+ this.setmax = !!(this.max == null);
+
+ // if given intervals and is an array of values, create labels and colors.
+ if (this.intervals.length) {
+ if (this.intervals[0].length == null || this.intervals.length == 1) {
+ for (var i=0; i<this.intervals.length; i++) {
+ this.intervals[i] = [this.intervals[i], this.intervals[i], this.intervalColors[i]];
+ }
+ }
+ else if (this.intervals[0].length == 2) {
+ for (i=0; i<this.intervals.length; i++) {
+ this.intervals[i] = [this.intervals[i][0], this.intervals[i][1], this.intervalColors[i]];
+ }
+ }
+ }
+
+ // compute min, max and ticks if not supplied:
+ if (this.ticks.length) {
+ if (this.ticks[0].length == null || this.ticks[0].length == 1) {
+ for (var i=0; i<this.ticks.length; i++) {
+ this.ticks[i] = [this.ticks[i], this.ticks[i]];
+ }
+ }
+ this.min = (this.min == null) ? this.ticks[0][0] : this.min;
+ this.max = (this.max == null) ? this.ticks[this.ticks.length-1][0] : this.max;
+ this.setmin = false;
+ this.setmax = false;
+ this.numberTicks = this.ticks.length;
+ this.tickInterval = this.ticks[1][0] - this.ticks[0][0];
+ this.tickFactor = Math.floor(parseFloat((Math.log(this.tickInterval)/Math.log(10)).toFixed(11)));
+ // use the first interal to calculate minor ticks;
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
+ if (!this.numberMinorTicks) {
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
+ }
+ if (!this.numberMinorTicks) {
+ this.numberMinorTicks = 1;
+ }
+ }
+
+ else if (this.intervals.length) {
+ this.min = (this.min == null) ? 0 : this.min;
+ this.setmin = false;
+ if (this.max == null) {
+ if (this.intervals[this.intervals.length-1][0] >= this.data[0][1]) {
+ this.max = this.intervals[this.intervals.length-1][0];
+ this.setmax = false;
+ }
+ }
+ else {
+ this.setmax = false;
+ }
+ }
+
+ else {
+ // no ticks and no intervals supplied, put needle in middle
+ this.min = (this.min == null) ? 0 : this.min;
+ this.setmin = false;
+ if (this.max == null) {
+ this.max = this.data[0][1] * 1.25;
+ this.setmax = true;
+ }
+ else {
+ this.setmax = false;
+ }
+ }
+ };
+
+ $.jqplot.MeterGaugeRenderer.prototype.setGridData = function(plot) {
+ // set gridData property. This will hold angle in radians of each data point.
+ var stack = [];
+ var td = [];
+ var sa = this.startAngle;
+ for (var i=0; i<this.data.length; i++){
+ stack.push(this.data[i][1]);
+ td.push([this.data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ }
+ this.gridData = td;
+ };
+
+ $.jqplot.MeterGaugeRenderer.prototype.makeGridData = function(data, plot) {
+ var stack = [];
+ var td = [];
+ var sa = this.startAngle;
+ for (var i=0; i<data.length; i++){
+ stack.push(data[i][1]);
+ td.push([data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ }
+ return td;
+ };
+
+
+ function getnmt(pos, interval, fact) {
+ var temp;
+ for (var i=pos.length-1; i>=0; i--) {
+ temp = interval/(pos[i] * Math.pow(10, fact));
+ if (temp == 4 || temp == 5) {
+ return temp - 1;
+ }
+ }
+ return null;
+ }
+
+ // called with scope of series
+ $.jqplot.MeterGaugeRenderer.prototype.draw = function (ctx, gd, options) {
+ var i;
+ var opts = (options != undefined) ? options : {};
+ // offset and direction of offset due to legend placement
+ var offx = 0;
+ var offy = 0;
+ var trans = 1;
+ if (options.legendInfo && options.legendInfo.placement == 'inside') {
+ var li = options.legendInfo;
+ switch (li.location) {
+ case 'nw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'w':
+ offx = li.width + li.xoffset;
+ break;
+ case 'sw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'ne':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'e':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'se':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'n':
+ offy = li.height + li.yoffset;
+ break;
+ case 's':
+ offy = li.height + li.yoffset;
+ trans = -1;
+ break;
+ default:
+ break;
+ }
+ }
+
+
+
+ // pre-draw so can get it's dimensions.
+ if (this.label) {
+ this._labelElem = $('<div class="jqplot-meterGauge-label" style="position:absolute;">'+this.label+'</div>');
+ this.canvas._elem.after(this._labelElem);
+ }
+
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var cw = ctx.canvas.width;
+ var ch = ctx.canvas.height;
+ if (this.padding == null) {
+ this.padding = Math.round(Math.min(cw, ch)/30);
+ }
+ var w = cw - offx - 2 * this.padding;
+ var h = ch - offy - 2 * this.padding;
+ if (this.labelPosition == 'bottom' && this.label) {
+ h -= this._labelElem.outerHeight(true);
+ }
+ var mindim = Math.min(w,h);
+ var d = mindim;
+
+ if (!this.diameter) {
+ if (this.semiCircular) {
+ if ( w >= 2*h) {
+ if (!this.ringWidth) {
+ this.ringWidth = 2*h/35;
+ }
+ this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8);
+ this.innerPad = this.ringWidth/2 + this.needleThickness/2 + this.needlePad;
+ this.diameter = 2 * (h - 2*this.innerPad);
+ }
+ else {
+ if (!this.ringWidth) {
+ this.ringWidth = w/35;
+ }
+ this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8);
+ this.innerPad = this.ringWidth/2 + this.needleThickness/2 + this.needlePad;
+ this.diameter = w - 2*this.innerPad - this.ringWidth - this.padding;
+ }
+ // center taking into account legend and over draw for gauge bottom below hub.
+ // this will be center of hub.
+ this._center = [(cw - trans * offx)/2 + trans * offx, (ch + trans*offy - this.padding - this.ringWidth - this.innerPad)];
+ }
+ else {
+ if (!this.ringWidth) {
+ this.ringWidth = d/35;
+ }
+ this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8);
+ this.innerPad = 0;
+ this.diameter = d - this.ringWidth;
+ // center in middle of canvas taking into account legend.
+ // will be center of hub.
+ this._center = [(cw-trans*offx)/2 + trans * offx, (ch-trans*offy)/2 + trans * offy];
+ }
+ }
+
+
+ if (this._labelElem && this.labelPosition == 'bottom') {
+ this._center[1] -= this._labelElem.outerHeight(true);
+ }
+
+ this._radius = this.diameter/2;
+
+ this.tickSpacing = 6000/this.diameter;
+
+ if (!this.hubRadius) {
+ this.hubRadius = this.diameter/18;
+ }
+
+ this.shadowOffset = 0.5 + this.ringWidth/9;
+ this.shadowWidth = this.ringWidth*1;
+
+ this.tickPadding = 3 + Math.pow(this.diameter/20, 0.7);
+ this.tickOuterRadius = this._radius - this.ringWidth/2 - this.tickPadding;
+ this.tickLength = (this.showTicks) ? this._radius/13 : 0;
+
+ if (this.ticks.length == 0) {
+ // no ticks, lets make some.
+ var max = this.max,
+ min = this.min,
+ setmax = this.setmax,
+ setmin = this.setmin,
+ ti = (max - min) * this.tickSpacing / this.span;
+ var tf = Math.floor(parseFloat((Math.log(ti)/Math.log(10)).toFixed(11)));
+ var tp = (ti/Math.pow(10, tf));
+ (tp > 2 && tp <= 2.5) ? tp = 2.5 : tp = Math.ceil(tp);
+ var t = this.tickPositions;
+ var tpindex, nt;
+
+ for (i=0; i<t.length; i++) {
+ if (tp == t[i] || i && t[i-1] < tp && tp < t[i]) {
+ ti = t[i]*Math.pow(10, tf);
+ tpindex = i;
+ }
+ }
+
+ for (i=0; i<t.length; i++) {
+ if (tp == t[i] || i && t[i-1] < tp && tp < t[i]) {
+ ti = t[i]*Math.pow(10, tf);
+ nt = Math.ceil((max - min) / ti);
+ }
+ }
+
+ // both max and min are free
+ if (setmax && setmin) {
+ var tmin = (min > 0) ? min - min % ti : min - min % ti - ti;
+ if (!this.forceZero) {
+ var diff = Math.min(min - tmin, 0.8*ti);
+ var ntp = Math.floor(diff/t[tpindex]);
+ if (ntp > 1) {
+ tmin = tmin + t[tpindex] * (ntp-1);
+ if (parseInt(tmin, 10) != tmin && parseInt(tmin-t[tpindex], 10) == tmin-t[tpindex]) {
+ tmin = tmin - t[tpindex];
+ }
+ }
+ }
+ if (min == tmin) {
+ min -= ti;
+ }
+ else {
+ // tmin should always be lower than dataMin
+ if (min - tmin > 0.23*ti) {
+ min = tmin;
+ }
+ else {
+ min = tmin -ti;
+ nt += 1;
+ }
+ }
+ nt += 1;
+ var tmax = min + (nt - 1) * ti;
+ if (max >= tmax) {
+ tmax += ti;
+ nt += 1;
+ }
+ // now tmax should always be mroe than dataMax
+ if (tmax - max < 0.23*ti) {
+ tmax += ti;
+ nt += 1;
+ }
+ this.max = max = tmax;
+ this.min = min;
+
+ this.tickInterval = ti;
+ this.numberTicks = nt;
+ var it;
+ for (i=0; i<nt; i++) {
+ it = parseFloat((min+i*ti).toFixed(11));
+ this.ticks.push([it, it]);
+ }
+ this.max = this.ticks[nt-1][1];
+
+ this.tickFactor = tf;
+ // determine number of minor ticks
+
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
+
+ if (!this.numberMinorTicks) {
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
+ }
+ }
+ // max is free, min is fixed
+ else if (setmax) {
+ var tmax = min + (nt - 1) * ti;
+ if (max >= tmax) {
+ max = tmax + ti;
+ nt += 1;
+ }
+ else {
+ max = tmax;
+ }
+
+ this.tickInterval = this.tickInterval || ti;
+ this.numberTicks = this.numberTicks || nt;
+ var it;
+ for (i=0; i<this.numberTicks; i++) {
+ it = parseFloat((min+i*this.tickInterval).toFixed(11));
+ this.ticks.push([it, it]);
+ }
+ this.max = this.ticks[this.numberTicks-1][1];
+
+ this.tickFactor = tf;
+ // determine number of minor ticks
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
+
+ if (!this.numberMinorTicks) {
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
+ }
+ }
+
+ // not setting max or min
+ if (!setmax && !setmin) {
+ var range = this.max - this.min;
+ tf = Math.floor(parseFloat((Math.log(range)/Math.log(10)).toFixed(11))) - 1;
+ var nticks = [5,6,4,7,3,8,9,10,2], res, numticks, nonSigDigits=0, sigRange;
+ // check to see how many zeros are at the end of the range
+ if (range > 1) {
+ var rstr = String(range);
+ if (rstr.search(/\./) == -1) {
+ var pos = rstr.search(/0+$/);
+ nonSigDigits = (pos > 0) ? rstr.length - pos - 1 : 0;
+ }
+ }
+ sigRange = range/Math.pow(10, nonSigDigits);
+ for (i=0; i<nticks.length; i++) {
+ res = sigRange/(nticks[i]-1);
+ if (res == parseInt(res, 10)) {
+ this.numberTicks = nticks[i];
+ this.tickInterval = range/(this.numberTicks-1);
+ this.tickFactor = tf+1;
+ break;
+ }
+ }
+ var it;
+ for (i=0; i<this.numberTicks; i++) {
+ it = parseFloat((this.min+i*this.tickInterval).toFixed(11));
+ this.ticks.push([it, it]);
+ }
+ // determine number of minor ticks
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor);
+
+ if (!this.numberMinorTicks) {
+ this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1);
+ }
+
+ if (!this.numberMinorTicks) {
+ this.numberMinorTicks = 1;
+ var nums = [4, 5, 3, 6, 2];
+ for (i=0; i<5; i++) {
+ var temp = this.tickInterval/nums[i];
+ if (temp == parseInt(temp, 10)) {
+ this.numberMinorTicks = nums[i]-1;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+
+ var r = this._radius,
+ sa = this.startAngle,
+ ea = this.endAngle,
+ pi = Math.PI,
+ hpi = Math.PI/2;
+
+ if (this.semiCircular) {
+ var overAngle = Math.atan(this.innerPad/r),
+ outersa = this.outerStartAngle = sa - overAngle,
+ outerea = this.outerEndAngle = ea + overAngle,
+ hubsa = this.hubStartAngle = sa - Math.atan(this.innerPad/this.hubRadius*2),
+ hubea = this.hubEndAngle = ea + Math.atan(this.innerPad/this.hubRadius*2);
+
+ ctx.save();
+
+ ctx.translate(this._center[0], this._center[1]);
+ ctx.lineJoin = "round";
+ ctx.lineCap = "round";
+
+ // draw the innerbackground
+ ctx.save();
+ ctx.beginPath();
+ ctx.fillStyle = this.background;
+ ctx.arc(0, 0, r, outersa, outerea, false);
+ ctx.closePath();
+ ctx.fill();
+ ctx.restore();
+
+ // draw the shadow
+ // the outer ring.
+ var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
+ ctx.save();
+ for (var i=0; i<this.shadowDepth; i++) {
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
+ ctx.beginPath();
+ ctx.strokeStyle = shadowColor;
+ ctx.lineWidth = this.shadowWidth;
+ ctx.arc(0 ,0, r, outersa, outerea, false);
+ ctx.closePath();
+ ctx.stroke();
+ }
+ ctx.restore();
+
+ // the inner hub.
+ ctx.save();
+ var tempd = parseInt((this.shadowDepth+1)/2, 10);
+ for (var i=0; i<tempd; i++) {
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
+ ctx.beginPath();
+ ctx.fillStyle = shadowColor;
+ ctx.arc(0 ,0, this.hubRadius, hubsa, hubea, false);
+ ctx.closePath();
+ ctx.fill();
+ }
+ ctx.restore();
+
+ // draw the outer ring.
+ ctx.save();
+ ctx.beginPath();
+ ctx.strokeStyle = this.ringColor;
+ ctx.lineWidth = this.ringWidth;
+ ctx.arc(0 ,0, r, outersa, outerea, false);
+ ctx.closePath();
+ ctx.stroke();
+ ctx.restore();
+
+ // draw the hub
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.fillStyle = this.ringColor;
+ ctx.arc(0 ,0, this.hubRadius,hubsa, hubea, false);
+ ctx.closePath();
+ ctx.fill();
+ ctx.restore();
+
+ // draw the ticks
+ if (this.showTicks) {
+ ctx.save();
+ var orad = this.tickOuterRadius,
+ tl = this.tickLength,
+ mtl = tl/2,
+ nmt = this.numberMinorTicks,
+ ts = this.span * Math.PI / 180 / (this.ticks.length-1),
+ mts = ts/(nmt + 1);
+
+ for (i = 0; i<this.ticks.length; i++) {
+ ctx.beginPath();
+ ctx.lineWidth = 1.5 + this.diameter/360;
+ ctx.strokeStyle = this.ringColor;
+ var wps = ts*i+sa;
+ ctx.moveTo(-orad * Math.cos(ts*i+sa), orad * Math.sin(ts*i+sa));
+ ctx.lineTo(-(orad-tl) * Math.cos(ts*i+sa), (orad - tl) * Math.sin(ts*i+sa));
+ this._tickPoints.push([(orad-tl) * Math.cos(ts*i+sa) + this._center[0] + this.canvas._offsets.left, (orad - tl) * Math.sin(ts*i+sa) + this._center[1] + this.canvas._offsets.top, ts*i+sa]);
+ ctx.stroke();
+ ctx.lineWidth = 1.0 + this.diameter/440;
+ if (i<this.ticks.length-1) {
+ for (var j=1; j<=nmt; j++) {
+ ctx.beginPath();
+ ctx.moveTo(-orad * Math.cos(ts*i+mts*j+sa), orad * Math.sin(ts*i+mts*j+sa));
+ ctx.lineTo(-(orad-mtl) * Math.cos(ts*i+mts*j+sa), (orad-mtl) * Math.sin(ts*i+mts*j+sa));
+ ctx.stroke();
+ }
+ }
+ }
+ ctx.restore();
+ }
+
+ // draw the tick labels
+ if (this.showTickLabels) {
+ var elem, l, t, ew, eh, dim, maxdim=0;
+ var tp = this.tickPadding * (1 - 1/(this.diameter/80+1));
+ for (i=0; i<this.ticks.length; i++) {
+ elem = $('<div class="jqplot-meterGauge-tick" style="position:absolute;">'+this.ticks[i][1]+'</div>');
+ this.canvas._elem.after(elem);
+ ew = elem.outerWidth(true);
+ eh = elem.outerHeight(true);
+ l = this._tickPoints[i][0] - ew * (this._tickPoints[i][2]-Math.PI)/Math.PI - tp * Math.cos(this._tickPoints[i][2]);
+ t = this._tickPoints[i][1] - eh/2 + eh/2 * Math.pow(Math.abs((Math.sin(this._tickPoints[i][2]))), 0.5) + tp/3 * Math.pow(Math.abs((Math.sin(this._tickPoints[i][2]))), 0.5) ;
+ // t = this._tickPoints[i][1] - eh/2 - eh/2 * Math.sin(this._tickPoints[i][2]) - tp/2 * Math.sin(this._tickPoints[i][2]);
+ elem.css({left:l, top:t});
+ dim = ew*Math.cos(this._tickPoints[i][2]) + eh*Math.sin(Math.PI/2+this._tickPoints[i][2]/2);
+ maxdim = (dim > maxdim) ? dim : maxdim;
+ }
+ }
+
+ // draw the gauge label
+ if (this.label && this.labelPosition == 'inside') {
+ var l = this._center[0] + this.canvas._offsets.left;
+ var tp = this.tickPadding * (1 - 1/(this.diameter/80+1));
+ var t = 0.5*(this._center[1] + this.canvas._offsets.top - this.hubRadius) + 0.5*(this._center[1] + this.canvas._offsets.top - this.tickOuterRadius + this.tickLength + tp) + this.labelHeightAdjust;
+ // this._labelElem = $('<div class="jqplot-meterGauge-label" style="position:absolute;">'+this.label+'</div>');
+ // this.canvas._elem.after(this._labelElem);
+ l -= this._labelElem.outerWidth(true)/2;
+ t -= this._labelElem.outerHeight(true)/2;
+ this._labelElem.css({left:l, top:t});
+ }
+
+ else if (this.label && this.labelPosition == 'bottom') {
+ var l = this._center[0] + this.canvas._offsets.left - this._labelElem.outerWidth(true)/2;
+ var t = this._center[1] + this.canvas._offsets.top + this.innerPad + + this.ringWidth + this.padding + this.labelHeightAdjust;
+ this._labelElem.css({left:l, top:t});
+
+ }
+
+ // draw the intervals
+
+ ctx.save();
+ var inner = this.intervalInnerRadius || this.hubRadius * 1.5;
+ if (this.intervalOuterRadius == null) {
+ if (this.showTickLabels) {
+ var outer = (this.tickOuterRadius - this.tickLength - this.tickPadding - this.diameter/8);
+ }
+ else {
+ var outer = (this.tickOuterRadius - this.tickLength - this.diameter/16);
+ }
+ }
+ else {
+ var outer = this.intervalOuterRadius;
+ }
+ var range = this.max - this.min;
+ var intrange = this.intervals[this.intervals.length-1] - this.min;
+ var start, end, span = this.span*Math.PI/180;
+ for (i=0; i<this.intervals.length; i++) {
+ start = (i == 0) ? sa : sa + (this.intervals[i-1][0] - this.min)*span/range;
+ if (start < 0) {
+ start = 0;
+ }
+ end = sa + (this.intervals[i][0] - this.min)*span/range;
+ if (end < 0) {
+ end = 0;
+ }
+ ctx.beginPath();
+ ctx.fillStyle = this.intervals[i][2];
+ ctx.arc(0, 0, inner, start, end, false);
+ ctx.lineTo(outer*Math.cos(end), outer*Math.sin(end));
+ ctx.arc(0, 0, outer, end, start, true);
+ ctx.lineTo(inner*Math.cos(start), inner*Math.sin(start));
+ ctx.closePath();
+ ctx.fill();
+ }
+ ctx.restore();
+
+ // draw the needle
+ var datapoint = this.data[0][1];
+ var dataspan = this.max - this.min;
+ if (this.pegNeedle) {
+ if (this.data[0][1] > this.max + dataspan*3/this.span) {
+ datapoint = this.max + dataspan*3/this.span;
+ }
+ if (this.data[0][1] < this.min - dataspan*3/this.span) {
+ datapoint = this.min - dataspan*3/this.span;
+ }
+ }
+ var dataang = (datapoint - this.min)/dataspan * this.span * Math.PI/180 + this.startAngle;
+
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.fillStyle = this.ringColor;
+ ctx.strokeStyle = this.ringColor;
+ this.needleLength = (this.tickOuterRadius - this.tickLength) * 0.85;
+ this.needleThickness = (this.needleThickness < 2) ? 2 : this.needleThickness;
+ var endwidth = this.needleThickness * 0.4;
+
+
+ var dl = this.needleLength/10;
+ var dt = (this.needleThickness - endwidth)/10;
+ var templ;
+ for (var i=0; i<10; i++) {
+ templ = this.needleThickness - i*dt;
+ ctx.moveTo(dl*i*Math.cos(dataang), dl*i*Math.sin(dataang));
+ ctx.lineWidth = templ;
+ ctx.lineTo(dl*(i+1)*Math.cos(dataang), dl*(i+1)*Math.sin(dataang));
+ ctx.stroke();
+ }
+
+ ctx.restore();
+ }
+ else {
+ this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy];
+ }
+ };
+
+ $.jqplot.MeterGaugeAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.MeterGaugeAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.MeterGaugeAxisRenderer.prototype.constructor = $.jqplot.MeterGaugeAxisRenderer;
+
+
+ // There are no traditional axes on a gauge chart. We just need to provide
+ // dummy objects with properties so the plot will render.
+ // called with scope of axis object.
+ $.jqplot.MeterGaugeAxisRenderer.prototype.init = function(options){
+ //
+ this.tickRenderer = $.jqplot.MeterGaugeTickRenderer;
+ $.extend(true, this, options);
+ // I don't think I'm going to need _dataBounds here.
+ // have to go Axis scaling in a way to fit chart onto plot area
+ // and provide u2p and p2u functionality for mouse cursor, etc.
+ // for convienence set _dataBounds to 0 and 100 and
+ // set min/max to 0 and 100.
+ this._dataBounds = {min:0, max:100};
+ this.min = 0;
+ this.max = 100;
+ this.showTicks = false;
+ this.ticks = [];
+ this.showMark = false;
+ this.show = false;
+ };
+
+ $.jqplot.MeterGaugeLegendRenderer = function(){
+ $.jqplot.TableLegendRenderer.call(this);
+ };
+
+ $.jqplot.MeterGaugeLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.MeterGaugeLegendRenderer.prototype.constructor = $.jqplot.MeterGaugeLegendRenderer;
+
+ /**
+ * Class: $.jqplot.MeterGaugeLegendRenderer
+ *Meter gauges don't typically have a legend, this overrides the default legend renderer.
+ */
+ $.jqplot.MeterGaugeLegendRenderer.prototype.init = function(options) {
+ // Maximum number of rows in the legend. 0 or null for unlimited.
+ this.numberRows = null;
+ // Maximum number of columns in the legend. 0 or null for unlimited.
+ this.numberColumns = null;
+ $.extend(true, this, options);
+ };
+
+ // called with context of legend
+ $.jqplot.MeterGaugeLegendRenderer.prototype.draw = function() {
+ if (this.show) {
+ var series = this._series;
+ var ss = 'position:absolute;';
+ ss += (this.background) ? 'background:'+this.background+';' : '';
+ ss += (this.border) ? 'border:'+this.border+';' : '';
+ ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
+ ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
+ ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
+ ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
+ ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
+ ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
+ ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
+ this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
+ // MeterGauge charts legends don't go by number of series, but by number of data points
+ // in the series. Refactor things here for that.
+
+ var pad = false,
+ reverse = false,
+ nr, nc;
+ var s = series[0];
+
+ if (s.show) {
+ var pd = s.data;
+ if (this.numberRows) {
+ nr = this.numberRows;
+ if (!this.numberColumns){
+ nc = Math.ceil(pd.length/nr);
+ }
+ else{
+ nc = this.numberColumns;
+ }
+ }
+ else if (this.numberColumns) {
+ nc = this.numberColumns;
+ nr = Math.ceil(pd.length/this.numberColumns);
+ }
+ else {
+ nr = pd.length;
+ nc = 1;
+ }
+
+ var i, j, tr, td1, td2, lt, rs, color;
+ var idx = 0;
+
+ for (i=0; i<nr; i++) {
+ if (reverse){
+ tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
+ }
+ else{
+ tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
+ }
+ for (j=0; j<nc; j++) {
+ if (idx < pd.length){
+ // debugger
+ lt = this.labels[idx] || pd[idx][0].toString();
+ color = s.color;
+ if (!reverse){
+ if (i>0){
+ pad = true;
+ }
+ else{
+ pad = false;
+ }
+ }
+ else{
+ if (i == nr -1){
+ pad = false;
+ }
+ else{
+ pad = true;
+ }
+ }
+ rs = (pad) ? this.rowSpacing : '0';
+
+ td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
+ '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
+ '</div></td>');
+ td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
+ if (this.escapeHtml){
+ td2.text(lt);
+ }
+ else {
+ td2.html(lt);
+ }
+ if (reverse) {
+ td2.prependTo(tr);
+ td1.prependTo(tr);
+ }
+ else {
+ td1.appendTo(tr);
+ td2.appendTo(tr);
+ }
+ pad = true;
+ }
+ idx++;
+ }
+ }
+ }
+ }
+ return this._elem;
+ };
+
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ // debugger
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.legend = options.legend || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ options.grid = options.grid || {};
+
+ // only set these if there is a gauge series
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.MeterGaugeRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.MeterGaugeRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.MeterGaugeAxisRenderer;
+ options.legend.renderer = $.jqplot.MeterGaugeLegendRenderer;
+ options.legend.preDraw = true;
+ options.grid.background = options.grid.background || 'white';
+ options.grid.drawGridlines = false;
+ options.grid.borderWidth = (options.grid.borderWidth != null) ? options.grid.borderWidth : 0;
+ options.grid.shadow = (options.grid.shadow != null) ? options.grid.shadow : false;
+ }
+ }
+
+ // called with scope of plot
+ function postParseOptions(options) {
+ //
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+ $.jqplot.postParseOptionsHooks.push(postParseOptions);
+
+ $.jqplot.MeterGaugeTickRenderer = function() {
+ $.jqplot.AxisTickRenderer.call(this);
+ };
+
+ $.jqplot.MeterGaugeTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
+ $.jqplot.MeterGaugeTickRenderer.prototype.constructor = $.jqplot.MeterGaugeTickRenderer;
+
+})(jQuery);
+
+ \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.mobile.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.mobile.js
new file mode 100644
index 00000000..22b77464
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.mobile.js
@@ -0,0 +1,45 @@
+/**
+ * jqplot.jquerymobile plugin
+ * jQuery Mobile virtual event support.
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2011 Takashi Okamoto
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ */
+(function($) {
+ function postInit(target, data, options){
+ this.bindCustomEvents = function() {
+ this.eventCanvas._elem.bind('vclick', {plot:this}, this.onClick);
+ this.eventCanvas._elem.bind('dblclick', {plot:this}, this.onDblClick);
+ this.eventCanvas._elem.bind('taphold', {plot:this}, this.onDblClick);
+ this.eventCanvas._elem.bind('vmousedown', {plot:this}, this.onMouseDown);
+ this.eventCanvas._elem.bind('vmousemove', {plot:this}, this.onMouseMove);
+ this.eventCanvas._elem.bind('mouseenter', {plot:this}, this.onMouseEnter);
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, this.onMouseLeave);
+ if (this.captureRightClick) {
+ this.eventCanvas._elem.bind('vmouseup', {plot:this}, this.onRightClick);
+ this.eventCanvas._elem.get(0).oncontextmenu = function() {
+ return false;
+ };
+ }
+ else {
+ this.eventCanvas._elem.bind('vmouseup', {plot:this}, this.onMouseUp);
+ }
+ };
+ this.plugins.mobile = true;
+ }
+ $.jqplot.postInitHooks.push(postInit);
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.ohlcRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.ohlcRenderer.js
new file mode 100644
index 00000000..2f143f1b
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.ohlcRenderer.js
@@ -0,0 +1,373 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.OHLCRenderer
+ * jqPlot Plugin to draw Open Hi Low Close, Candlestick and Hi Low Close charts.
+ *
+ * To use this plugin, include the renderer js file in
+ * your source:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.ohlcRenderer.js"></script>
+ *
+ * You will most likely want to use a date axis renderer
+ * for the x axis also, so include the date axis render js file also:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.dateAxisRenderer.js"></script>
+ *
+ * Then you set the renderer in the series options on your plot:
+ *
+ * > series: [{renderer:$.jqplot.OHLCRenderer}]
+ *
+ * For OHLC and candlestick charts, data should be specified
+ * like so:
+ *
+ * > dat = [['07/06/2009',138.7,139.68,135.18,135.4], ['06/29/2009',143.46,144.66,139.79,140.02], ...]
+ *
+ * If the data array has only 4 values per point instead of 5,
+ * the renderer will create a Hi Low Close chart instead. In that case,
+ * data should be supplied like:
+ *
+ * > dat = [['07/06/2009',139.68,135.18,135.4], ['06/29/2009',144.66,139.79,140.02], ...]
+ *
+ * To generate a candlestick chart instead of an OHLC chart,
+ * set the "candlestick" option to true:
+ *
+ * > series: [{renderer:$.jqplot.OHLCRenderer, rendererOptions:{candleStick:true}}],
+ *
+ */
+ $.jqplot.OHLCRenderer = function(){
+ // subclass line renderer to make use of some of it's methods.
+ $.jqplot.LineRenderer.call(this);
+ // prop: candleStick
+ // true to render chart as candleStick.
+ // Must have an open price, cannot be a hlc chart.
+ this.candleStick = false;
+ // prop: tickLength
+ // length of the line in pixels indicating open and close price.
+ // Default will auto calculate based on plot width and
+ // number of points displayed.
+ this.tickLength = 'auto';
+ // prop: bodyWidth
+ // width of the candlestick body in pixels. Default will auto calculate
+ // based on plot width and number of candlesticks displayed.
+ this.bodyWidth = 'auto';
+ // prop: openColor
+ // color of the open price tick mark. Default is series color.
+ this.openColor = null;
+ // prop: closeColor
+ // color of the close price tick mark. Default is series color.
+ this.closeColor = null;
+ // prop: wickColor
+ // color of the hi-lo line thorugh the candlestick body.
+ // Default is the series color.
+ this.wickColor = null;
+ // prop: fillUpBody
+ // true to render an "up" day (close price greater than open price)
+ // with a filled candlestick body.
+ this.fillUpBody = false;
+ // prop: fillDownBody
+ // true to render a "down" day (close price lower than open price)
+ // with a filled candlestick body.
+ this.fillDownBody = true;
+ // prop: upBodyColor
+ // Color of candlestick body of an "up" day. Default is series color.
+ this.upBodyColor = null;
+ // prop: downBodyColor
+ // Color of candlestick body on a "down" day. Default is series color.
+ this.downBodyColor = null;
+ // prop: hlc
+ // true if is a hi-low-close chart (no open price).
+ // This is determined automatically from the series data.
+ this.hlc = false;
+ // prop: lineWidth
+ // Width of the hi-low line and open/close ticks.
+ // Must be set in the rendererOptions for the series.
+ this.lineWidth = 1.5;
+ this._tickLength;
+ this._bodyWidth;
+ };
+
+ $.jqplot.OHLCRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.OHLCRenderer.prototype.constructor = $.jqplot.OHLCRenderer;
+
+ // called with scope of series.
+ $.jqplot.OHLCRenderer.prototype.init = function(options) {
+ options = options || {};
+ // lineWidth has to be set on the series, changes in renderer
+ // constructor have no effect. set the default here
+ // if no renderer option for lineWidth is specified.
+ this.lineWidth = options.lineWidth || 1.5;
+ $.jqplot.LineRenderer.prototype.init.call(this, options);
+ this._type = 'ohlc';
+ // set the yaxis data bounds here to account for hi and low values
+ var db = this._yaxis._dataBounds;
+ var d = this._plotData;
+ // if data points have less than 5 values, force a hlc chart.
+ if (d[0].length < 5) {
+ this.renderer.hlc = true;
+
+ for (var j=0; j<d.length; j++) {
+ if (d[j][2] < db.min || db.min == null) {
+ db.min = d[j][2];
+ }
+ if (d[j][1] > db.max || db.max == null) {
+ db.max = d[j][1];
+ }
+ }
+ }
+ else {
+ for (var j=0; j<d.length; j++) {
+ if (d[j][3] < db.min || db.min == null) {
+ db.min = d[j][3];
+ }
+ if (d[j][2] > db.max || db.max == null) {
+ db.max = d[j][2];
+ }
+ }
+ }
+
+ };
+
+ // called within scope of series.
+ $.jqplot.OHLCRenderer.prototype.draw = function(ctx, gd, options) {
+ var d = this.data;
+ var xmin = this._xaxis.min;
+ var xmax = this._xaxis.max;
+ // index of last value below range of plot.
+ var xminidx = 0;
+ // index of first value above range of plot.
+ var xmaxidx = d.length;
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var i, prevColor, ops, b, h, w, a, points;
+ var o;
+ var r = this.renderer;
+ var opts = (options != undefined) ? options : {};
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var fillAndStroke = (opts.fillAndStroke != undefined) ? opts.fillAndStroke : this.fillAndStroke;
+ r.bodyWidth = (opts.bodyWidth != undefined) ? opts.bodyWidth : r.bodyWidth;
+ r.tickLength = (opts.tickLength != undefined) ? opts.tickLength : r.tickLength;
+ ctx.save();
+ if (this.show) {
+ var x, open, hi, low, close;
+ // need to get widths based on number of points shown,
+ // not on total number of points. Use the results
+ // to speed up drawing in next step.
+ for (var i=0; i<d.length; i++) {
+ if (d[i][0] < xmin) {
+ xminidx = i;
+ }
+ else if (d[i][0] < xmax) {
+ xmaxidx = i+1;
+ }
+ }
+
+ var dwidth = this.gridData[xmaxidx-1][0] - this.gridData[xminidx][0];
+ var nvisiblePoints = xmaxidx - xminidx;
+ try {
+ var dinterval = Math.abs(this._xaxis.series_u2p(parseInt(this._xaxis._intervalStats[0].sortedIntervals[0].interval, 10)) - this._xaxis.series_u2p(0));
+ }
+
+ catch (e) {
+ var dinterval = dwidth / nvisiblePoints;
+ }
+
+ if (r.candleStick) {
+ if (typeof(r.bodyWidth) == 'number') {
+ r._bodyWidth = r.bodyWidth;
+ }
+ else {
+ r._bodyWidth = Math.min(20, dinterval/1.65);
+ }
+ }
+ else {
+ if (typeof(r.tickLength) == 'number') {
+ r._tickLength = r.tickLength;
+ }
+ else {
+ r._tickLength = Math.min(10, dinterval/3.5);
+ }
+ }
+
+ for (var i=xminidx; i<xmaxidx; i++) {
+ x = xp(d[i][0]);
+ if (r.hlc) {
+ open = null;
+ hi = yp(d[i][1]);
+ low = yp(d[i][2]);
+ close = yp(d[i][3]);
+ }
+ else {
+ open = yp(d[i][1]);
+ hi = yp(d[i][2]);
+ low = yp(d[i][3]);
+ close = yp(d[i][4]);
+ }
+ o = {};
+ if (r.candleStick && !r.hlc) {
+ w = r._bodyWidth;
+ a = x - w/2;
+ // draw candle
+ // determine if candle up or down
+ // up, remember grid coordinates increase downward
+ if (close < open) {
+ // draw wick
+ if (r.wickColor) {
+ o.color = r.wickColor;
+ }
+ else if (r.downBodyColor) {
+ o.color = r.upBodyColor;
+ }
+ ops = $.extend(true, {}, opts, o);
+ r.shapeRenderer.draw(ctx, [[x, hi], [x, close]], ops);
+ r.shapeRenderer.draw(ctx, [[x, open], [x, low]], ops);
+ o = {};
+ b = close;
+ h = open - close;
+ // if color specified, use it
+ if (r.fillUpBody) {
+ o.fillRect = true;
+ }
+ else {
+ o.strokeRect = true;
+ w = w - this.lineWidth;
+ a = x - w/2;
+ }
+ if (r.upBodyColor) {
+ o.color = r.upBodyColor;
+ o.fillStyle = r.upBodyColor;
+ }
+ points = [a, b, w, h];
+ }
+ // down
+ else if (close > open) {
+ // draw wick
+ if (r.wickColor) {
+ o.color = r.wickColor;
+ }
+ else if (r.downBodyColor) {
+ o.color = r.downBodyColor;
+ }
+ ops = $.extend(true, {}, opts, o);
+ r.shapeRenderer.draw(ctx, [[x, hi], [x, open]], ops);
+ r.shapeRenderer.draw(ctx, [[x, close], [x, low]], ops);
+
+ o = {};
+
+ b = open;
+ h = close - open;
+ // if color specified, use it
+ if (r.fillDownBody) {
+ o.fillRect = true;
+ }
+ else {
+ o.strokeRect = true;
+ w = w - this.lineWidth;
+ a = x - w/2;
+ }
+ if (r.downBodyColor) {
+ o.color = r.downBodyColor;
+ o.fillStyle = r.downBodyColor;
+ }
+ points = [a, b, w, h];
+ }
+ // even, open = close
+ else {
+ // draw wick
+ if (r.wickColor) {
+ o.color = r.wickColor;
+ }
+ ops = $.extend(true, {}, opts, o);
+ r.shapeRenderer.draw(ctx, [[x, hi], [x, low]], ops);
+ o = {};
+ o.fillRect = false;
+ o.strokeRect = false;
+ a = [x - w/2, open];
+ b = [x + w/2, close];
+ w = null;
+ h = null;
+ points = [a, b];
+ }
+ ops = $.extend(true, {}, opts, o);
+ r.shapeRenderer.draw(ctx, points, ops);
+ }
+ else {
+ prevColor = opts.color;
+ if (r.openColor) {
+ opts.color = r.openColor;
+ }
+ // draw open tick
+ if (!r.hlc) {
+ r.shapeRenderer.draw(ctx, [[x-r._tickLength, open], [x, open]], opts);
+ }
+ opts.color = prevColor;
+ // draw wick
+ if (r.wickColor) {
+ opts.color = r.wickColor;
+ }
+ r.shapeRenderer.draw(ctx, [[x, hi], [x, low]], opts);
+ opts.color = prevColor;
+ // draw close tick
+ if (r.closeColor) {
+ opts.color = r.closeColor;
+ }
+ r.shapeRenderer.draw(ctx, [[x, close], [x+r._tickLength, close]], opts);
+ opts.color = prevColor;
+ }
+ }
+ }
+
+ ctx.restore();
+ };
+
+ $.jqplot.OHLCRenderer.prototype.drawShadow = function(ctx, gd, options) {
+ // This is a no-op, shadows drawn with lines.
+ };
+
+ // called with scope of plot.
+ $.jqplot.OHLCRenderer.checkOptions = function(target, data, options) {
+ // provide some sensible highlighter options by default
+ // These aren't good for hlc, only for ohlc or candlestick
+ if (!options.highlighter) {
+ options.highlighter = {
+ showMarker:false,
+ tooltipAxes: 'y',
+ yvalues: 4,
+ formatString:'<table class="jqplot-highlighter"><tr><td>date:</td><td>%s</td></tr><tr><td>open:</td><td>%s</td></tr><tr><td>hi:</td><td>%s</td></tr><tr><td>low:</td><td>%s</td></tr><tr><td>close:</td><td>%s</td></tr></table>'
+ };
+ }
+ };
+
+ //$.jqplot.preInitHooks.push($.jqplot.OHLCRenderer.checkOptions);
+
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.pieRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.pieRenderer.js
new file mode 100644
index 00000000..2479885c
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.pieRenderer.js
@@ -0,0 +1,904 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ /**
+ * Class: $.jqplot.PieRenderer
+ * Plugin renderer to draw a pie chart.
+ * x values, if present, will be used as slice labels.
+ * y values give slice size.
+ *
+ * To use this renderer, you need to include the
+ * pie renderer plugin, for example:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.pieRenderer.js"></script>
+ *
+ * Properties described here are passed into the $.jqplot function
+ * as options on the series renderer. For example:
+ *
+ * > plot2 = $.jqplot('chart2', [s1, s2], {
+ * > seriesDefaults: {
+ * > renderer:$.jqplot.PieRenderer,
+ * > rendererOptions:{
+ * > sliceMargin: 2,
+ * > startAngle: -90
+ * > }
+ * > }
+ * > });
+ *
+ * A pie plot will trigger events on the plot target
+ * according to user interaction. All events return the event object,
+ * the series index, the point (slice) index, and the point data for
+ * the appropriate slice.
+ *
+ * 'jqplotDataMouseOver' - triggered when user mouseing over a slice.
+ * 'jqplotDataHighlight' - triggered the first time user mouses over a slice,
+ * if highlighting is enabled.
+ * 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of
+ * a highlighted slice.
+ * 'jqplotDataClick' - triggered when the user clicks on a slice.
+ * 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if
+ * the "captureRightClick" option is set to true on the plot.
+ */
+ $.jqplot.PieRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.PieRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.PieRenderer.prototype.constructor = $.jqplot.PieRenderer;
+
+ // called with scope of a series
+ $.jqplot.PieRenderer.prototype.init = function(options, plot) {
+ // Group: Properties
+ //
+ // prop: diameter
+ // Outer diameter of the pie, auto computed by default
+ this.diameter = null;
+ // prop: padding
+ // padding between the pie and plot edges, legend, etc.
+ this.padding = 20;
+ // prop: sliceMargin
+ // angular spacing between pie slices in degrees.
+ this.sliceMargin = 0;
+ // prop: fill
+ // true or false, wether to fil the slices.
+ this.fill = true;
+ // prop: shadowOffset
+ // offset of the shadow from the slice and offset of
+ // each succesive stroke of the shadow from the last.
+ this.shadowOffset = 2;
+ // prop: shadowAlpha
+ // transparency of the shadow (0 = transparent, 1 = opaque)
+ this.shadowAlpha = 0.07;
+ // prop: shadowDepth
+ // number of strokes to apply to the shadow,
+ // each stroke offset shadowOffset from the last.
+ this.shadowDepth = 5;
+ // prop: highlightMouseOver
+ // True to highlight slice when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over a slice.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColors
+ // an array of colors to use when highlighting a slice.
+ this.highlightColors = [];
+ // prop: dataLabels
+ // Either 'label', 'value', 'percent' or an array of labels to place on the pie slices.
+ // Defaults to percentage of each pie slice.
+ this.dataLabels = 'percent';
+ // prop: showDataLabels
+ // true to show data labels on slices.
+ this.showDataLabels = false;
+ // prop: dataLabelFormatString
+ // Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage.
+ this.dataLabelFormatString = null;
+ // prop: dataLabelThreshold
+ // Threshhold in percentage (0-100) of pie area, below which no label will be displayed.
+ // This applies to all label types, not just to percentage labels.
+ this.dataLabelThreshold = 3;
+ // prop: dataLabelPositionFactor
+ // A Multiplier (0-1) of the pie radius which controls position of label on slice.
+ // Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie.
+ this.dataLabelPositionFactor = 0.52;
+ // prop: dataLabelNudge
+ // Number of pixels to slide the label away from (+) or toward (-) the center of the pie.
+ this.dataLabelNudge = 2;
+ // prop: dataLabelCenterOn
+ // True to center the data label at its position.
+ // False to set the inside facing edge of the label at its position.
+ this.dataLabelCenterOn = true;
+ // prop: startAngle
+ // Angle to start drawing pie in degrees.
+ // According to orientation of canvas coordinate system:
+ // 0 = on the positive x axis
+ // -90 = on the positive y axis.
+ // 90 = on the negaive y axis.
+ // 180 or - 180 = on the negative x axis.
+ this.startAngle = 0;
+ this.tickRenderer = $.jqplot.PieTickRenderer;
+ // Used as check for conditions where pie shouldn't be drawn.
+ this._drawData = true;
+ this._type = 'pie';
+
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
+ options.highlightMouseOver = false;
+ }
+
+ $.extend(true, this, options);
+
+ if (this.sliceMargin < 0) {
+ this.sliceMargin = 0;
+ }
+
+ this._diameter = null;
+ this._radius = null;
+ // array of [start,end] angles arrays, one for each slice. In radians.
+ this._sliceAngles = [];
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+
+ // set highlight colors if none provided
+ if (this.highlightColors.length == 0) {
+ for (var i=0; i<this.seriesColors.length; i++){
+ var rgba = $.jqplot.getColorComponents(this.seriesColors[i]);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
+ newrgb[j] = parseInt(newrgb[j], 10);
+ }
+ this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')');
+ }
+ }
+
+ this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors);
+
+ plot.postParseOptionsHooks.addOnce(postParseOptions);
+ plot.postInitHooks.addOnce(postInit);
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
+ plot.postDrawHooks.addOnce(postPlotDraw);
+ };
+
+ $.jqplot.PieRenderer.prototype.setGridData = function(plot) {
+ // set gridData property. This will hold angle in radians of each data point.
+ var stack = [];
+ var td = [];
+ var sa = this.startAngle/180*Math.PI;
+ var tot = 0;
+ // don't know if we have any valid data yet, so set plot to not draw.
+ this._drawData = false;
+ for (var i=0; i<this.data.length; i++){
+ if (this.data[i][1] != 0) {
+ // we have data, O.K. to draw.
+ this._drawData = true;
+ }
+ stack.push(this.data[i][1]);
+ td.push([this.data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ tot += this.data[i][1];
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ td[i][2] = this.data[i][1]/tot;
+ }
+ this.gridData = td;
+ };
+
+ $.jqplot.PieRenderer.prototype.makeGridData = function(data, plot) {
+ var stack = [];
+ var td = [];
+ var tot = 0;
+ var sa = this.startAngle/180*Math.PI;
+ // don't know if we have any valid data yet, so set plot to not draw.
+ this._drawData = false;
+ for (var i=0; i<data.length; i++){
+ if (this.data[i][1] != 0) {
+ // we have data, O.K. to draw.
+ this._drawData = true;
+ }
+ stack.push(data[i][1]);
+ td.push([data[i][0]]);
+ if (i>0) {
+ stack[i] += stack[i-1];
+ }
+ tot += data[i][1];
+ }
+ var fact = Math.PI*2/stack[stack.length - 1];
+
+ for (var i=0; i<stack.length; i++) {
+ td[i][1] = stack[i] * fact;
+ td[i][2] = data[i][1]/tot;
+ }
+ return td;
+ };
+
+ function calcRadiusAdjustment(ang) {
+ return Math.sin((ang - (ang-Math.PI) / 8 / Math.PI )/2.0);
+ }
+
+ function calcRPrime(ang1, ang2, sliceMargin, fill, lineWidth) {
+ var rprime = 0;
+ var ang = ang2 - ang1;
+ var absang = Math.abs(ang);
+ var sm = sliceMargin;
+ if (fill == false) {
+ sm += lineWidth;
+ }
+
+ if (sm > 0 && absang > 0.01 && absang < 6.282) {
+ rprime = parseFloat(sm) / 2.0 / calcRadiusAdjustment(ang);
+ }
+
+ return rprime;
+ }
+
+ $.jqplot.PieRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) {
+ if (this._drawData) {
+ var r = this._radius;
+ var fill = this.fill;
+ var lineWidth = this.lineWidth;
+ var sm = this.sliceMargin;
+ if (this.fill == false) {
+ sm += this.lineWidth;
+ }
+ ctx.save();
+ ctx.translate(this._center[0], this._center[1]);
+
+ var rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth);
+
+ var transx = rprime * Math.cos((ang1 + ang2) / 2.0);
+ var transy = rprime * Math.sin((ang1 + ang2) / 2.0);
+
+ if ((ang2 - ang1) <= Math.PI) {
+ r -= rprime;
+ }
+ else {
+ r += rprime;
+ }
+
+ ctx.translate(transx, transy);
+
+ if (isShadow) {
+ for (var i=0, l=this.shadowDepth; i<l; i++) {
+ ctx.save();
+ ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI));
+ doDraw(r);
+ }
+ for (var i=0, l=this.shadowDepth; i<l; i++) {
+ ctx.restore();
+ }
+ }
+
+ else {
+ doDraw(r);
+ }
+ ctx.restore();
+ }
+
+ function doDraw (rad) {
+ // Fix for IE and Chrome that can't seem to draw circles correctly.
+ // ang2 should always be <= 2 pi since that is the way the data is converted.
+ // 2Pi = 6.2831853, Pi = 3.1415927
+ if (ang2 > 6.282 + this.startAngle) {
+ ang2 = 6.282 + this.startAngle;
+ if (ang1 > ang2) {
+ ang1 = 6.281 + this.startAngle;
+ }
+ }
+ // Fix for IE, where it can't seem to handle 0 degree angles. Also avoids
+ // ugly line on unfilled pies.
+ if (ang1 >= ang2) {
+ return;
+ }
+
+ ctx.beginPath();
+ ctx.fillStyle = color;
+ ctx.strokeStyle = color;
+ ctx.lineWidth = lineWidth;
+ ctx.arc(0, 0, rad, ang1, ang2, false);
+ ctx.lineTo(0,0);
+ ctx.closePath();
+
+ if (fill) {
+ ctx.fill();
+ }
+ else {
+ ctx.stroke();
+ }
+ }
+ };
+
+ // called with scope of series
+ $.jqplot.PieRenderer.prototype.draw = function (ctx, gd, options, plot) {
+ var i;
+ var opts = (options != undefined) ? options : {};
+ // offset and direction of offset due to legend placement
+ var offx = 0;
+ var offy = 0;
+ var trans = 1;
+ var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
+ if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
+ var li = options.legendInfo;
+ switch (li.location) {
+ case 'nw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'w':
+ offx = li.width + li.xoffset;
+ break;
+ case 'sw':
+ offx = li.width + li.xoffset;
+ break;
+ case 'ne':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'e':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'se':
+ offx = li.width + li.xoffset;
+ trans = -1;
+ break;
+ case 'n':
+ offy = li.height + li.yoffset;
+ break;
+ case 's':
+ offy = li.height + li.yoffset;
+ trans = -1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var cw = ctx.canvas.width;
+ var ch = ctx.canvas.height;
+ var w = cw - offx - 2 * this.padding;
+ var h = ch - offy - 2 * this.padding;
+ var mindim = Math.min(w,h);
+ var d = mindim;
+
+ // Fixes issue #272. Thanks hugwijst!
+ // reset slice angles array.
+ this._sliceAngles = [];
+
+ var sm = this.sliceMargin;
+ if (this.fill == false) {
+ sm += this.lineWidth;
+ }
+
+ var rprime;
+ var maxrprime = 0;
+
+ var ang, ang1, ang2, shadowColor;
+ var sa = this.startAngle / 180 * Math.PI;
+
+ // have to pre-draw shadows, so loop throgh here and calculate some values also.
+ for (var i=0, l=gd.length; i<l; i++) {
+ ang1 = (i == 0) ? sa : gd[i-1][1] + sa;
+ ang2 = gd[i][1] + sa;
+
+ this._sliceAngles.push([ang1, ang2]);
+
+ rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth);
+
+ if (Math.abs(ang2-ang1) > Math.PI) {
+ maxrprime = Math.max(rprime, maxrprime);
+ }
+ }
+
+ if (this.diameter != null && this.diameter > 0) {
+ this._diameter = this.diameter - 2*maxrprime;
+ }
+ else {
+ this._diameter = d - 2*maxrprime;
+ }
+
+ // Need to check for undersized pie. This can happen if
+ // plot area too small and legend is too big.
+ if (this._diameter < 6) {
+ $.jqplot.log('Diameter of pie too small, not rendering.');
+ return;
+ }
+
+ var r = this._radius = this._diameter/2;
+
+ this._center = [(cw - trans * offx)/2 + trans * offx + maxrprime * Math.cos(sa), (ch - trans*offy)/2 + trans * offy + maxrprime * Math.sin(sa)];
+
+ if (this.shadow) {
+ for (var i=0, l=gd.length; i<l; i++) {
+ shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')';
+ this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], shadowColor, true);
+ }
+ }
+
+ for (var i=0; i<gd.length; i++) {
+
+ this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], colorGenerator.next(), false);
+
+ if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) {
+ var fstr, avgang = (this._sliceAngles[i][0] + this._sliceAngles[i][1])/2, label;
+
+ if (this.dataLabels == 'label') {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, gd[i][0]);
+ }
+ else if (this.dataLabels == 'value') {
+ fstr = this.dataLabelFormatString || '%d';
+ label = $.jqplot.sprintf(fstr, this.data[i][1]);
+ }
+ else if (this.dataLabels == 'percent') {
+ fstr = this.dataLabelFormatString || '%d%%';
+ label = $.jqplot.sprintf(fstr, gd[i][2]*100);
+ }
+ else if (this.dataLabels.constructor == Array) {
+ fstr = this.dataLabelFormatString || '%s';
+ label = $.jqplot.sprintf(fstr, this.dataLabels[i]);
+ }
+
+ var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge;
+
+ var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left;
+ var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top;
+
+ var labelelem = $('<div class="jqplot-pie-series jqplot-data-label" style="position:absolute;">' + label + '</div>').insertBefore(plot.eventCanvas._elem);
+ if (this.dataLabelCenterOn) {
+ x -= labelelem.width()/2;
+ y -= labelelem.height()/2;
+ }
+ else {
+ x -= labelelem.width() * Math.sin(avgang/2);
+ y -= labelelem.height()/2;
+ }
+ x = Math.round(x);
+ y = Math.round(y);
+ labelelem.css({left: x, top: y});
+ }
+ }
+ };
+
+ $.jqplot.PieAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.PieAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.PieAxisRenderer.prototype.constructor = $.jqplot.PieAxisRenderer;
+
+
+ // There are no traditional axes on a pie chart. We just need to provide
+ // dummy objects with properties so the plot will render.
+ // called with scope of axis object.
+ $.jqplot.PieAxisRenderer.prototype.init = function(options){
+ //
+ this.tickRenderer = $.jqplot.PieTickRenderer;
+ $.extend(true, this, options);
+ // I don't think I'm going to need _dataBounds here.
+ // have to go Axis scaling in a way to fit chart onto plot area
+ // and provide u2p and p2u functionality for mouse cursor, etc.
+ // for convienence set _dataBounds to 0 and 100 and
+ // set min/max to 0 and 100.
+ this._dataBounds = {min:0, max:100};
+ this.min = 0;
+ this.max = 100;
+ this.showTicks = false;
+ this.ticks = [];
+ this.showMark = false;
+ this.show = false;
+ };
+
+
+
+
+ $.jqplot.PieLegendRenderer = function(){
+ $.jqplot.TableLegendRenderer.call(this);
+ };
+
+ $.jqplot.PieLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+ $.jqplot.PieLegendRenderer.prototype.constructor = $.jqplot.PieLegendRenderer;
+
+ /**
+ * Class: $.jqplot.PieLegendRenderer
+ * Legend Renderer specific to pie plots. Set by default
+ * when user creates a pie plot.
+ */
+ $.jqplot.PieLegendRenderer.prototype.init = function(options) {
+ // Group: Properties
+ //
+ // prop: numberRows
+ // Maximum number of rows in the legend. 0 or null for unlimited.
+ this.numberRows = null;
+ // prop: numberColumns
+ // Maximum number of columns in the legend. 0 or null for unlimited.
+ this.numberColumns = null;
+ $.extend(true, this, options);
+ };
+
+ // called with context of legend
+ $.jqplot.PieLegendRenderer.prototype.draw = function() {
+ var legend = this;
+ if (this.show) {
+ var series = this._series;
+
+
+ this._elem = $(document.createElement('table'));
+ this._elem.addClass('jqplot-table-legend');
+
+ var ss = {position:'absolute'};
+ if (this.background) {
+ ss['background'] = this.background;
+ }
+ if (this.border) {
+ ss['border'] = this.border;
+ }
+ if (this.fontSize) {
+ ss['fontSize'] = this.fontSize;
+ }
+ if (this.fontFamily) {
+ ss['fontFamily'] = this.fontFamily;
+ }
+ if (this.textColor) {
+ ss['textColor'] = this.textColor;
+ }
+ if (this.marginTop != null) {
+ ss['marginTop'] = this.marginTop;
+ }
+ if (this.marginBottom != null) {
+ ss['marginBottom'] = this.marginBottom;
+ }
+ if (this.marginLeft != null) {
+ ss['marginLeft'] = this.marginLeft;
+ }
+ if (this.marginRight != null) {
+ ss['marginRight'] = this.marginRight;
+ }
+
+ this._elem.css(ss);
+
+ // Pie charts legends don't go by number of series, but by number of data points
+ // in the series. Refactor things here for that.
+
+ var pad = false,
+ reverse = false,
+ nr,
+ nc;
+ var s = series[0];
+ var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
+
+ if (s.show) {
+ var pd = s.data;
+ if (this.numberRows) {
+ nr = this.numberRows;
+ if (!this.numberColumns){
+ nc = Math.ceil(pd.length/nr);
+ }
+ else{
+ nc = this.numberColumns;
+ }
+ }
+ else if (this.numberColumns) {
+ nc = this.numberColumns;
+ nr = Math.ceil(pd.length/this.numberColumns);
+ }
+ else {
+ nr = pd.length;
+ nc = 1;
+ }
+
+ var i, j;
+ var tr, td1, td2;
+ var lt, rs, color;
+ var idx = 0;
+ var div0, div1;
+
+ for (i=0; i<nr; i++) {
+ tr = $(document.createElement('tr'));
+ tr.addClass('jqplot-table-legend');
+
+ if (reverse){
+ tr.prependTo(this._elem);
+ }
+
+ else{
+ tr.appendTo(this._elem);
+ }
+
+ for (j=0; j<nc; j++) {
+ if (idx < pd.length){
+ lt = this.labels[idx] || pd[idx][0].toString();
+ color = colorGenerator.next();
+ if (!reverse){
+ if (i>0){
+ pad = true;
+ }
+ else{
+ pad = false;
+ }
+ }
+ else{
+ if (i == nr -1){
+ pad = false;
+ }
+ else{
+ pad = true;
+ }
+ }
+ rs = (pad) ? this.rowSpacing : '0';
+
+
+
+ td1 = $(document.createElement('td'));
+ td1.addClass('jqplot-table-legend jqplot-table-legend-swatch');
+ td1.css({textAlign: 'center', paddingTop: rs});
+
+ div0 = $(document.createElement('div'));
+ div0.addClass('jqplot-table-legend-swatch-outline');
+ div1 = $(document.createElement('div'));
+ div1.addClass('jqplot-table-legend-swatch');
+ div1.css({backgroundColor: color, borderColor: color});
+ td1.append(div0.append(div1));
+
+ td2 = $(document.createElement('td'));
+ td2.addClass('jqplot-table-legend jqplot-table-legend-label');
+ td2.css('paddingTop', rs);
+
+ if (this.escapeHtml){
+ td2.text(lt);
+ }
+ else {
+ td2.html(lt);
+ }
+ if (reverse) {
+ td2.prependTo(tr);
+ td1.prependTo(tr);
+ }
+ else {
+ td1.appendTo(tr);
+ td2.appendTo(tr);
+ }
+ pad = true;
+ }
+ idx++;
+ }
+ }
+ }
+ }
+ return this._elem;
+ };
+
+ $.jqplot.PieRenderer.prototype.handleMove = function(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ plot.target.trigger('jqplotDataMouseOver', ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ plot.target.trigger('jqplotDataHighlight', ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ };
+
+
+ // this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]);
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.legend = options.legend || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ // only set these if there is a pie series
+ var setopts = false;
+ if (options.seriesDefaults.renderer == $.jqplot.PieRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer == $.jqplot.PieRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.PieAxisRenderer;
+ options.legend.renderer = $.jqplot.PieLegendRenderer;
+ options.legend.preDraw = true;
+ options.seriesDefaults.pointLabels = {show: false};
+ }
+ }
+
+ function postInit(target, data, options) {
+ for (var i=0; i<this.series.length; i++) {
+ if (this.series[i].renderer.constructor == $.jqplot.PieRenderer) {
+ // don't allow mouseover and mousedown at same time.
+ if (this.series[i].highlightMouseOver) {
+ this.series[i].highlightMouseDown = false;
+ }
+ }
+ }
+ }
+
+ // called with scope of plot
+ function postParseOptions(options) {
+ for (var i=0; i<this.series.length; i++) {
+ this.series[i].seriesColors = this.seriesColors;
+ this.series[i].colorGenerator = $.jqplot.colorGenerator;
+ }
+ }
+
+ function highlight (plot, sidx, pidx) {
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.pieRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.pieRenderer.highlightedSeriesIndex = sidx;
+ s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColorGenerator.get(pidx), false);
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.pieRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.pieRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ }
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, ins[0], ins[1]);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
+ var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ }
+
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt = jQuery.Event('jqplotDataClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var idx = plot.plugins.pieRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ var evt = jQuery.Event('jqplotDataRightClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.pieRenderer && this.plugins.pieRenderer.highlightCanvas) {
+ this.plugins.pieRenderer.highlightCanvas.resetCanvas();
+ this.plugins.pieRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.pieRenderer = {highlightedSeriesIndex:null};
+ this.plugins.pieRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ // do we have any data labels? if so, put highlight canvas before those
+ var labels = $(this.targetId+' .jqplot-data-label');
+ if (labels.length) {
+ $(labels[0]).before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this));
+ }
+ // else put highlight canvas before event canvas.
+ else {
+ this.eventCanvas._elem.before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this));
+ }
+
+ var hctx = this.plugins.pieRenderer.highlightCanvas.setContext();
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
+ }
+
+ $.jqplot.preInitHooks.push(preInit);
+
+ $.jqplot.PieTickRenderer = function() {
+ $.jqplot.AxisTickRenderer.call(this);
+ };
+
+ $.jqplot.PieTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
+ $.jqplot.PieTickRenderer.prototype.constructor = $.jqplot.PieTickRenderer;
+
+})(jQuery);
+
+ \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.pointLabels.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.pointLabels.js
new file mode 100644
index 00000000..c20a9c44
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.pointLabels.js
@@ -0,0 +1,379 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+
+ /**
+ * Class: $.jqplot.PointLabels
+ * Plugin for putting labels at the data points.
+ *
+ * To use this plugin, include the js
+ * file in your source:
+ *
+ * > <script type="text/javascript" src="plugins/jqplot.pointLabels.js"></script>
+ *
+ * By default, the last value in the data ponit array in the data series is used
+ * for the label. For most series renderers, extra data can be added to the
+ * data point arrays and the last value will be used as the label.
+ *
+ * For instance,
+ * this series:
+ *
+ * > [[1,4], [3,5], [7,2]]
+ *
+ * Would, by default, use the y values in the labels.
+ * Extra data can be added to the series like so:
+ *
+ * > [[1,4,'mid'], [3 5,'hi'], [7,2,'low']]
+ *
+ * And now the point labels would be 'mid', 'low', and 'hi'.
+ *
+ * Options to the point labels and a custom labels array can be passed into the
+ * "pointLabels" option on the series option like so:
+ *
+ * > series:[{pointLabels:{
+ * > labels:['mid', 'hi', 'low'],
+ * > location:'se',
+ * > ypadding: 12
+ * > }
+ * > }]
+ *
+ * A custom labels array in the options takes precendence over any labels
+ * in the series data. If you have a custom labels array in the options,
+ * but still want to use values from the series array as labels, set the
+ * "labelsFromSeries" option to true.
+ *
+ * By default, html entities (<, >, etc.) are escaped in point labels.
+ * If you want to include actual html markup in the labels,
+ * set the "escapeHTML" option to false.
+ *
+ */
+ $.jqplot.PointLabels = function(options) {
+ // Group: Properties
+ //
+ // prop: show
+ // show the labels or not.
+ this.show = $.jqplot.config.enablePlugins;
+ // prop: location
+ // compass location where to position the label around the point.
+ // 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
+ this.location = 'n';
+ // prop: labelsFromSeries
+ // true to use labels within data point arrays.
+ this.labelsFromSeries = false;
+ // prop: seriesLabelIndex
+ // array index for location of labels within data point arrays.
+ // if null, will use the last element of the data point array.
+ this.seriesLabelIndex = null;
+ // prop: labels
+ // array of arrays of labels, one array for each series.
+ this.labels = [];
+ // actual labels that will get displayed.
+ // needed to preserve user specified labels in labels array.
+ this._labels = [];
+ // prop: stackedValue
+ // true to display value as stacked in a stacked plot.
+ // no effect if labels is specified.
+ this.stackedValue = false;
+ // prop: ypadding
+ // vertical padding in pixels between point and label
+ this.ypadding = 6;
+ // prop: xpadding
+ // horizontal padding in pixels between point and label
+ this.xpadding = 6;
+ // prop: escapeHTML
+ // true to escape html entities in the labels.
+ // If you want to include markup in the labels, set to false.
+ this.escapeHTML = true;
+ // prop: edgeTolerance
+ // Number of pixels that the label must be away from an axis
+ // boundary in order to be drawn. Negative values will allow overlap
+ // with the grid boundaries.
+ this.edgeTolerance = -5;
+ // prop: formatter
+ // A class of a formatter for the tick text. sprintf by default.
+ this.formatter = $.jqplot.DefaultTickFormatter;
+ // prop: formatString
+ // string passed to the formatter.
+ this.formatString = '';
+ // prop: hideZeros
+ // true to not show a label for a value which is 0.
+ this.hideZeros = false;
+ this._elems = [];
+
+ $.extend(true, this, options);
+ };
+
+ var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];
+ var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7};
+ var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e'];
+
+ // called with scope of a series
+ $.jqplot.PointLabels.init = function (target, data, seriesDefaults, opts, plot){
+ var options = $.extend(true, {}, seriesDefaults, opts);
+ options.pointLabels = options.pointLabels || {};
+ if (this.renderer.constructor === $.jqplot.BarRenderer && this.barDirection === 'horizontal' && !options.pointLabels.location) {
+ options.pointLabels.location = 'e';
+ }
+ // add a pointLabels attribute to the series plugins
+ this.plugins.pointLabels = new $.jqplot.PointLabels(options.pointLabels);
+ this.plugins.pointLabels.setLabels.call(this);
+ };
+
+ // called with scope of series
+ $.jqplot.PointLabels.prototype.setLabels = function() {
+ var p = this.plugins.pointLabels;
+ var labelIdx;
+ if (p.seriesLabelIndex != null) {
+ labelIdx = p.seriesLabelIndex;
+ }
+ else if (this.renderer.constructor === $.jqplot.BarRenderer && this.barDirection === 'horizontal') {
+ labelIdx = 0;
+ }
+ else {
+ labelIdx = (this._plotData.length === 0) ? 0 : this._plotData[0].length -1;
+ }
+ p._labels = [];
+ if (p.labels.length === 0 || p.labelsFromSeries) {
+ if (p.stackedValue) {
+ if (this._plotData.length && this._plotData[0].length){
+ // var idx = p.seriesLabelIndex || this._plotData[0].length -1;
+ for (var i=0; i<this._plotData.length; i++) {
+ p._labels.push(this._plotData[i][labelIdx]);
+ }
+ }
+ }
+ else {
+ // var d = this._plotData;
+ var d = this.data;
+ if (this.renderer.constructor === $.jqplot.BarRenderer && this.waterfall) {
+ d = this._data;
+ }
+ if (d.length && d[0].length) {
+ // var idx = p.seriesLabelIndex || d[0].length -1;
+ for (var i=0; i<d.length; i++) {
+ p._labels.push(d[i][labelIdx]);
+ }
+ }
+ d = null;
+ }
+ }
+ else if (p.labels.length){
+ p._labels = p.labels;
+ }
+ };
+
+ $.jqplot.PointLabels.prototype.xOffset = function(elem, location, padding) {
+ location = location || this.location;
+ padding = padding || this.xpadding;
+ var offset;
+
+ switch (location) {
+ case 'nw':
+ offset = -elem.outerWidth(true) - this.xpadding;
+ break;
+ case 'n':
+ offset = -elem.outerWidth(true)/2;
+ break;
+ case 'ne':
+ offset = this.xpadding;
+ break;
+ case 'e':
+ offset = this.xpadding;
+ break;
+ case 'se':
+ offset = this.xpadding;
+ break;
+ case 's':
+ offset = -elem.outerWidth(true)/2;
+ break;
+ case 'sw':
+ offset = -elem.outerWidth(true) - this.xpadding;
+ break;
+ case 'w':
+ offset = -elem.outerWidth(true) - this.xpadding;
+ break;
+ default: // same as 'nw'
+ offset = -elem.outerWidth(true) - this.xpadding;
+ break;
+ }
+ return offset;
+ };
+
+ $.jqplot.PointLabels.prototype.yOffset = function(elem, location, padding) {
+ location = location || this.location;
+ padding = padding || this.xpadding;
+ var offset;
+
+ switch (location) {
+ case 'nw':
+ offset = -elem.outerHeight(true) - this.ypadding;
+ break;
+ case 'n':
+ offset = -elem.outerHeight(true) - this.ypadding;
+ break;
+ case 'ne':
+ offset = -elem.outerHeight(true) - this.ypadding;
+ break;
+ case 'e':
+ offset = -elem.outerHeight(true)/2;
+ break;
+ case 'se':
+ offset = this.ypadding;
+ break;
+ case 's':
+ offset = this.ypadding;
+ break;
+ case 'sw':
+ offset = this.ypadding;
+ break;
+ case 'w':
+ offset = -elem.outerHeight(true)/2;
+ break;
+ default: // same as 'nw'
+ offset = -elem.outerHeight(true) - this.ypadding;
+ break;
+ }
+ return offset;
+ };
+
+ // called with scope of series
+ $.jqplot.PointLabels.draw = function (sctx, options, plot) {
+ var p = this.plugins.pointLabels;
+ // set labels again in case they have changed.
+ p.setLabels.call(this);
+ // remove any previous labels
+ for (var i=0; i<p._elems.length; i++) {
+ // Memory Leaks patch
+ // p._elems[i].remove();
+ p._elems[i].emptyForce();
+ }
+ p._elems.splice(0, p._elems.length);
+
+ if (p.show) {
+ var ax = '_'+this._stackAxis+'axis';
+
+ if (!p.formatString) {
+ p.formatString = this[ax]._ticks[0].formatString;
+ p.formatter = this[ax]._ticks[0].formatter;
+ }
+
+ var pd = this._plotData;
+ var ppd = this._prevPlotData;
+ var xax = this._xaxis;
+ var yax = this._yaxis;
+ var elem, helem;
+
+ for (var i=0, l=p._labels.length; i < l; i++) {
+ var label = p._labels[i];
+
+ if (p.hideZeros && parseInt(p._labels[i], 10) == 0) {
+ label = '';
+ }
+
+ if (label != null) {
+ label = p.formatter(p.formatString, label);
+ }
+
+ helem = document.createElement('div');
+ p._elems[i] = $(helem);
+
+ elem = p._elems[i];
+
+
+ elem.addClass('jqplot-point-label jqplot-series-'+this.index+' jqplot-point-'+i);
+ elem.css('position', 'absolute');
+ elem.insertAfter(sctx.canvas);
+
+ if (p.escapeHTML) {
+ elem.text(label);
+ }
+ else {
+ elem.html(label);
+ }
+ var location = p.location;
+ if ((this.fillToZero && pd[i][1] < 0) || (this.fillToZero && this._type === 'bar' && this.barDirection === 'horizontal' && pd[i][0] < 0) || (this.waterfall && parseInt(label, 10)) < 0) {
+ location = oppositeLocations[locationIndicies[location]];
+ }
+
+
+ var ell = xax.u2p(pd[i][0]) + p.xOffset(elem, location);
+ var elt = yax.u2p(pd[i][1]) + p.yOffset(elem, location);
+
+ // we have stacked chart but are not showing stacked values,
+ // place labels in center.
+ if (this._stack && !p.stackedValue) {
+ if (this.barDirection === "vertical") {
+ elt = (this._barPoints[i][0][1] + this._barPoints[i][1][1]) / 2 + plot._gridPadding.top - 0.5 * elem.outerHeight(true);
+ }
+ else {
+ ell = (this._barPoints[i][2][0] + this._barPoints[i][0][0]) / 2 + plot._gridPadding.left - 0.5 * elem.outerWidth(true);
+ }
+ }
+
+ if (this.renderer.constructor == $.jqplot.BarRenderer) {
+ if (this.barDirection == "vertical") {
+ ell += this._barNudge;
+ }
+ else {
+ elt -= this._barNudge;
+ }
+ }
+ elem.css('left', ell);
+ elem.css('top', elt);
+ var elr = ell + elem.width();
+ var elb = elt + elem.height();
+ var et = p.edgeTolerance;
+ var scl = $(sctx.canvas).position().left;
+ var sct = $(sctx.canvas).position().top;
+ var scr = sctx.canvas.width + scl;
+ var scb = sctx.canvas.height + sct;
+ // if label is outside of allowed area, remove it
+ if (ell - et < scl || elt - et < sct || elr + et > scr || elb + et > scb) {
+ elem.remove();
+ }
+
+ elem = null;
+ helem = null;
+ }
+
+ // finally, animate them if the series is animated
+ // if (this.renderer.animation && this.renderer.animation._supported && this.renderer.animation.show && plot._drawCount < 2) {
+ // var sel = '.jqplot-point-label.jqplot-series-'+this.index;
+ // $(sel).hide();
+ // $(sel).fadeIn(1000);
+ // }
+
+ }
+ };
+
+ $.jqplot.postSeriesInitHooks.push($.jqplot.PointLabels.init);
+ $.jqplot.postDrawSeriesHooks.push($.jqplot.PointLabels.draw);
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidAxisRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidAxisRenderer.js
new file mode 100644
index 00000000..4035488a
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidAxisRenderer.js
@@ -0,0 +1,728 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ $.jqplot.PyramidAxisRenderer = function() {
+ $.jqplot.LinearAxisRenderer.call(this);
+ };
+
+ $.jqplot.PyramidAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+ $.jqplot.PyramidAxisRenderer.prototype.constructor = $.jqplot.PyramidAxisRenderer;
+
+ // called with scope of axis
+ $.jqplot.PyramidAxisRenderer.prototype.init = function(options){
+ // Group: Properties
+ //
+ // prop: position
+ // Position of axis. Values are: top, bottom , left, center, right.
+ // By default, x and x2 axes are bottom, y axis is center.
+ this.position = null;
+ // prop: drawBaseline
+ // True to draw the axis baseline.
+ this.drawBaseline = true;
+ // prop: baselineWidth
+ // width of the baseline in pixels.
+ this.baselineWidth = null;
+ // prop: baselineColor
+ // CSS color spec for the baseline.
+ this.baselineColor = null;
+ this.tickSpacingFactor = 25;
+ this._type = 'pyramid';
+ this._splitAxis = false;
+ this._splitLength = null;
+ this.category = false;
+ this._autoFormatString = '';
+ this._overrideFormatString = false;
+
+ $.extend(true, this, options);
+ this.renderer.options = options;
+
+ this.resetDataBounds = this.renderer.resetDataBounds;
+ this.resetDataBounds();
+
+ };
+
+ $.jqplot.PyramidAxisRenderer.prototype.resetDataBounds = function() {
+ // Go through all the series attached to this axis and find
+ // the min/max bounds for this axis.
+ var db = this._dataBounds;
+ db.min = null;
+ db.max = null;
+ var temp;
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ var d = s._plotData;
+
+ for (var j=0, l=d.length; j<l; j++) {
+ if (this.name.charAt(0) === 'x') {
+ temp = d[j][1];
+ if ((temp !== null && temp < db.min) || db.min === null) {
+ db.min = temp;
+ }
+ if ((temp !== null && temp > db.max) || db.max === null) {
+ db.max = temp;
+ }
+ }
+ else {
+ temp = d[j][0];
+ if ((temp !== null && temp < db.min) || db.min === null) {
+ db.min = temp;
+ }
+ if ((temp !== null && temp > db.max) || db.max === null) {
+ db.max = temp;
+ }
+ }
+ }
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.PyramidAxisRenderer.prototype.draw = function(ctx, plot) {
+ if (this.show) {
+ // populate the axis label and value properties.
+ // createTicks is a method on the renderer, but
+ // call it within the scope of the axis.
+ this.renderer.createTicks.call(this, plot);
+ // fill a div with axes labels in the right direction.
+ // Need to pregenerate each axis to get it's bounds and
+ // position it and the labels correctly on the plot.
+ var dim=0;
+ var temp;
+ // Added for theming.
+ if (this._elem) {
+ // Memory Leaks patch
+ //this._elem.empty();
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ this._elem = $(document.createElement('div'));
+ this._elem.addClass('jqplot-axis jqplot-'+this.name);
+ this._elem.css('position', 'absolute');
+
+
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ this._elem.width(this._plotDimensions.width);
+ }
+ else {
+ this._elem.height(this._plotDimensions.height);
+ }
+
+ // create a _label object.
+ this.labelOptions.axis = this.name;
+ this._label = new this.labelRenderer(this.labelOptions);
+ if (this._label.show) {
+ var elem = this._label.draw(ctx, plot);
+ elem.appendTo(this._elem);
+ elem = null;
+ }
+
+ var t = this._ticks;
+ var tick;
+ for (var i=0; i<t.length; i++) {
+ tick = t[i];
+ if (tick.show && tick.showLabel && (!tick.isMinorTick)) {
+ this._elem.append(tick.draw(ctx, plot));
+ }
+ }
+ tick = null;
+ t = null;
+ }
+ return this._elem;
+ };
+
+ // Note, primes can be found on http://primes.utm.edu/
+ var _primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997];
+
+
+ var _primesHash = {};
+
+ for (var i =0, l = _primes.length; i < l; i++) {
+ _primesHash[_primes[i]] = _primes[i];
+ }
+
+ // called with scope of axis
+ $.jqplot.PyramidAxisRenderer.prototype.createTicks = function(plot) {
+ // we're are operating on an axis here
+ var userTicks = this.ticks;
+ // databounds were set on axis initialization.
+ var db = this._dataBounds;
+ var dim;
+ var interval;
+ var min;
+ var max;
+ var range;
+ var pos1;
+ var pos2;
+ var tt;
+ var i;
+ var l;
+ var s;
+ // get a copy of user's settings for min/max.
+ var userMin = this.min;
+ var userMax = this.max;
+ var ut;
+ var t;
+ var threshold;
+ var tdim;
+ var scalefact;
+ var ret;
+ var tumin;
+ var tumax;
+ var maxVisibleTicks;
+ var val;
+ var skip = null;
+ var temp;
+
+ // if we already have ticks, use them.
+ // ticks must be in order of increasing value.
+
+ if (userTicks.length) {
+ // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
+ for (i=0, l=userTicks.length; i<l; i++){
+ ut = userTicks[i];
+ t = new this.tickRenderer(this.tickOptions);
+ if ($.isArray(ut)) {
+ t.value = ut[0];
+ t.label = ut[1];
+ t.setTick(ut[0], this.name);
+ this._ticks.push(t);
+ }
+
+ else if ($.isPlainObject(ut)) {
+ $.extend(true, t, ut);
+ t.axis = this.name;
+ this._ticks.push(t);
+ }
+
+ else {
+ if (typeof ut === 'string') {
+ val = i + plot.defaultAxisStart;
+ }
+ else {
+ val = ut;
+ }
+ t.value = val;
+ t.label = ut;
+ t.axis = this.name;
+ this._ticks.push(t);
+ }
+ }
+ this.numberTicks = userTicks.length;
+ this.min = this._ticks[0].value;
+ this.max = this._ticks[this.numberTicks-1].value;
+ this.tickInterval = (this.max - this.min) / (this.numberTicks - 1);
+
+ // use user specified tickInterval if there is one
+ if (this._options.tickInterval) {
+ // hide every tick except for ticks on interval
+ var ti = this._options.tickInterval;
+ for (i=0; i<this.numberTicks; i++) {
+ if (i%ti !== 0) {
+ // this._ticks[i].show = false;
+ this._ticks[i].isMinorTick = true;
+ }
+ }
+ }
+
+ else {
+ // check if we have too many ticks
+ dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height;
+ maxVisibleTicks = Math.round(2.0 + dim/this.tickSpacingFactor);
+
+ if (this.numberTicks > maxVisibleTicks) {
+ // check for number of ticks we can skip
+ temp = this.numberTicks - 1;
+ for (i=2; i<temp; i++) {
+ if (temp % i === 0 && temp/i < maxVisibleTicks) {
+ skip = i-1;
+ break;
+ }
+ }
+
+ if (skip !== null) {
+ var count = 1;
+ for (i=1, l=this._ticks.length; i<l; i++) {
+ if (count <= skip) {
+ this._ticks[i].show = false;
+ count += 1;
+ }
+ else {
+ count = 1;
+ }
+ }
+ }
+ }
+ }
+
+ // if category style, add minor ticks in between
+ temp = [];
+ if (this.category) {
+ // turn off gridline and mark on first tick
+ this._ticks[0].showGridline = false;
+ this._ticks[0].showMark = false;
+
+ for (i=this._ticks.length-1; i>0; i--) {
+ t = new this.tickRenderer(this.tickOptions);
+ t.value = this._ticks[i-1].value + this.tickInterval/2.0;
+ t.label = '';
+ t.showLabel = false;
+ t.axis = this.name;
+ this._ticks[i].showGridline = false;
+ this._ticks[i].showMark = false;
+ this._ticks.splice(i, 0, t);
+ // temp.push(t);
+ }
+
+ // merge in the new ticks
+ // for (i=1, l=temp.length; i<l; i++) {
+ // this._ticks.splice(i, 0, temp[i]);
+ // }
+
+ // now add a tick at beginning and end
+ t = new this.tickRenderer(this.tickOptions);
+ t.value = this._ticks[0].value - this.tickInterval/2.0;
+ t.label = '';
+ t.showLabel = false;
+ t.axis = this.name;
+ this._ticks.unshift(t);
+
+ t = new this.tickRenderer(this.tickOptions);
+ t.value = this._ticks[this._ticks.length-1].value + this.tickInterval/2.0;
+ t.label = '';
+ t.showLabel = false;
+ t.axis = this.name;
+ this._ticks.push(t);
+
+ this.tickInterval = this.tickInterval / 2.0;
+ this.numberTicks = this._ticks.length;
+ this.min = this._ticks[0].value;
+ this.max = this._ticks[this._ticks.length-1].value;
+ }
+ }
+
+ // we don't have any ticks yet, let's make some!
+ else {
+ if (this.name.charAt(0) === 'x') {
+ dim = this._plotDimensions.width;
+ // make sure x axis is symetric about 0.
+ var tempmax = Math.max(db.max, Math.abs(db.min));
+ var tempmin = Math.min(db.min, -tempmax);
+ // min = ((this.min != null) ? this.min : tempmin);
+ // max = ((this.max != null) ? this.max : tempmax);
+ min = tempmin;
+ max = tempmax;
+ range = max - min;
+
+ if (this.tickOptions == null || !this.tickOptions.formatString) {
+ this._overrideFormatString = true;
+ }
+
+ threshold = 30;
+ tdim = Math.max(dim, threshold+1);
+ scalefact = (tdim-threshold)/300.0;
+ ret = $.jqplot.LinearTickGenerator(min, max, scalefact);
+ // calculate a padded max and min, points should be less than these
+ // so that they aren't too close to the edges of the plot.
+ // User can adjust how much padding is allowed with pad, padMin and PadMax options.
+ tumin = min + range*(this.padMin - 1);
+ tumax = max - range*(this.padMax - 1);
+
+ if (min < tumin || max > tumax) {
+ tumin = min - range*(this.padMin - 1);
+ tumax = max + range*(this.padMax - 1);
+ ret = $.jqplot.LinearTickGenerator(tumin, tumax, scalefact);
+ }
+
+ this.min = ret[0];
+ this.max = ret[1];
+ this.numberTicks = ret[2];
+ this._autoFormatString = ret[3];
+ this.tickInterval = ret[4];
+ }
+ else {
+ dim = this._plotDimensions.height;
+
+ // ticks will be on whole integers like 1, 2, 3, ... or 1, 4, 7, ...
+ min = db.min;
+ max = db.max;
+ s = this._series[0];
+ this._ticks = [];
+
+ range = max - min;
+
+ // if range is a prime, will get only 2 ticks, expand range in that case.
+ if (_primesHash[range]) {
+ range += 1;
+ max += 1;
+ }
+
+ this.max = max;
+ this.min = min;
+
+ maxVisibleTicks = Math.round(2.0 + dim/this.tickSpacingFactor);
+
+ if (range + 1 <= maxVisibleTicks) {
+ this.numberTicks = range + 1;
+ this.tickInterval = 1.0;
+ }
+
+ else {
+ // figure out a round number of ticks to skip in every interval
+ // range / ti + 1 = nt
+ // ti = range / (nt - 1)
+ for (var i=maxVisibleTicks; i>1; i--) {
+ if (range/(i - 1) === Math.round(range/(i - 1))) {
+ this.numberTicks = i;
+ this.tickInterval = range/(i - 1);
+ break;
+ }
+
+ }
+ }
+ }
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ this.tickOptions = this.tickOptions || {};
+ this.tickOptions.formatString = this._autoFormatString;
+ }
+
+ var labelval;
+ for (i=0; i<this.numberTicks; i++) {
+ this.tickOptions.axis = this.name;
+ labelval = this.min + this.tickInterval * i;
+ if (this.name.charAt(0) === 'x') {
+ labelval = Math.abs(labelval);
+ }
+ // this.tickOptions.label = String (labelval);
+ this.tickOptions.value = this.min + this.tickInterval * i;
+ t = new this.tickRenderer(this.tickOptions);
+
+ t.label = t.prefix + t.formatter(t.formatString, labelval);
+
+ this._ticks.push(t);
+ // for x axis, if y axis is in middle, add a symetrical 0 tick
+ if (this.name.charAt(0) === 'x' && plot.axes.yMidAxis.show && this.tickOptions.value === 0) {
+ this._splitAxis = true;
+ this._splitLength = plot.axes.yMidAxis.getWidth();
+ // t.value = -this.max/2000.0;
+ t = new this.tickRenderer(this.tickOptions);
+ this._ticks.push(t);
+ t.value = this.max/2000.0;
+ }
+ }
+ t = null;
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.PyramidAxisRenderer.prototype.set = function() {
+ var dim = 0;
+ var temp;
+ var w = 0;
+ var h = 0;
+ var i;
+ var t;
+ var tick;
+ var lshow = (this._label == null) ? false : this._label.show;
+ if (this.show) {
+ t = this._ticks;
+ l = t.length;
+ for (i=0; i<l; i++) {
+ tick = t[i];
+ if (!tick._breakTick && tick.show && tick.showLabel && !tick.isMinorTick) {
+ if (this.name.charAt(0) === 'x') {
+ temp = tick._elem.outerHeight(true);
+ }
+ else {
+ temp = tick._elem.outerWidth(true);
+ }
+ if (temp > dim) {
+ dim = temp;
+ }
+ }
+ }
+
+ if (this.name === 'yMidAxis') {
+ for (i=0; i<l; i++) {
+ tick = t[i];
+ if (tick._elem) {
+ temp = (dim - tick._elem.outerWidth(true))/2.0;
+ tick._elem.css('left', temp);
+ }
+ }
+ }
+ tick = null;
+ t = null;
+
+ if (lshow) {
+ w = this._label._elem.outerWidth(true);
+ h = this._label._elem.outerHeight(true);
+ }
+ if (this.name === 'xaxis') {
+ dim = dim + h;
+ this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});
+ }
+ else if (this.name === 'x2axis') {
+ dim = dim + h;
+ this._elem.css({'height':dim+'px', left:'0px', top:'0px'});
+ }
+ else if (this.name === 'yaxis') {
+ dim = dim + w;
+ this._elem.css({'width':dim+'px', left:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ else if (this.name === 'yMidAxis') {
+ // don't include width of label at all in width of axis?
+ // dim = (dim > w) ? dim : w;
+ var temp = dim/2.0 - w/2.0;
+ this._elem.css({'width':dim+'px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css({width: w, left: temp, top: 0});
+ }
+ }
+ else {
+ dim = dim + w;
+ this._elem.css({'width':dim+'px', right:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ }
+ };
+
+ $.jqplot.PyramidAxisRenderer.prototype.pack = function(pos, offsets) {
+ // Add defaults for repacking from resetTickValues function.
+ pos = pos || {};
+ offsets = offsets || this._offsets;
+
+ var ticks = this._ticks;
+ var max = this.max;
+ var min = this.min;
+ var offmax = offsets.max;
+ var offmin = offsets.min;
+ var lshow = (this._label == null) ? false : this._label.show;
+
+ for (var p in pos) {
+ this._elem.css(p, pos[p]);
+ }
+
+ this._offsets = offsets;
+ // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
+ var pixellength = offmax - offmin;
+ var unitlength = max - min;
+ var sl = this._splitLength;
+
+ // point to unit and unit to point conversions references to Plot DOM element top left corner.
+ if (this._splitAxis) {
+ pixellength -= this._splitLength;
+
+ // don't know that this one is correct.
+ this.p2u = function(p){
+ return (p - offmin) * unitlength / pixellength + min;
+ };
+
+ this.u2p = function(u){
+ if (u <= 0) {
+ return (u - min) * pixellength / unitlength + offmin;
+ }
+ else {
+ return (u - min) * pixellength / unitlength + offmin + sl;
+ }
+ };
+
+ this.series_u2p = function(u){
+ if (u <= 0) {
+ return (u - min) * pixellength / unitlength;
+ }
+ else {
+ return (u - min) * pixellength / unitlength + sl;
+ }
+ };
+
+ // don't know that this one is correct.
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+ else {
+ this.p2u = function(p){
+ return (p - offmin) * unitlength / pixellength + min;
+ };
+
+ this.u2p = function(u){
+ return (u - min) * pixellength / unitlength + offmin;
+ };
+
+ if (this.name.charAt(0) === 'x'){
+ this.series_u2p = function(u){
+ return (u - min) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+
+ else {
+ this.series_u2p = function(u){
+ return (u - max) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + max;
+ };
+ }
+ }
+
+ if (this.show) {
+ if (this.name.charAt(0) === 'x') {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'xaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ if (temp * t.angle < 0) {
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ }
+ // position at start
+ else {
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'end':
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ case 'start':
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ break;
+ case 'middle':
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ default:
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getWidth()/2;
+ }
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('left', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var w = this._label._elem.outerWidth(true);
+ this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
+ if (this.name == 'xaxis') {
+ this._label._elem.css('bottom', '0px');
+ }
+ else {
+ this._label._elem.css('top', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ else {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel && !t.isMinorTick) {
+ var shim;
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'yaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ case 'end':
+ if (temp * t.angle < 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'start':
+ if (t.angle > 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'middle':
+ // if (t.angle > 0) {
+ // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ // }
+ // else {
+ // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ // }
+ shim = -t.getHeight()/2;
+ break;
+ default:
+ shim = -t.getHeight()/2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getHeight()/2;
+ }
+
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('top', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var h = this._label._elem.outerHeight(true);
+ if (this.name !== 'yMidAxis') {
+ this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
+ }
+ if (this.name == 'yaxis') {
+ this._label._elem.css('left', '0px');
+ }
+ else if (this.name !== 'yMidAxis') {
+ this._label._elem.css('right', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ }
+
+ ticks = null;
+ };
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidGridRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidGridRenderer.js
new file mode 100644
index 00000000..6124cbad
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidGridRenderer.js
@@ -0,0 +1,429 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+ // Class: $.jqplot.CanvasGridRenderer
+ // The default jqPlot grid renderer, creating a grid on a canvas element.
+ // The renderer has no additional options beyond the <Grid> class.
+ $.jqplot.PyramidGridRenderer = function(){
+ $.jqplot.CanvasGridRenderer.call(this);
+ };
+
+ $.jqplot.PyramidGridRenderer.prototype = new $.jqplot.CanvasGridRenderer();
+ $.jqplot.PyramidGridRenderer.prototype.constructor = $.jqplot.PyramidGridRenderer;
+
+ // called with context of Grid object
+ $.jqplot.CanvasGridRenderer.prototype.init = function(options) {
+ this._ctx;
+ this.plotBands = {
+ show: false,
+ color: 'rgb(230, 219, 179)',
+ axis: 'y',
+ start: null,
+ interval: 10
+ };
+ $.extend(true, this, options);
+ // set the shadow renderer options
+ var sopts = {lineJoin:'miter', lineCap:'round', fill:false, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.shadowWidth, closePath:false, strokeStyle:this.shadowColor};
+ this.renderer.shadowRenderer.init(sopts);
+ };
+
+ $.jqplot.PyramidGridRenderer.prototype.draw = function() {
+ this._ctx = this._elem.get(0).getContext("2d");
+ var ctx = this._ctx;
+ var axes = this._axes;
+ var xp = axes.xaxis.u2p;
+ var yp = axes.yMidAxis.u2p;
+ var xnudge = axes.xaxis.max/1000.0;
+ var xp0 = xp(0);
+ var xpn = xp(xnudge);
+ var ax = ['xaxis', 'yaxis', 'x2axis', 'y2axis','yMidAxis'];
+ // Add the grid onto the grid canvas. This is the bottom most layer.
+ ctx.save();
+ ctx.clearRect(0, 0, this._plotDimensions.width, this._plotDimensions.height);
+ ctx.fillStyle = this.backgroundColor || this.background;
+
+ ctx.fillRect(this._left, this._top, this._width, this._height);
+
+ if (this.plotBands.show) {
+ ctx.save();
+ var pb = this.plotBands;
+ ctx.fillStyle = pb.color;
+ var axis;
+ var x, y, w, h;
+ // find axis to work with
+ if (pb.axis.charAt(0) === 'x') {
+ if (axes.xaxis.show) {
+ axis = axes.xaxis;
+ }
+ }
+ else if (pb.axis.charAt(0) === 'y') {
+ if (axes.yaxis.show) {
+ axis = axes.yaxis;
+ }
+ else if (axes.y2axis.show) {
+ axis = axes.y2axis;
+ }
+ else if (axes.yMidAxis.show) {
+ axis = axes.yMidAxis;
+ }
+ }
+
+ if (axis !== undefined) {
+ // draw some rectangles
+ var start = pb.start;
+ if (start === null) {
+ start = axis.min;
+ }
+ for (var i = start; i < axis.max; i += 2 * pb.interval) {
+ if (axis.name.charAt(0) === 'y') {
+ x = this._left;
+ if ((i + pb.interval) < axis.max) {
+ y = axis.series_u2p(i + pb.interval) + this._top;
+ }
+ else {
+ y = axis.series_u2p(axis.max) + this._top;
+ }
+ w = this._right - this._left;
+ h = axis.series_u2p(start) - axis.series_u2p(start + pb.interval);
+ ctx.fillRect(x, y, w, h);
+ }
+ // else {
+ // y = 0;
+ // x = axis.series_u2p(i);
+ // h = this._height;
+ // w = axis.series_u2p(start + pb.interval) - axis.series_u2p(start);
+ // }
+
+ }
+ }
+ ctx.restore();
+ }
+
+ ctx.save();
+ ctx.lineJoin = 'miter';
+ ctx.lineCap = 'butt';
+ ctx.lineWidth = this.gridLineWidth;
+ ctx.strokeStyle = this.gridLineColor;
+ var b, e, s, m;
+ for (var i=5; i>0; i--) {
+ var name = ax[i-1];
+ var axis = axes[name];
+ var ticks = axis._ticks;
+ var numticks = ticks.length;
+ if (axis.show) {
+ if (axis.drawBaseline) {
+ var bopts = {};
+ if (axis.baselineWidth !== null) {
+ bopts.lineWidth = axis.baselineWidth;
+ }
+ if (axis.baselineColor !== null) {
+ bopts.strokeStyle = axis.baselineColor;
+ }
+ switch (name) {
+ case 'xaxis':
+ if (axes.yMidAxis.show) {
+ drawLine (this._left, this._bottom, xp0, this._bottom, bopts);
+ drawLine (xpn, this._bottom, this._right, this._bottom, bopts);
+ }
+ else {
+ drawLine (this._left, this._bottom, this._right, this._bottom, bopts);
+ }
+ break;
+ case 'yaxis':
+ drawLine (this._left, this._bottom, this._left, this._top, bopts);
+ break;
+ case 'yMidAxis':
+ drawLine(xp0, this._bottom, xp0, this._top, bopts);
+ drawLine(xpn, this._bottom, xpn, this._top, bopts);
+ break;
+ case 'x2axis':
+ if (axes.yMidAxis.show) {
+ drawLine (this._left, this._top, xp0, this._top, bopts);
+ drawLine (xpn, this._top, this._right, this._top, bopts);
+ }
+ else {
+ drawLine (this._left, this._bottom, this._right, this._bottom, bopts);
+ }
+ break;
+ case 'y2axis':
+ drawLine (this._right, this._bottom, this._right, this._top, bopts);
+ break;
+
+ }
+ }
+ for (var j=numticks; j>0; j--) {
+ var t = ticks[j-1];
+ if (t.show) {
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (name) {
+ case 'xaxis':
+ // draw the grid line if we should
+ if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) {
+ drawLine(pos, this._top, pos, this._bottom);
+ }
+
+ // draw the mark
+ if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._bottom;
+ e = this._bottom+s;
+ break;
+ case 'inside':
+ b = this._bottom-s;
+ e = this._bottom;
+ break;
+ case 'cross':
+ b = this._bottom-s;
+ e = this._bottom+s;
+ break;
+ default:
+ b = this._bottom;
+ e = this._bottom+s;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false});
+ }
+ // draw the line
+ drawLine(pos, b, pos, e);
+ }
+ break;
+ case 'yaxis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) {
+ drawLine(this._right, pos, this._left, pos);
+ }
+
+ // draw the mark
+ if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._left-s;
+ e = this._left;
+ break;
+ case 'inside':
+ b = this._left;
+ e = this._left+s;
+ break;
+ case 'cross':
+ b = this._left-s;
+ e = this._left+s;
+ break;
+ default:
+ b = this._left-s;
+ e = this._left;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+ }
+ break;
+ case 'yMidAxis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) {
+ drawLine(this._left, pos, xp0, pos);
+ drawLine(xpn, pos, this._right, pos);
+ }
+ // draw the mark
+ if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+
+ b = xp0;
+ e = xp0 + s;
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+
+ b = xpn - s;
+ e = xpn;
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+ }
+ break;
+ case 'x2axis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) {
+ drawLine(pos, this._bottom, pos, this._top);
+ }
+
+ // draw the mark
+ if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._top-s;
+ e = this._top;
+ break;
+ case 'inside':
+ b = this._top;
+ e = this._top+s;
+ break;
+ case 'cross':
+ b = this._top-s;
+ e = this._top+s;
+ break;
+ default:
+ b = this._top-s;
+ e = this._top;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false});
+ }
+ drawLine(pos, b, pos, e);
+ }
+ break;
+ case 'y2axis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && (!t.isMinorTick || axis.showMinorTicks)) {
+ drawLine(this._left, pos, this._right, pos);
+ }
+
+ // draw the mark
+ if (t.showMark && t.mark && (!t.isMinorTick || axis.showMinorTicks)) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._right;
+ e = this._right+s;
+ break;
+ case 'inside':
+ b = this._right-s;
+ e = this._right;
+ break;
+ case 'cross':
+ b = this._right-s;
+ e = this._right+s;
+ break;
+ default:
+ b = this._right;
+ e = this._right+s;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ t = null;
+ }
+ axis = null;
+ ticks = null;
+ }
+
+ ctx.restore();
+
+ function drawLine(bx, by, ex, ey, opts) {
+ ctx.save();
+ opts = opts || {};
+ if (opts.lineWidth == null || opts.lineWidth != 0){
+ $.extend(true, ctx, opts);
+ ctx.beginPath();
+ ctx.moveTo(bx, by);
+ ctx.lineTo(ex, ey);
+ ctx.stroke();
+ }
+ ctx.restore();
+ }
+
+ if (this.shadow) {
+ if (axes.yMidAxis.show) {
+ var points = [[this._left, this._bottom], [xp0, this._bottom]];
+ this.renderer.shadowRenderer.draw(ctx, points);
+ var points = [[xpn, this._bottom], [this._right, this._bottom], [this._right, this._top]];
+ this.renderer.shadowRenderer.draw(ctx, points);
+ var points = [[xp0, this._bottom], [xp0, this._top]];
+ this.renderer.shadowRenderer.draw(ctx, points);
+ }
+ else {
+ var points = [[this._left, this._bottom], [this._right, this._bottom], [this._right, this._top]];
+ this.renderer.shadowRenderer.draw(ctx, points);
+ }
+ }
+ // Now draw border around grid. Use axis border definitions. start at
+ // upper left and go clockwise.
+ if (this.borderWidth != 0 && this.drawBorder) {
+ if (axes.yMidAxis.show) {
+ drawLine (this._left, this._top, xp0, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth});
+ drawLine (xpn, this._top, this._right, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth});
+ drawLine (this._right, this._top, this._right, this._bottom, {lineCap:'round', strokeStyle:axes.y2axis.borderColor, lineWidth:axes.y2axis.borderWidth});
+ drawLine (this._right, this._bottom, xpn, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth});
+ drawLine (xp0, this._bottom, this._left, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth});
+ drawLine (this._left, this._bottom, this._left, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth});
+ drawLine (xp0, this._bottom, xp0, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth});
+ drawLine (xpn, this._bottom, xpn, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth});
+ }
+ else {
+ drawLine (this._left, this._top, this._right, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth});
+ drawLine (this._right, this._top, this._right, this._bottom, {lineCap:'round', strokeStyle:axes.y2axis.borderColor, lineWidth:axes.y2axis.borderWidth});
+ drawLine (this._right, this._bottom, this._left, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth});
+ drawLine (this._left, this._bottom, this._left, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth});
+ }
+ }
+ // ctx.lineWidth = this.borderWidth;
+ // ctx.strokeStyle = this.borderColor;
+ // ctx.strokeRect(this._left, this._top, this._width, this._height);
+
+ ctx.restore();
+ ctx = null;
+ axes = null;
+ };
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidRenderer.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidRenderer.js
new file mode 100644
index 00000000..185b94a7
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.pyramidRenderer.js
@@ -0,0 +1,514 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+
+ // Need to ensure pyramid axis and grid renderers are loaded.
+ // You should load these with script tags in the html head, that is more efficient
+ // as the browser will cache the request.
+ // Note, have to block with synchronous request in order to execute bar renderer code.
+ if ($.jqplot.PyramidAxisRenderer === undefined) {
+ $.ajax({
+ url: $.jqplot.pluginLocation + 'jqplot.pyramidAxisRenderer.js',
+ dataType: "script",
+ async: false
+ });
+ }
+
+ if ($.jqplot.PyramidGridRenderer === undefined) {
+ $.ajax({
+ url: $.jqplot.pluginLocation + 'jqplot.pyramidGridRenderer.js',
+ dataType: "script",
+ async: false
+ });
+ }
+
+ $.jqplot.PyramidRenderer = function(){
+ $.jqplot.LineRenderer.call(this);
+ };
+
+ $.jqplot.PyramidRenderer.prototype = new $.jqplot.LineRenderer();
+ $.jqplot.PyramidRenderer.prototype.constructor = $.jqplot.PyramidRenderer;
+
+ // called with scope of a series
+ $.jqplot.PyramidRenderer.prototype.init = function(options, plot) {
+ options = options || {};
+ this._type = 'pyramid';
+ // Group: Properties
+ //
+ // prop: barPadding
+ this.barPadding = 10;
+ this.barWidth = null;
+ // prop: fill
+ // True to fill the bars.
+ this.fill = true;
+ // prop: highlightMouseOver
+ // True to highlight slice when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on a slice.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over a slice.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColors
+ // an array of colors to use when highlighting a slice.
+ this.highlightColors = [];
+ // prop highlightThreshold
+ // Expand the highlightable region in the x direction.
+ // E.g. a value of 3 will highlight a bar when the mouse is
+ // within 3 pixels of the bar in the x direction.
+ this.highlightThreshold = 2;
+ // prop: synchronizeHighlight
+ // Index of another series to highlight when this series is highlighted.
+ // null or false to not synchronize.
+ this.synchronizeHighlight = false;
+ // prop: offsetBars
+ // False will center bars on their y value.
+ // True will push bars up by 1/2 bar width to fill between their y values.
+ // If true, there needs to be 1 more tick than there are bars.
+ this.offsetBars = false;
+
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (options.highlightMouseDown && options.highlightMouseOver == null) {
+ options.highlightMouseOver = false;
+ }
+
+ this.side = 'right';
+
+ $.extend(true, this, options);
+
+ // if (this.fill === false) {
+ // this.shadow = false;
+ // }
+
+ if (this.side === 'left') {
+ this._highlightThreshold = [[-this.highlightThreshold, 0], [-this.highlightThreshold, 0], [0,0], [0,0]];
+ }
+
+ else {
+ this._highlightThreshold = [[0,0], [0,0], [this.highlightThreshold, 0], [this.highlightThreshold, 0]];
+ }
+
+ this.renderer.options = options;
+ // index of the currenty highlighted point, if any
+ this._highlightedPoint = null;
+ // Array of actual data colors used for each data point.
+ this._dataColors = [];
+ this._barPoints = [];
+ this.fillAxis = 'y';
+ this._primaryAxis = '_yaxis';
+ this._xnudge = 0;
+
+ // set the shape renderer options
+ var opts = {lineJoin:'miter', lineCap:'butt', fill:this.fill, fillRect:this.fill, isarc:false, strokeStyle:this.color, fillStyle:this.color, closePath:this.fill, lineWidth: this.lineWidth};
+ this.renderer.shapeRenderer.init(opts);
+ // set the shadow renderer options
+ var shadow_offset = options.shadowOffset;
+ // set the shadow renderer options
+ if (shadow_offset == null) {
+ // scale the shadowOffset to the width of the line.
+ if (this.lineWidth > 2.5) {
+ shadow_offset = 1.25 * (1 + (Math.atan((this.lineWidth/2.5))/0.785398163 - 1)*0.6);
+ // var shadow_offset = this.shadowOffset;
+ }
+ // for skinny lines, don't make such a big shadow.
+ else {
+ shadow_offset = 1.25 * Math.atan((this.lineWidth/2.5))/0.785398163;
+ }
+ }
+ var sopts = {lineJoin:'miter', lineCap:'butt', fill:this.fill, fillRect:this.fill, isarc:false, angle:this.shadowAngle, offset:shadow_offset, alpha:this.shadowAlpha, depth:this.shadowDepth, closePath:this.fill, lineWidth: this.lineWidth};
+ this.renderer.shadowRenderer.init(sopts);
+
+ plot.postDrawHooks.addOnce(postPlotDraw);
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+
+ // if this is the left side of pyramid, set y values to negative.
+ if (this.side === 'left') {
+ for (var i=0, l=this.data.length; i<l; i++) {
+ this.data[i][1] = -Math.abs(this.data[i][1]);
+ }
+ }
+ };
+
+ // setGridData
+ // converts the user data values to grid coordinates and stores them
+ // in the gridData array.
+ // Called with scope of a series.
+ $.jqplot.PyramidRenderer.prototype.setGridData = function(plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var data = this._plotData;
+ var pdata = this._prevPlotData;
+ this.gridData = [];
+ this._prevGridData = [];
+ var l = data.length;
+ var adjust = false;
+ var i;
+
+ // if any data values are < 0, consider this a negative series
+ for (i = 0; i < l; i++) {
+ if (data[i][1] < 0) {
+ this.side = 'left';
+ }
+ }
+
+ if (this._yaxis.name === 'yMidAxis' && this.side === 'right') {
+ this._xnudge = this._xaxis.max/2000.0;
+ adjust = true;
+ }
+
+ for (i = 0; i < l; i++) {
+ // if not a line series or if no nulls in data, push the converted point onto the array.
+ if (data[i][0] != null && data[i][1] != null) {
+ this.gridData.push([xp(data[i][1]), yp(data[i][0])]);
+ }
+ // else if there is a null, preserve it.
+ else if (data[i][0] == null) {
+ this.gridData.push([xp(data[i][1]), null]);
+ }
+ else if (data[i][1] == null) {
+ this.gridData.push(null, [yp(data[i][0])]);
+ }
+ // finally, adjust x grid data if have to
+ if (data[i][1] === 0 && adjust) {
+ this.gridData[i][0] = xp(this._xnudge);
+ }
+ }
+ };
+
+ // makeGridData
+ // converts any arbitrary data values to grid coordinates and
+ // returns them. This method exists so that plugins can use a series'
+ // linerenderer to generate grid data points without overwriting the
+ // grid data associated with that series.
+ // Called with scope of a series.
+ $.jqplot.PyramidRenderer.prototype.makeGridData = function(data, plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var gd = [];
+ var l = data.length;
+ var adjust = false;
+ var i;
+
+ // if any data values are < 0, consider this a negative series
+ for (i = 0; i < l; i++) {
+ if (data[i][1] < 0) {
+ this.side = 'left';
+ }
+ }
+
+ if (this._yaxis.name === 'yMidAxis' && this.side === 'right') {
+ this._xnudge = this._xaxis.max/2000.0;
+ adjust = true;
+ }
+
+ for (i = 0; i < l; i++) {
+ // if not a line series or if no nulls in data, push the converted point onto the array.
+ if (data[i][0] != null && data[i][1] != null) {
+ gd.push([xp(data[i][1]), yp(data[i][0])]);
+ }
+ // else if there is a null, preserve it.
+ else if (data[i][0] == null) {
+ gd.push([xp(data[i][1]), null]);
+ }
+ else if (data[i][1] == null) {
+ gd.push([null, yp(data[i][0])]);
+ }
+ // finally, adjust x grid data if have to
+ if (data[i][1] === 0 && adjust) {
+ gd[i][0] = xp(this._xnudge);
+ }
+ }
+
+ return gd;
+ };
+
+ $.jqplot.PyramidRenderer.prototype.setBarWidth = function() {
+ // need to know how many data values we have on the approprate axis and figure it out.
+ var i;
+ var nvals = 0;
+ var nseries = 0;
+ var paxis = this[this._primaryAxis];
+ var s, series, pos;
+ nvals = paxis.max - paxis.min;
+ var nticks = paxis.numberTicks;
+ var nbins = (nticks-1)/2;
+ // so, now we have total number of axis values.
+ var temp = (this.barPadding === 0) ? 1.0 : 0;
+ if (paxis.name == 'xaxis' || paxis.name == 'x2axis') {
+ this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals - this.barPadding + temp;
+ }
+ else {
+ if (this.fill) {
+ this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals - this.barPadding + temp;
+ }
+ else {
+ this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals;
+ }
+ }
+ };
+
+ $.jqplot.PyramidRenderer.prototype.draw = function(ctx, gridData, options) {
+ var i;
+ // Ughhh, have to make a copy of options b/c it may be modified later.
+ var opts = $.extend({}, options);
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var pointx, pointy;
+ // clear out data colors.
+ this._dataColors = [];
+ this._barPoints = [];
+
+ if (this.renderer.options.barWidth == null) {
+ this.renderer.setBarWidth.call(this);
+ }
+
+ // var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this);
+ // var nvals = temp[0];
+ // var nseries = temp[1];
+ // var pos = temp[2];
+ var points = [],
+ w,
+ h;
+
+ // this._barNudge = 0;
+
+ if (showLine) {
+ var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors);
+ var positiveColors = new $.jqplot.ColorGenerator(this.seriesColors);
+ var negativeColor = negativeColors.get(this.index);
+ if (! this.useNegativeColors) {
+ negativeColor = opts.fillStyle;
+ }
+ var positiveColor = opts.fillStyle;
+ var base;
+ var xstart = this._xaxis.series_u2p(this._xnudge);
+ var ystart = this._yaxis.series_u2p(this._yaxis.min);
+ var yend = this._yaxis.series_u2p(this._yaxis.max);
+ var bw = this.barWidth;
+ var bw2 = bw/2.0;
+ var points = [];
+ var yadj = this.offsetBars ? bw2 : 0;
+
+ for (var i=0, l=gridData.length; i<l; i++) {
+ if (this.data[i][0] == null) {
+ continue;
+ }
+ base = gridData[i][1];
+ // not stacked and first series in stack
+
+ if (this._plotData[i][1] < 0) {
+ if (this.varyBarColor && !this._stack) {
+ if (this.useNegativeColors) {
+ opts.fillStyle = negativeColors.next();
+ }
+ else {
+ opts.fillStyle = positiveColors.next();
+ }
+ }
+ }
+ else {
+ if (this.varyBarColor && !this._stack) {
+ opts.fillStyle = positiveColors.next();
+ }
+ else {
+ opts.fillStyle = positiveColor;
+ }
+ }
+
+ if (this.fill) {
+
+ if (this._plotData[i][1] >= 0) {
+ // xstart = this._xaxis.series_u2p(this._xnudge);
+ w = gridData[i][0] - xstart;
+ h = this.barWidth;
+ points = [xstart, base - bw2 - yadj, w, h];
+ }
+ else {
+ // xstart = this._xaxis.series_u2p(0);
+ w = xstart - gridData[i][0];
+ h = this.barWidth;
+ points = [gridData[i][0], base - bw2 - yadj, w, h];
+ }
+
+ this._barPoints.push([[points[0], points[1] + h], [points[0], points[1]], [points[0] + w, points[1]], [points[0] + w, points[1] + h]]);
+
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, points);
+ }
+ var clr = opts.fillStyle || this.color;
+ this._dataColors.push(clr);
+ this.renderer.shapeRenderer.draw(ctx, points, opts);
+ }
+
+ else {
+ if (i === 0) {
+ points =[[xstart, ystart], [gridData[i][0], ystart], [gridData[i][0], gridData[i][1] - bw2 - yadj]];
+ }
+
+ else if (i < l-1) {
+ points = points.concat([[gridData[i-1][0], gridData[i-1][1] - bw2 - yadj], [gridData[i][0], gridData[i][1] + bw2 - yadj], [gridData[i][0], gridData[i][1] - bw2 - yadj]]);
+ }
+
+ // finally, draw the line
+ else {
+ points = points.concat([[gridData[i-1][0], gridData[i-1][1] - bw2 - yadj], [gridData[i][0], gridData[i][1] + bw2 - yadj], [gridData[i][0], yend], [xstart, yend]]);
+
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, points);
+ }
+ var clr = opts.fillStyle || this.color;
+ this._dataColors.push(clr);
+ this.renderer.shapeRenderer.draw(ctx, points, opts);
+ }
+ }
+ }
+ }
+
+ if (this.highlightColors.length == 0) {
+ this.highlightColors = $.jqplot.computeHighlightColors(this._dataColors);
+ }
+
+ else if (typeof(this.highlightColors) == 'string') {
+ this.highlightColors = [];
+ for (var i=0; i<this._dataColors.length; i++) {
+ this.highlightColors.push(this.highlightColors);
+ }
+ }
+
+ };
+
+
+ // setup default renderers for axes and legend so user doesn't have to
+ // called with scope of plot
+ function preInit(target, data, options) {
+ options = options || {};
+ options.axesDefaults = options.axesDefaults || {};
+ options.grid = options.grid || {};
+ options.legend = options.legend || {};
+ options.seriesDefaults = options.seriesDefaults || {};
+ // only set these if there is a pie series
+ var setopts = false;
+ if (options.seriesDefaults.renderer === $.jqplot.PyramidRenderer) {
+ setopts = true;
+ }
+ else if (options.series) {
+ for (var i=0; i < options.series.length; i++) {
+ if (options.series[i].renderer === $.jqplot.PyramidRenderer) {
+ setopts = true;
+ }
+ }
+ }
+
+ if (setopts) {
+ options.axesDefaults.renderer = $.jqplot.PyramidAxisRenderer;
+ options.grid.renderer = $.jqplot.PyramidGridRenderer;
+ options.seriesDefaults.pointLabels = {show: false};
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.pyramidRenderer && this.plugins.pyramidRenderer.highlightCanvas) {
+
+ this.plugins.pyramidRenderer.highlightCanvas.resetCanvas();
+ this.plugins.pyramidRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.pyramidRenderer = {highlightedSeriesIndex:null};
+ this.plugins.pyramidRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ this.eventCanvas._elem.before(this.plugins.pyramidRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pyramidRenderer-highlight-canvas', this._plotDimensions, this));
+ this.plugins.pyramidRenderer.highlightCanvas.setContext();
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
+ }
+
+ function highlight (plot, sidx, pidx, points) {
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.pyramidRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.pyramidRenderer.highlightedSeriesIndex = sidx;
+ var opts = {fillStyle: s.highlightColors[pidx], fillRect: false};
+ s.renderer.shapeRenderer.draw(canvas._ctx, points, opts);
+ if (s.synchronizeHighlight !== false && plot.series.length >= s.synchronizeHighlight && s.synchronizeHighlight !== sidx) {
+ s = plot.series[s.synchronizeHighlight];
+ opts = {fillStyle: s.highlightColors[pidx], fillRect: false};
+ s.renderer.shapeRenderer.draw(canvas._ctx, s._barPoints[pidx], opts);
+ }
+ canvas = null;
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.pyramidRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.pyramidRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ canvas = null;
+ }
+
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pyramidRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ // Have to add hook here, becuase it needs called before series is inited.
+ $.jqplot.preInitHooks.push(preInit);
+
+
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jqplot.trendline.js b/SemanticResultFormats/resources/jquery/jqplot/jqplot.trendline.js
new file mode 100644
index 00000000..168fb7a6
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jqplot.trendline.js
@@ -0,0 +1,223 @@
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: 1.0.4
+ * Revision: 1121
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * Although not required, the author would appreciate an email letting him
+ * know of any substantial use of jqPlot. You can reach the author at:
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ */
+(function($) {
+
+ /**
+ * Class: $.jqplot.Trendline
+ * Plugin which will automatically compute and draw trendlines for plotted data.
+ */
+ $.jqplot.Trendline = function() {
+ // Group: Properties
+
+ // prop: show
+ // Wether or not to show the trend line.
+ this.show = $.jqplot.config.enablePlugins;
+ // prop: color
+ // CSS color spec for the trend line.
+ // By default this wil be the same color as the primary line.
+ this.color = '#666666';
+ // prop: renderer
+ // Renderer to use to draw the trend line.
+ // The data series that is plotted may not be rendered as a line.
+ // Therefore, we use our own line renderer here to draw a trend line.
+ this.renderer = new $.jqplot.LineRenderer();
+ // prop: rendererOptions
+ // Options to pass to the line renderer.
+ // By default, markers are not shown on trend lines.
+ this.rendererOptions = {marker:{show:false}};
+ // prop: label
+ // Label for the trend line to use in the legend.
+ this.label = '';
+ // prop: type
+ // Either 'exponential', 'exp', or 'linear'.
+ this.type = 'linear';
+ // prop: shadow
+ // true or false, wether or not to show the shadow.
+ this.shadow = true;
+ // prop: markerRenderer
+ // Renderer to use to draw markers on the line.
+ // I think this is wrong.
+ this.markerRenderer = {show:false};
+ // prop: lineWidth
+ // Width of the trend line.
+ this.lineWidth = 1.5;
+ // prop: shadowAngle
+ // Angle of the shadow on the trend line.
+ this.shadowAngle = 45;
+ // prop: shadowOffset
+ // pixel offset for each stroke of the shadow.
+ this.shadowOffset = 1.0;
+ // prop: shadowAlpha
+ // Alpha transparency of the shadow.
+ this.shadowAlpha = 0.07;
+ // prop: shadowDepth
+ // number of strokes to make of the shadow.
+ this.shadowDepth = 3;
+ this.isTrendline = true;
+
+ };
+
+ $.jqplot.postSeriesInitHooks.push(parseTrendLineOptions);
+ $.jqplot.postDrawSeriesHooks.push(drawTrendline);
+ $.jqplot.addLegendRowHooks.push(addTrendlineLegend);
+
+ // called witin scope of the legend object
+ // current series passed in
+ // must return null or an object {label:label, color:color}
+ function addTrendlineLegend(series) {
+ var ret = null;
+ if (series.trendline && series.trendline.show) {
+ var lt = series.trendline.label.toString();
+ if (lt) {
+ ret = {label:lt, color:series.trendline.color};
+ }
+ }
+ return ret;
+ }
+
+ // called within scope of a series
+ function parseTrendLineOptions (target, data, seriesDefaults, options, plot) {
+ if (this._type && (this._type === 'line' || this._type == 'bar')) {
+ this.trendline = new $.jqplot.Trendline();
+ options = options || {};
+ $.extend(true, this.trendline, {color:this.color}, seriesDefaults.trendline, options.trendline);
+ this.trendline.renderer.init.call(this.trendline, null);
+ }
+ }
+
+ // called within scope of series object
+ function drawTrendline(sctx, options) {
+ // if we have options, merge trendline options in with precedence
+ options = $.extend(true, {}, this.trendline, options);
+
+ if (this.trendline && options.show) {
+ var fit;
+ // this.renderer.setGridData.call(this);
+ var data = options.data || this.data;
+ fit = fitData(data, this.trendline.type);
+ var gridData = options.gridData || this.renderer.makeGridData.call(this, fit.data);
+ this.trendline.renderer.draw.call(this.trendline, sctx, gridData, {showLine:true, shadow:this.trendline.shadow});
+ }
+ }
+
+ function regression(x, y, typ) {
+ var type = (typ == null) ? 'linear' : typ;
+ var N = x.length;
+ var slope;
+ var intercept;
+ var SX = 0;
+ var SY = 0;
+ var SXX = 0;
+ var SXY = 0;
+ var SYY = 0;
+ var Y = [];
+ var X = [];
+
+ if (type == 'linear') {
+ X = x;
+ Y = y;
+ }
+ else if (type == 'exp' || type == 'exponential') {
+ for ( var i=0; i<y.length; i++) {
+ // ignore points <= 0, log undefined.
+ if (y[i] <= 0) {
+ N--;
+ }
+ else {
+ X.push(x[i]);
+ Y.push(Math.log(y[i]));
+ }
+ }
+ }
+
+ for ( var i = 0; i < N; i++) {
+ SX = SX + X[i];
+ SY = SY + Y[i];
+ SXY = SXY + X[i]* Y[i];
+ SXX = SXX + X[i]* X[i];
+ SYY = SYY + Y[i]* Y[i];
+ }
+
+ slope = (N*SXY - SX*SY)/(N*SXX - SX*SX);
+ intercept = (SY - slope*SX)/N;
+
+ return [slope, intercept];
+ }
+
+ function linearRegression(X,Y) {
+ var ret;
+ ret = regression(X,Y,'linear');
+ return [ret[0],ret[1]];
+ }
+
+ function expRegression(X,Y) {
+ var ret;
+ var x = X;
+ var y = Y;
+ ret = regression(x, y,'exp');
+ var base = Math.exp(ret[0]);
+ var coeff = Math.exp(ret[1]);
+ return [base, coeff];
+ }
+
+ function fitData(data, typ) {
+ var type = (typ == null) ? 'linear' : typ;
+ var ret;
+ var res;
+ var x = [];
+ var y = [];
+ var ypred = [];
+
+ for (i=0; i<data.length; i++){
+ if (data[i] != null && data[i][0] != null && data[i][1] != null) {
+ x.push(data[i][0]);
+ y.push(data[i][1]);
+ }
+ }
+
+ if (type == 'linear') {
+ ret = linearRegression(x,y);
+ for ( var i=0; i<x.length; i++){
+ res = ret[0]*x[i] + ret[1];
+ ypred.push([x[i], res]);
+ }
+ }
+ else if (type == 'exp' || type == 'exponential') {
+ ret = expRegression(x,y);
+ for ( var i=0; i<x.length; i++){
+ res = ret[1]*Math.pow(ret[0],x[i]);
+ ypred.push([x[i], res]);
+ }
+ }
+ return {data: ypred, slope: ret[0], intercept: ret[1]};
+ }
+
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.css b/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.css
new file mode 100644
index 00000000..d30bafb1
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.css
@@ -0,0 +1,259 @@
+/*rules for the plot target div. These will be cascaded down to all plot elements according to css rules*/
+.jqplot-target {
+ position: relative;
+ color: #666666;
+ font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
+ font-size: 1em;
+/* height: 300px;
+ width: 400px;*/
+}
+
+/*rules applied to all axes*/
+.jqplot-axis {
+ font-size: 0.75em;
+}
+
+.jqplot-xaxis {
+ margin-top: 10px;
+}
+
+.jqplot-x2axis {
+ margin-bottom: 10px;
+}
+
+.jqplot-yaxis {
+ margin-right: 10px;
+}
+
+.jqplot-y2axis, .jqplot-y3axis, .jqplot-y4axis, .jqplot-y5axis, .jqplot-y6axis, .jqplot-y7axis, .jqplot-y8axis, .jqplot-y9axis, .jqplot-yMidAxis {
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+/*rules applied to all axis tick divs*/
+.jqplot-axis-tick, .jqplot-xaxis-tick, .jqplot-yaxis-tick, .jqplot-x2axis-tick, .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick, .jqplot-yMidAxis-tick {
+ position: absolute;
+ white-space: pre;
+}
+
+
+.jqplot-xaxis-tick {
+ top: 0px;
+ /* initial position untill tick is drawn in proper place */
+ left: 15px;
+/* padding-top: 10px;*/
+ vertical-align: top;
+}
+
+.jqplot-x2axis-tick {
+ bottom: 0px;
+ /* initial position untill tick is drawn in proper place */
+ left: 15px;
+/* padding-bottom: 10px;*/
+ vertical-align: bottom;
+}
+
+.jqplot-yaxis-tick {
+ right: 0px;
+ /* initial position untill tick is drawn in proper place */
+ top: 15px;
+/* padding-right: 10px;*/
+ text-align: right;
+}
+
+.jqplot-yaxis-tick.jqplot-breakTick {
+ right: -20px;
+ margin-right: 0px;
+ padding:1px 5px 1px 5px;
+/* background-color: white;*/
+ z-index: 2;
+ font-size: 1.5em;
+}
+
+.jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick {
+ left: 0px;
+ /* initial position untill tick is drawn in proper place */
+ top: 15px;
+/* padding-left: 10px;*/
+/* padding-right: 15px;*/
+ text-align: left;
+}
+
+.jqplot-yMidAxis-tick {
+ text-align: center;
+ white-space: nowrap;
+}
+
+.jqplot-xaxis-label {
+ margin-top: 10px;
+ font-size: 11pt;
+ position: absolute;
+}
+
+.jqplot-x2axis-label {
+ margin-bottom: 10px;
+ font-size: 11pt;
+ position: absolute;
+}
+
+.jqplot-yaxis-label {
+ margin-right: 10px;
+/* text-align: center;*/
+ font-size: 11pt;
+ position: absolute;
+}
+
+.jqplot-yMidAxis-label {
+ font-size: 11pt;
+ position: absolute;
+}
+
+.jqplot-y2axis-label, .jqplot-y3axis-label, .jqplot-y4axis-label, .jqplot-y5axis-label, .jqplot-y6axis-label, .jqplot-y7axis-label, .jqplot-y8axis-label, .jqplot-y9axis-label {
+/* text-align: center;*/
+ font-size: 11pt;
+ margin-left: 10px;
+ position: absolute;
+}
+
+.jqplot-meterGauge-tick {
+ font-size: 0.75em;
+ color: #999999;
+}
+
+.jqplot-meterGauge-label {
+ font-size: 1em;
+ color: #999999;
+}
+
+table.jqplot-table-legend {
+ margin-top: 12px;
+ margin-bottom: 12px;
+ margin-left: 12px;
+ margin-right: 12px;
+}
+
+table.jqplot-table-legend, table.jqplot-cursor-legend {
+ background-color: rgba(255,255,255,0.6);
+ border: 1px solid #cccccc;
+ position: absolute;
+ font-size: 0.75em;
+}
+
+td.jqplot-table-legend {
+ vertical-align:middle;
+}
+
+/*
+These rules could be used instead of assigning
+element styles and relying on js object properties.
+*/
+
+/*
+td.jqplot-table-legend-swatch {
+ padding-top: 0.5em;
+ text-align: center;
+}
+
+tr.jqplot-table-legend:first td.jqplot-table-legend-swatch {
+ padding-top: 0px;
+}
+*/
+
+td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active {
+ cursor: pointer;
+}
+
+.jqplot-table-legend .jqplot-series-hidden {
+ text-decoration: line-through;
+}
+
+div.jqplot-table-legend-swatch-outline {
+ border: 1px solid #cccccc;
+ padding:1px;
+}
+
+div.jqplot-table-legend-swatch {
+ width:0px;
+ height:0px;
+ border-top-width: 5px;
+ border-bottom-width: 5px;
+ border-left-width: 6px;
+ border-right-width: 6px;
+ border-top-style: solid;
+ border-bottom-style: solid;
+ border-left-style: solid;
+ border-right-style: solid;
+}
+
+.jqplot-title {
+ top: 0px;
+ left: 0px;
+ padding-bottom: 0.5em;
+ font-size: 1.2em;
+}
+
+table.jqplot-cursor-tooltip {
+ border: 1px solid #cccccc;
+ font-size: 0.75em;
+}
+
+
+.jqplot-cursor-tooltip {
+ border: 1px solid #cccccc;
+ font-size: 0.75em;
+ white-space: nowrap;
+ background: rgba(208,208,208,0.5);
+ padding: 1px;
+}
+
+.jqplot-highlighter-tooltip, .jqplot-canvasOverlay-tooltip {
+ border: 1px solid #cccccc;
+ font-size: 0.75em;
+ white-space: nowrap;
+ background: rgba(208,208,208,0.5);
+ padding: 1px;
+}
+
+.jqplot-point-label {
+ font-size: 0.75em;
+ z-index: 2;
+}
+
+td.jqplot-cursor-legend-swatch {
+ vertical-align: middle;
+ text-align: center;
+}
+
+div.jqplot-cursor-legend-swatch {
+ width: 1.2em;
+ height: 0.7em;
+}
+
+.jqplot-error {
+/* Styles added to the plot target container when there is an error go here.*/
+ text-align: center;
+}
+
+.jqplot-error-message {
+/* Styling of the custom error message div goes here.*/
+ position: relative;
+ top: 46%;
+ display: inline-block;
+}
+
+div.jqplot-bubble-label {
+ font-size: 0.8em;
+/* background: rgba(90%, 90%, 90%, 0.15);*/
+ padding-left: 2px;
+ padding-right: 2px;
+ color: rgb(20%, 20%, 20%);
+}
+
+div.jqplot-bubble-label.jqplot-bubble-label-highlight {
+ background: rgba(90%, 90%, 90%, 0.7);
+}
+
+div.jqplot-noData-container {
+ text-align: center;
+ background-color: rgba(96%, 96%, 96%, 0.3);
+}
diff --git a/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.js b/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.js
new file mode 100644
index 00000000..cded47ab
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jqplot/jquery.jqplot.js
@@ -0,0 +1,11381 @@
+/**
+ * Title: jqPlot Charts
+ *
+ * Pure JavaScript plotting plugin for jQuery.
+ *
+ * About: Version
+ *
+ * version: 1.0.4
+ * revision: 1121
+ *
+ * About: Copyright & License
+ *
+ * Copyright (c) 2009-2012 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects
+ * under both the MIT and GPL version 2.0 licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * See <GPL Version 2> and <MIT License> contained within this distribution for further information.
+ *
+ * The author would appreciate an email letting him know of any substantial
+ * use of jqPlot. You can reach the author at: chris at jqplot dot com
+ * or see http://www.jqplot.com/info.php. This is, of course, not required.
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php.
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ * version 2007.04.27
+ * author Ash Searle
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ * The author (Ash Searle) has placed this code in the public domain:
+ * "This code is unrestricted: you are free to use it however you like."
+ *
+ *
+ * About: Introduction
+ *
+ * jqPlot requires jQuery (1.4+ required for certain features). jQuery 1.4.2 is included in the distribution.
+ * To use jqPlot include jQuery, the jqPlot jQuery plugin, the jqPlot css file and optionally
+ * the excanvas script for IE support in your web page:
+ *
+ * > <!--[if lt IE 9]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]-->
+ * > <script language="javascript" type="text/javascript" src="jquery-1.4.4.min.js"></script>
+ * > <script language="javascript" type="text/javascript" src="jquery.jqplot.min.js"></script>
+ * > <link rel="stylesheet" type="text/css" href="jquery.jqplot.css" />
+ *
+ * jqPlot can be customized by overriding the defaults of any of the objects which make
+ * up the plot. The general usage of jqplot is:
+ *
+ * > chart = $.jqplot('targetElemId', [dataArray,...], {optionsObject});
+ *
+ * The options available to jqplot are detailed in <jqPlot Options> in the jqPlotOptions.txt file.
+ *
+ * An actual call to $.jqplot() may look like the
+ * examples below:
+ *
+ * > chart = $.jqplot('chartdiv', [[[1, 2],[3,5.12],[5,13.1],[7,33.6],[9,85.9],[11,219.9]]]);
+ *
+ * or
+ *
+ * > dataArray = [34,12,43,55,77];
+ * > chart = $.jqplot('targetElemId', [dataArray, ...], {title:'My Plot', axes:{yaxis:{min:20, max:100}}});
+ *
+ * For more inforrmation, see <jqPlot Usage>.
+ *
+ * About: Usage
+ *
+ * See <jqPlot Usage>
+ *
+ * About: Available Options
+ *
+ * See <jqPlot Options> for a list of options available thorugh the options object (not complete yet!)
+ *
+ * About: Options Usage
+ *
+ * See <Options Tutorial>
+ *
+ * About: Changes
+ *
+ * See <Change Log>
+ *
+ */
+
+(function($) {
+ // make sure undefined is undefined
+ var undefined;
+
+ $.fn.emptyForce = function() {
+ for ( var i = 0, elem; (elem = $(this)[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ $.cleanData( elem.getElementsByTagName("*") );
+ }
+
+ // Remove any remaining nodes
+ if ($.jqplot.use_excanvas) {
+ elem.outerHTML = "";
+ }
+ else {
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+ }
+
+ elem = null;
+ }
+
+ return $(this);
+ };
+
+ $.fn.removeChildForce = function(parent) {
+ while ( parent.firstChild ) {
+ this.removeChildForce( parent.firstChild );
+ parent.removeChild( parent.firstChild );
+ }
+ };
+
+ $.fn.jqplot = function() {
+ var datas = [];
+ var options = [];
+ // see how many data arrays we have
+ for (var i=0, l=arguments.length; i<l; i++) {
+ if ($.isArray(arguments[i])) {
+ datas.push(arguments[i]);
+ }
+ else if ($.isPlainObject(arguments[i])) {
+ options.push(arguments[i]);
+ }
+ }
+
+ return this.each(function(index) {
+ var tid,
+ plot,
+ $this = $(this),
+ dl = datas.length,
+ ol = options.length,
+ data,
+ opts;
+
+ if (index < dl) {
+ data = datas[index];
+ }
+ else {
+ data = dl ? datas[dl-1] : null;
+ }
+
+ if (index < ol) {
+ opts = options[index];
+ }
+ else {
+ opts = ol ? options[ol-1] : null;
+ }
+
+ // does el have an id?
+ // if not assign it one.
+ tid = $this.attr('id');
+ if (tid === undefined) {
+ tid = 'jqplot_target_' + $.jqplot.targetCounter++;
+ $this.attr('id', tid);
+ }
+
+ plot = $.jqplot(tid, data, opts);
+
+ $this.data('jqplot', plot);
+ });
+ };
+
+
+ /**
+ * Namespace: $.jqplot
+ * jQuery function called by the user to create a plot.
+ *
+ * Parameters:
+ * target - ID of target element to render the plot into.
+ * data - an array of data series.
+ * options - user defined options object. See the individual classes for available options.
+ *
+ * Properties:
+ * config - object to hold configuration information for jqPlot plot object.
+ *
+ * attributes:
+ * enablePlugins - False to disable plugins by default. Plugins must then be explicitly
+ * enabled in the individual plot options. Default: false.
+ * This property sets the "show" property of certain plugins to true or false.
+ * Only plugins that can be immediately active upon loading are affected. This includes
+ * non-renderer plugins like cursor, dragable, highlighter, and trendline.
+ * defaultHeight - Default height for plots where no css height specification exists. This
+ * is a jqplot wide default.
+ * defaultWidth - Default height for plots where no css height specification exists. This
+ * is a jqplot wide default.
+ */
+
+ $.jqplot = function(target, data, options) {
+ var _data = null, _options = null;
+
+ if (arguments.length === 3) {
+ _data = data;
+ _options = options;
+ }
+
+ else if (arguments.length === 2) {
+ if ($.isArray(data)) {
+ _data = data;
+ }
+
+ else if ($.isPlainObject(data)) {
+ _options = data;
+ }
+ }
+
+ if (_data === null && _options !== null && _options.data) {
+ _data = _options.data;
+ }
+
+ var plot = new jqPlot();
+ // remove any error class that may be stuck on target.
+ $('#'+target).removeClass('jqplot-error');
+
+ if ($.jqplot.config.catchErrors) {
+ try {
+ plot.init(target, _data, _options);
+ plot.draw();
+ plot.themeEngine.init.call(plot);
+ return plot;
+ }
+ catch(e) {
+ var msg = $.jqplot.config.errorMessage || e.message;
+ $('#'+target).append('<div class="jqplot-error-message">'+msg+'</div>');
+ $('#'+target).addClass('jqplot-error');
+ document.getElementById(target).style.background = $.jqplot.config.errorBackground;
+ document.getElementById(target).style.border = $.jqplot.config.errorBorder;
+ document.getElementById(target).style.fontFamily = $.jqplot.config.errorFontFamily;
+ document.getElementById(target).style.fontSize = $.jqplot.config.errorFontSize;
+ document.getElementById(target).style.fontStyle = $.jqplot.config.errorFontStyle;
+ document.getElementById(target).style.fontWeight = $.jqplot.config.errorFontWeight;
+ }
+ }
+ else {
+ plot.init(target, _data, _options);
+ plot.draw();
+ plot.themeEngine.init.call(plot);
+ return plot;
+ }
+ };
+
+ $.jqplot.version = "1.0.4";
+ $.jqplot.revision = "1121";
+
+ $.jqplot.targetCounter = 1;
+
+ // canvas manager to reuse canvases on the plot.
+ // Should help solve problem of canvases not being freed and
+ // problem of waiting forever for firefox to decide to free memory.
+ $.jqplot.CanvasManager = function() {
+ // canvases are managed globally so that they can be reused
+ // across plots after they have been freed
+ if (typeof $.jqplot.CanvasManager.canvases == 'undefined') {
+ $.jqplot.CanvasManager.canvases = [];
+ $.jqplot.CanvasManager.free = [];
+ }
+
+ var myCanvases = [];
+
+ this.getCanvas = function() {
+ var canvas;
+ var makeNew = true;
+
+ if (!$.jqplot.use_excanvas) {
+ for (var i = 0, l = $.jqplot.CanvasManager.canvases.length; i < l; i++) {
+ if ($.jqplot.CanvasManager.free[i] === true) {
+ makeNew = false;
+ canvas = $.jqplot.CanvasManager.canvases[i];
+ // $(canvas).removeClass('jqplot-canvasManager-free').addClass('jqplot-canvasManager-inuse');
+ $.jqplot.CanvasManager.free[i] = false;
+ myCanvases.push(i);
+ break;
+ }
+ }
+ }
+
+ if (makeNew) {
+ canvas = document.createElement('canvas');
+ myCanvases.push($.jqplot.CanvasManager.canvases.length);
+ $.jqplot.CanvasManager.canvases.push(canvas);
+ $.jqplot.CanvasManager.free.push(false);
+ }
+
+ return canvas;
+ };
+
+ // this method has to be used after settings the dimesions
+ // on the element returned by getCanvas()
+ this.initCanvas = function(canvas) {
+ if ($.jqplot.use_excanvas) {
+ return window.G_vmlCanvasManager.initElement(canvas);
+ }
+ return canvas;
+ };
+
+ this.freeAllCanvases = function() {
+ for (var i = 0, l=myCanvases.length; i < l; i++) {
+ this.freeCanvas(myCanvases[i]);
+ }
+ myCanvases = [];
+ };
+
+ this.freeCanvas = function(idx) {
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ // excanvas can't be reused, but properly unset
+ window.G_vmlCanvasManager.uninitElement($.jqplot.CanvasManager.canvases[idx]);
+ $.jqplot.CanvasManager.canvases[idx] = null;
+ }
+ else {
+ var canvas = $.jqplot.CanvasManager.canvases[idx];
+ canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
+ $(canvas).unbind().removeAttr('class').removeAttr('style');
+ // Style attributes seemed to be still hanging around. wierd. Some ticks
+ // still retained a left: 0px attribute after reusing a canvas.
+ $(canvas).css({left: '', top: '', position: ''});
+ // setting size to 0 may save memory of unused canvases?
+ canvas.width = 0;
+ canvas.height = 0;
+ $.jqplot.CanvasManager.free[idx] = true;
+ }
+ };
+
+ };
+
+
+ // Convienence function that won't hang IE or FF without FireBug.
+ $.jqplot.log = function() {
+ if (window.console) {
+ window.console.log.apply(window.console, arguments);
+ }
+ };
+
+ $.jqplot.config = {
+ addDomReference: false,
+ enablePlugins:false,
+ defaultHeight:300,
+ defaultWidth:400,
+ UTCAdjust:false,
+ timezoneOffset: new Date(new Date().getTimezoneOffset() * 60000),
+ errorMessage: '',
+ errorBackground: '',
+ errorBorder: '',
+ errorFontFamily: '',
+ errorFontSize: '',
+ errorFontStyle: '',
+ errorFontWeight: '',
+ catchErrors: false,
+ defaultTickFormatString: "%.1f",
+ defaultColors: [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"],
+ defaultNegativeColors: [ "#498991", "#C08840", "#9F9274", "#546D61", "#646C4A", "#6F6621", "#6E3F5F", "#4F64B0", "#A89050", "#C45923", "#187399", "#945381", "#959E5C", "#C7AF7B", "#478396", "#907294"],
+ dashLength: 4,
+ gapLength: 4,
+ dotGapLength: 2.5,
+ srcLocation: 'jqplot/src/',
+ pluginLocation: 'jqplot/src/plugins/'
+ };
+
+
+ $.jqplot.arrayMax = function( array ){
+ return Math.max.apply( Math, array );
+ };
+
+ $.jqplot.arrayMin = function( array ){
+ return Math.min.apply( Math, array );
+ };
+
+ $.jqplot.enablePlugins = $.jqplot.config.enablePlugins;
+
+ // canvas related tests taken from modernizer:
+ // Copyright (c) 2009 - 2010 Faruk Ates.
+ // http://www.modernizr.com
+
+ $.jqplot.support_canvas = function() {
+ if (typeof $.jqplot.support_canvas.result == 'undefined') {
+ $.jqplot.support_canvas.result = !!document.createElement('canvas').getContext;
+ }
+ return $.jqplot.support_canvas.result;
+ };
+
+ $.jqplot.support_canvas_text = function() {
+ if (typeof $.jqplot.support_canvas_text.result == 'undefined') {
+ if (window.G_vmlCanvasManager !== undefined && window.G_vmlCanvasManager._version > 887) {
+ $.jqplot.support_canvas_text.result = true;
+ }
+ else {
+ $.jqplot.support_canvas_text.result = !!(document.createElement('canvas').getContext && typeof document.createElement('canvas').getContext('2d').fillText == 'function');
+ }
+
+ }
+ return $.jqplot.support_canvas_text.result;
+ };
+
+ $.jqplot.use_excanvas = ($.browser.msie && !$.jqplot.support_canvas()) ? true : false;
+
+ /**
+ *
+ * Hooks: jqPlot Pugin Hooks
+ *
+ * $.jqplot.preInitHooks - called before initialization.
+ * $.jqplot.postInitHooks - called after initialization.
+ * $.jqplot.preParseOptionsHooks - called before user options are parsed.
+ * $.jqplot.postParseOptionsHooks - called after user options are parsed.
+ * $.jqplot.preDrawHooks - called before plot draw.
+ * $.jqplot.postDrawHooks - called after plot draw.
+ * $.jqplot.preDrawSeriesHooks - called before each series is drawn.
+ * $.jqplot.postDrawSeriesHooks - called after each series is drawn.
+ * $.jqplot.preDrawLegendHooks - called before the legend is drawn.
+ * $.jqplot.addLegendRowHooks - called at the end of legend draw, so plugins
+ * can add rows to the legend table.
+ * $.jqplot.preSeriesInitHooks - called before series is initialized.
+ * $.jqplot.postSeriesInitHooks - called after series is initialized.
+ * $.jqplot.preParseSeriesOptionsHooks - called before series related options
+ * are parsed.
+ * $.jqplot.postParseSeriesOptionsHooks - called after series related options
+ * are parsed.
+ * $.jqplot.eventListenerHooks - called at the end of plot drawing, binds
+ * listeners to the event canvas which lays on top of the grid area.
+ * $.jqplot.preDrawSeriesShadowHooks - called before series shadows are drawn.
+ * $.jqplot.postDrawSeriesShadowHooks - called after series shadows are drawn.
+ *
+ */
+
+ $.jqplot.preInitHooks = [];
+ $.jqplot.postInitHooks = [];
+ $.jqplot.preParseOptionsHooks = [];
+ $.jqplot.postParseOptionsHooks = [];
+ $.jqplot.preDrawHooks = [];
+ $.jqplot.postDrawHooks = [];
+ $.jqplot.preDrawSeriesHooks = [];
+ $.jqplot.postDrawSeriesHooks = [];
+ $.jqplot.preDrawLegendHooks = [];
+ $.jqplot.addLegendRowHooks = [];
+ $.jqplot.preSeriesInitHooks = [];
+ $.jqplot.postSeriesInitHooks = [];
+ $.jqplot.preParseSeriesOptionsHooks = [];
+ $.jqplot.postParseSeriesOptionsHooks = [];
+ $.jqplot.eventListenerHooks = [];
+ $.jqplot.preDrawSeriesShadowHooks = [];
+ $.jqplot.postDrawSeriesShadowHooks = [];
+
+ // A superclass holding some common properties and methods.
+ $.jqplot.ElemContainer = function() {
+ this._elem;
+ this._plotWidth;
+ this._plotHeight;
+ this._plotDimensions = {height:null, width:null};
+ };
+
+ $.jqplot.ElemContainer.prototype.createElement = function(el, offsets, clss, cssopts, attrib) {
+ this._offsets = offsets;
+ var klass = clss || 'jqplot';
+ var elem = document.createElement(el);
+ this._elem = $(elem);
+ this._elem.addClass(klass);
+ this._elem.css(cssopts);
+ this._elem.attr(attrib);
+ // avoid memory leak;
+ elem = null;
+ return this._elem;
+ };
+
+ $.jqplot.ElemContainer.prototype.getWidth = function() {
+ if (this._elem) {
+ return this._elem.outerWidth(true);
+ }
+ else {
+ return null;
+ }
+ };
+
+ $.jqplot.ElemContainer.prototype.getHeight = function() {
+ if (this._elem) {
+ return this._elem.outerHeight(true);
+ }
+ else {
+ return null;
+ }
+ };
+
+ $.jqplot.ElemContainer.prototype.getPosition = function() {
+ if (this._elem) {
+ return this._elem.position();
+ }
+ else {
+ return {top:null, left:null, bottom:null, right:null};
+ }
+ };
+
+ $.jqplot.ElemContainer.prototype.getTop = function() {
+ return this.getPosition().top;
+ };
+
+ $.jqplot.ElemContainer.prototype.getLeft = function() {
+ return this.getPosition().left;
+ };
+
+ $.jqplot.ElemContainer.prototype.getBottom = function() {
+ return this._elem.css('bottom');
+ };
+
+ $.jqplot.ElemContainer.prototype.getRight = function() {
+ return this._elem.css('right');
+ };
+
+
+ /**
+ * Class: Axis
+ * An individual axis object. Cannot be instantiated directly, but created
+ * by the Plot oject. Axis properties can be set or overriden by the
+ * options passed in from the user.
+ *
+ */
+ function Axis(name) {
+ $.jqplot.ElemContainer.call(this);
+ // Group: Properties
+ //
+ // Axes options are specified within an axes object at the top level of the
+ // plot options like so:
+ // > {
+ // > axes: {
+ // > xaxis: {min: 5},
+ // > yaxis: {min: 2, max: 8, numberTicks:4},
+ // > x2axis: {pad: 1.5},
+ // > y2axis: {ticks:[22, 44, 66, 88]}
+ // > }
+ // > }
+ // There are 2 x axes, 'xaxis' and 'x2axis', and
+ // 9 yaxes, 'yaxis', 'y2axis'. 'y3axis', ... Any or all of which may be specified.
+ this.name = name;
+ this._series = [];
+ // prop: show
+ // Wether to display the axis on the graph.
+ this.show = false;
+ // prop: tickRenderer
+ // A class of a rendering engine for creating the ticks labels displayed on the plot,
+ // See <$.jqplot.AxisTickRenderer>.
+ this.tickRenderer = $.jqplot.AxisTickRenderer;
+ // prop: tickOptions
+ // Options that will be passed to the tickRenderer, see <$.jqplot.AxisTickRenderer> options.
+ this.tickOptions = {};
+ // prop: labelRenderer
+ // A class of a rendering engine for creating an axis label.
+ this.labelRenderer = $.jqplot.AxisLabelRenderer;
+ // prop: labelOptions
+ // Options passed to the label renderer.
+ this.labelOptions = {};
+ // prop: label
+ // Label for the axis
+ this.label = null;
+ // prop: showLabel
+ // true to show the axis label.
+ this.showLabel = true;
+ // prop: min
+ // minimum value of the axis (in data units, not pixels).
+ this.min = null;
+ // prop: max
+ // maximum value of the axis (in data units, not pixels).
+ this.max = null;
+ // prop: autoscale
+ // DEPRECATED
+ // the default scaling algorithm produces superior results.
+ this.autoscale = false;
+ // prop: pad
+ // Padding to extend the range above and below the data bounds.
+ // The data range is multiplied by this factor to determine minimum and maximum axis bounds.
+ // A value of 0 will be interpreted to mean no padding, and pad will be set to 1.0.
+ this.pad = 1.2;
+ // prop: padMax
+ // Padding to extend the range above data bounds.
+ // The top of the data range is multiplied by this factor to determine maximum axis bounds.
+ // A value of 0 will be interpreted to mean no padding, and padMax will be set to 1.0.
+ this.padMax = null;
+ // prop: padMin
+ // Padding to extend the range below data bounds.
+ // The bottom of the data range is multiplied by this factor to determine minimum axis bounds.
+ // A value of 0 will be interpreted to mean no padding, and padMin will be set to 1.0.
+ this.padMin = null;
+ // prop: ticks
+ // 1D [val, val, ...] or 2D [[val, label], [val, label], ...] array of ticks for the axis.
+ // If no label is specified, the value is formatted into an appropriate label.
+ this.ticks = [];
+ // prop: numberTicks
+ // Desired number of ticks. Default is to compute automatically.
+ this.numberTicks;
+ // prop: tickInterval
+ // number of units between ticks. Mutually exclusive with numberTicks.
+ this.tickInterval;
+ // prop: renderer
+ // A class of a rendering engine that handles tick generation,
+ // scaling input data to pixel grid units and drawing the axis element.
+ this.renderer = $.jqplot.LinearAxisRenderer;
+ // prop: rendererOptions
+ // renderer specific options. See <$.jqplot.LinearAxisRenderer> for options.
+ this.rendererOptions = {};
+ // prop: showTicks
+ // Wether to show the ticks (both marks and labels) or not.
+ // Will not override showMark and showLabel options if specified on the ticks themselves.
+ this.showTicks = true;
+ // prop: showTickMarks
+ // Wether to show the tick marks (line crossing grid) or not.
+ // Overridden by showTicks and showMark option of tick itself.
+ this.showTickMarks = true;
+ // prop: showMinorTicks
+ // Wether or not to show minor ticks. This is renderer dependent.
+ this.showMinorTicks = true;
+ // prop: drawMajorGridlines
+ // True to draw gridlines for major axis ticks.
+ this.drawMajorGridlines = true;
+ // prop: drawMinorGridlines
+ // True to draw gridlines for minor ticks.
+ this.drawMinorGridlines = false;
+ // prop: drawMajorTickMarks
+ // True to draw tick marks for major axis ticks.
+ this.drawMajorTickMarks = true;
+ // prop: drawMinorTickMarks
+ // True to draw tick marks for minor ticks. This is renderer dependent.
+ this.drawMinorTickMarks = true;
+ // prop: useSeriesColor
+ // Use the color of the first series associated with this axis for the
+ // tick marks and line bordering this axis.
+ this.useSeriesColor = false;
+ // prop: borderWidth
+ // width of line stroked at the border of the axis. Defaults
+ // to the width of the grid boarder.
+ this.borderWidth = null;
+ // prop: borderColor
+ // color of the border adjacent to the axis. Defaults to grid border color.
+ this.borderColor = null;
+ // prop: scaleToHiddenSeries
+ // True to include hidden series when computing axes bounds and scaling.
+ this.scaleToHiddenSeries = false;
+ // minimum and maximum values on the axis.
+ this._dataBounds = {min:null, max:null};
+ // statistics (min, max, mean) as well as actual data intervals for each series attached to axis.
+ // holds collection of {intervals:[], min:, max:, mean: } objects for each series on axis.
+ this._intervalStats = [];
+ // pixel position from the top left of the min value and max value on the axis.
+ this._offsets = {min:null, max:null};
+ this._ticks=[];
+ this._label = null;
+ // prop: syncTicks
+ // true to try and synchronize tick spacing across multiple axes so that ticks and
+ // grid lines line up. This has an impact on autoscaling algorithm, however.
+ // In general, autoscaling an individual axis will work better if it does not
+ // have to sync ticks.
+ this.syncTicks = null;
+ // prop: tickSpacing
+ // Approximate pixel spacing between ticks on graph. Used during autoscaling.
+ // This number will be an upper bound, actual spacing will be less.
+ this.tickSpacing = 75;
+ // Properties to hold the original values for min, max, ticks, tickInterval and numberTicks
+ // so they can be restored if altered by plugins.
+ this._min = null;
+ this._max = null;
+ this._tickInterval = null;
+ this._numberTicks = null;
+ this.__ticks = null;
+ // hold original user options.
+ this._options = {};
+ }
+
+ Axis.prototype = new $.jqplot.ElemContainer();
+ Axis.prototype.constructor = Axis;
+
+ Axis.prototype.init = function() {
+ if ($.isFunction(this.renderer)) {
+ this.renderer = new this.renderer();
+ }
+ // set the axis name
+ this.tickOptions.axis = this.name;
+ // if showMark or showLabel tick options not specified, use value of axis option.
+ // showTicks overrides showTickMarks.
+ if (this.tickOptions.showMark == null) {
+ this.tickOptions.showMark = this.showTicks;
+ }
+ if (this.tickOptions.showMark == null) {
+ this.tickOptions.showMark = this.showTickMarks;
+ }
+ if (this.tickOptions.showLabel == null) {
+ this.tickOptions.showLabel = this.showTicks;
+ }
+
+ if (this.label == null || this.label == '') {
+ this.showLabel = false;
+ }
+ else {
+ this.labelOptions.label = this.label;
+ }
+ if (this.showLabel == false) {
+ this.labelOptions.show = false;
+ }
+ // set the default padMax, padMin if not specified
+ // special check, if no padding desired, padding
+ // should be set to 1.0
+ if (this.pad == 0) {
+ this.pad = 1.0;
+ }
+ if (this.padMax == 0) {
+ this.padMax = 1.0;
+ }
+ if (this.padMin == 0) {
+ this.padMin = 1.0;
+ }
+ if (this.padMax == null) {
+ this.padMax = (this.pad-1)/2 + 1;
+ }
+ if (this.padMin == null) {
+ this.padMin = (this.pad-1)/2 + 1;
+ }
+ // now that padMin and padMax are correctly set, reset pad in case user has supplied
+ // padMin and/or padMax
+ this.pad = this.padMax + this.padMin - 1;
+ if (this.min != null || this.max != null) {
+ this.autoscale = false;
+ }
+ // if not set, sync ticks for y axes but not x by default.
+ if (this.syncTicks == null && this.name.indexOf('y') > -1) {
+ this.syncTicks = true;
+ }
+ else if (this.syncTicks == null){
+ this.syncTicks = false;
+ }
+ this.renderer.init.call(this, this.rendererOptions);
+
+ };
+
+ Axis.prototype.draw = function(ctx, plot) {
+ // Memory Leaks patch
+ if (this.__ticks) {
+ this.__ticks = null;
+ }
+
+ return this.renderer.draw.call(this, ctx, plot);
+
+ };
+
+ Axis.prototype.set = function() {
+ this.renderer.set.call(this);
+ };
+
+ Axis.prototype.pack = function(pos, offsets) {
+ if (this.show) {
+ this.renderer.pack.call(this, pos, offsets);
+ }
+ // these properties should all be available now.
+ if (this._min == null) {
+ this._min = this.min;
+ this._max = this.max;
+ this._tickInterval = this.tickInterval;
+ this._numberTicks = this.numberTicks;
+ this.__ticks = this._ticks;
+ }
+ };
+
+ // reset the axis back to original values if it has been scaled, zoomed, etc.
+ Axis.prototype.reset = function() {
+ this.renderer.reset.call(this);
+ };
+
+ Axis.prototype.resetScale = function(opts) {
+ $.extend(true, this, {min: null, max: null, numberTicks: null, tickInterval: null, _ticks: [], ticks: []}, opts);
+ this.resetDataBounds();
+ };
+
+ Axis.prototype.resetDataBounds = function() {
+ // Go through all the series attached to this axis and find
+ // the min/max bounds for this axis.
+ var db = this._dataBounds;
+ db.min = null;
+ db.max = null;
+ var l, s, d;
+ // check for when to force min 0 on bar series plots.
+ var doforce = (this.show) ? true : false;
+ for (var i=0; i<this._series.length; i++) {
+ s = this._series[i];
+ if (s.show || this.scaleToHiddenSeries) {
+ d = s._plotData;
+ if (s._type === 'line' && s.renderer.bands.show && this.name.charAt(0) !== 'x') {
+ d = [[0, s.renderer.bands._min], [1, s.renderer.bands._max]];
+ }
+
+ var minyidx = 1, maxyidx = 1;
+
+ if (s._type != null && s._type == 'ohlc') {
+ minyidx = 3;
+ maxyidx = 2;
+ }
+
+ for (var j=0, l=d.length; j<l; j++) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ if ((d[j][0] != null && d[j][0] < db.min) || db.min == null) {
+ db.min = d[j][0];
+ }
+ if ((d[j][0] != null && d[j][0] > db.max) || db.max == null) {
+ db.max = d[j][0];
+ }
+ }
+ else {
+ if ((d[j][minyidx] != null && d[j][minyidx] < db.min) || db.min == null) {
+ db.min = d[j][minyidx];
+ }
+ if ((d[j][maxyidx] != null && d[j][maxyidx] > db.max) || db.max == null) {
+ db.max = d[j][maxyidx];
+ }
+ }
+ }
+
+ // Hack to not pad out bottom of bar plots unless user has specified a padding.
+ // every series will have a chance to set doforce to false. once it is set to
+ // false, it cannot be reset to true.
+ // If any series attached to axis is not a bar, wont force 0.
+ if (doforce && s.renderer.constructor !== $.jqplot.BarRenderer) {
+ doforce = false;
+ }
+
+ else if (doforce && this._options.hasOwnProperty('forceTickAt0') && this._options.forceTickAt0 == false) {
+ doforce = false;
+ }
+
+ else if (doforce && s.renderer.constructor === $.jqplot.BarRenderer) {
+ if (s.barDirection == 'vertical' && this.name != 'xaxis' && this.name != 'x2axis') {
+ if (this._options.pad != null || this._options.padMin != null) {
+ doforce = false;
+ }
+ }
+
+ else if (s.barDirection == 'horizontal' && (this.name == 'xaxis' || this.name == 'x2axis')) {
+ if (this._options.pad != null || this._options.padMin != null) {
+ doforce = false;
+ }
+ }
+
+ }
+ }
+ }
+
+ if (doforce && this.renderer.constructor === $.jqplot.LinearAxisRenderer && db.min >= 0) {
+ this.padMin = 1.0;
+ this.forceTickAt0 = true;
+ }
+ };
+
+ /**
+ * Class: Legend
+ * Legend object. Cannot be instantiated directly, but created
+ * by the Plot oject. Legend properties can be set or overriden by the
+ * options passed in from the user.
+ */
+ function Legend(options) {
+ $.jqplot.ElemContainer.call(this);
+ // Group: Properties
+
+ // prop: show
+ // Wether to display the legend on the graph.
+ this.show = false;
+ // prop: location
+ // Placement of the legend. one of the compass directions: nw, n, ne, e, se, s, sw, w
+ this.location = 'ne';
+ // prop: labels
+ // Array of labels to use. By default the renderer will look for labels on the series.
+ // Labels specified in this array will override labels specified on the series.
+ this.labels = [];
+ // prop: showLabels
+ // true to show the label text on the legend.
+ this.showLabels = true;
+ // prop: showSwatch
+ // true to show the color swatches on the legend.
+ this.showSwatches = true;
+ // prop: placement
+ // "insideGrid" places legend inside the grid area of the plot.
+ // "outsideGrid" places the legend outside the grid but inside the plot container,
+ // shrinking the grid to accomodate the legend.
+ // "inside" synonym for "insideGrid",
+ // "outside" places the legend ouside the grid area, but does not shrink the grid which
+ // can cause the legend to overflow the plot container.
+ this.placement = "insideGrid";
+ // prop: xoffset
+ // DEPRECATED. Set the margins on the legend using the marginTop, marginLeft, etc.
+ // properties or via CSS margin styling of the .jqplot-table-legend class.
+ this.xoffset = 0;
+ // prop: yoffset
+ // DEPRECATED. Set the margins on the legend using the marginTop, marginLeft, etc.
+ // properties or via CSS margin styling of the .jqplot-table-legend class.
+ this.yoffset = 0;
+ // prop: border
+ // css spec for the border around the legend box.
+ this.border;
+ // prop: background
+ // css spec for the background of the legend box.
+ this.background;
+ // prop: textColor
+ // css color spec for the legend text.
+ this.textColor;
+ // prop: fontFamily
+ // css font-family spec for the legend text.
+ this.fontFamily;
+ // prop: fontSize
+ // css font-size spec for the legend text.
+ this.fontSize ;
+ // prop: rowSpacing
+ // css padding-top spec for the rows in the legend.
+ this.rowSpacing = '0.5em';
+ // renderer
+ // A class that will create a DOM object for the legend,
+ // see <$.jqplot.TableLegendRenderer>.
+ this.renderer = $.jqplot.TableLegendRenderer;
+ // prop: rendererOptions
+ // renderer specific options passed to the renderer.
+ this.rendererOptions = {};
+ // prop: predraw
+ // Wether to draw the legend before the series or not.
+ // Used with series specific legend renderers for pie, donut, mekko charts, etc.
+ this.preDraw = false;
+ // prop: marginTop
+ // CSS margin for the legend DOM element. This will set an element
+ // CSS style for the margin which will override any style sheet setting.
+ // The default will be taken from the stylesheet.
+ this.marginTop = null;
+ // prop: marginRight
+ // CSS margin for the legend DOM element. This will set an element
+ // CSS style for the margin which will override any style sheet setting.
+ // The default will be taken from the stylesheet.
+ this.marginRight = null;
+ // prop: marginBottom
+ // CSS margin for the legend DOM element. This will set an element
+ // CSS style for the margin which will override any style sheet setting.
+ // The default will be taken from the stylesheet.
+ this.marginBottom = null;
+ // prop: marginLeft
+ // CSS margin for the legend DOM element. This will set an element
+ // CSS style for the margin which will override any style sheet setting.
+ // The default will be taken from the stylesheet.
+ this.marginLeft = null;
+ // prop: escapeHtml
+ // True to escape special characters with their html entity equivalents
+ // in legend text. "<" becomes &lt; and so on, so html tags are not rendered.
+ this.escapeHtml = false;
+ this._series = [];
+
+ $.extend(true, this, options);
+ }
+
+ Legend.prototype = new $.jqplot.ElemContainer();
+ Legend.prototype.constructor = Legend;
+
+ Legend.prototype.setOptions = function(options) {
+ $.extend(true, this, options);
+
+ // Try to emulate deprecated behaviour
+ // if user has specified xoffset or yoffset, copy these to
+ // the margin properties.
+
+ if (this.placement == 'inside') {
+ this.placement = 'insideGrid';
+ }
+
+ if (this.xoffset >0) {
+ if (this.placement == 'insideGrid') {
+ switch (this.location) {
+ case 'nw':
+ case 'w':
+ case 'sw':
+ if (this.marginLeft == null) {
+ this.marginLeft = this.xoffset + 'px';
+ }
+ this.marginRight = '0px';
+ break;
+ case 'ne':
+ case 'e':
+ case 'se':
+ default:
+ if (this.marginRight == null) {
+ this.marginRight = this.xoffset + 'px';
+ }
+ this.marginLeft = '0px';
+ break;
+ }
+ }
+ else if (this.placement == 'outside') {
+ switch (this.location) {
+ case 'nw':
+ case 'w':
+ case 'sw':
+ if (this.marginRight == null) {
+ this.marginRight = this.xoffset + 'px';
+ }
+ this.marginLeft = '0px';
+ break;
+ case 'ne':
+ case 'e':
+ case 'se':
+ default:
+ if (this.marginLeft == null) {
+ this.marginLeft = this.xoffset + 'px';
+ }
+ this.marginRight = '0px';
+ break;
+ }
+ }
+ this.xoffset = 0;
+ }
+
+ if (this.yoffset >0) {
+ if (this.placement == 'outside') {
+ switch (this.location) {
+ case 'sw':
+ case 's':
+ case 'se':
+ if (this.marginTop == null) {
+ this.marginTop = this.yoffset + 'px';
+ }
+ this.marginBottom = '0px';
+ break;
+ case 'ne':
+ case 'n':
+ case 'nw':
+ default:
+ if (this.marginBottom == null) {
+ this.marginBottom = this.yoffset + 'px';
+ }
+ this.marginTop = '0px';
+ break;
+ }
+ }
+ else if (this.placement == 'insideGrid') {
+ switch (this.location) {
+ case 'sw':
+ case 's':
+ case 'se':
+ if (this.marginBottom == null) {
+ this.marginBottom = this.yoffset + 'px';
+ }
+ this.marginTop = '0px';
+ break;
+ case 'ne':
+ case 'n':
+ case 'nw':
+ default:
+ if (this.marginTop == null) {
+ this.marginTop = this.yoffset + 'px';
+ }
+ this.marginBottom = '0px';
+ break;
+ }
+ }
+ this.yoffset = 0;
+ }
+
+ // TO-DO:
+ // Handle case where offsets are < 0.
+ //
+ };
+
+ Legend.prototype.init = function() {
+ if ($.isFunction(this.renderer)) {
+ this.renderer = new this.renderer();
+ }
+ this.renderer.init.call(this, this.rendererOptions);
+ };
+
+ Legend.prototype.draw = function(offsets, plot) {
+ for (var i=0; i<$.jqplot.preDrawLegendHooks.length; i++){
+ $.jqplot.preDrawLegendHooks[i].call(this, offsets);
+ }
+ return this.renderer.draw.call(this, offsets, plot);
+ };
+
+ Legend.prototype.pack = function(offsets) {
+ this.renderer.pack.call(this, offsets);
+ };
+
+ /**
+ * Class: Title
+ * Plot Title object. Cannot be instantiated directly, but created
+ * by the Plot oject. Title properties can be set or overriden by the
+ * options passed in from the user.
+ *
+ * Parameters:
+ * text - text of the title.
+ */
+ function Title(text) {
+ $.jqplot.ElemContainer.call(this);
+ // Group: Properties
+
+ // prop: text
+ // text of the title;
+ this.text = text;
+ // prop: show
+ // wether or not to show the title
+ this.show = true;
+ // prop: fontFamily
+ // css font-family spec for the text.
+ this.fontFamily;
+ // prop: fontSize
+ // css font-size spec for the text.
+ this.fontSize ;
+ // prop: textAlign
+ // css text-align spec for the text.
+ this.textAlign;
+ // prop: textColor
+ // css color spec for the text.
+ this.textColor;
+ // prop: renderer
+ // A class for creating a DOM element for the title,
+ // see <$.jqplot.DivTitleRenderer>.
+ this.renderer = $.jqplot.DivTitleRenderer;
+ // prop: rendererOptions
+ // renderer specific options passed to the renderer.
+ this.rendererOptions = {};
+ // prop: escapeHtml
+ // True to escape special characters with their html entity equivalents
+ // in title text. "<" becomes &lt; and so on, so html tags are not rendered.
+ this.escapeHtml = false;
+ }
+
+ Title.prototype = new $.jqplot.ElemContainer();
+ Title.prototype.constructor = Title;
+
+ Title.prototype.init = function() {
+ if ($.isFunction(this.renderer)) {
+ this.renderer = new this.renderer();
+ }
+ this.renderer.init.call(this, this.rendererOptions);
+ };
+
+ Title.prototype.draw = function(width) {
+ return this.renderer.draw.call(this, width);
+ };
+
+ Title.prototype.pack = function() {
+ this.renderer.pack.call(this);
+ };
+
+
+ /**
+ * Class: Series
+ * An individual data series object. Cannot be instantiated directly, but created
+ * by the Plot oject. Series properties can be set or overriden by the
+ * options passed in from the user.
+ */
+ function Series(options) {
+ options = options || {};
+ $.jqplot.ElemContainer.call(this);
+ // Group: Properties
+ // Properties will be assigned from a series array at the top level of the
+ // options. If you had two series and wanted to change the color and line
+ // width of the first and set the second to use the secondary y axis with
+ // no shadow and supply custom labels for each:
+ // > {
+ // > series:[
+ // > {color: '#ff4466', lineWidth: 5, label:'good line'},
+ // > {yaxis: 'y2axis', shadow: false, label:'bad line'}
+ // > ]
+ // > }
+
+ // prop: show
+ // wether or not to draw the series.
+ this.show = true;
+ // prop: xaxis
+ // which x axis to use with this series, either 'xaxis' or 'x2axis'.
+ this.xaxis = 'xaxis';
+ this._xaxis;
+ // prop: yaxis
+ // which y axis to use with this series, either 'yaxis' or 'y2axis'.
+ this.yaxis = 'yaxis';
+ this._yaxis;
+ this.gridBorderWidth = 2.0;
+ // prop: renderer
+ // A class of a renderer which will draw the series,
+ // see <$.jqplot.LineRenderer>.
+ this.renderer = $.jqplot.LineRenderer;
+ // prop: rendererOptions
+ // Options to pass on to the renderer.
+ this.rendererOptions = {};
+ this.data = [];
+ this.gridData = [];
+ // prop: label
+ // Line label to use in the legend.
+ this.label = '';
+ // prop: showLabel
+ // true to show label for this series in the legend.
+ this.showLabel = true;
+ // prop: color
+ // css color spec for the series
+ this.color;
+ // prop: negativeColor
+ // css color spec used for filled (area) plots that are filled to zero and
+ // the "useNegativeColors" option is true.
+ this.negativeColor;
+ // prop: lineWidth
+ // width of the line in pixels. May have different meanings depending on renderer.
+ this.lineWidth = 2.5;
+ // prop: lineJoin
+ // Canvas lineJoin style between segments of series.
+ this.lineJoin = 'round';
+ // prop: lineCap
+ // Canvas lineCap style at ends of line.
+ this.lineCap = 'round';
+ // prop: linePattern
+ // line pattern 'dashed', 'dotted', 'solid', some combination
+ // of '-' and '.' characters such as '.-.' or a numerical array like
+ // [draw, skip, draw, skip, ...] such as [1, 10] to draw a dotted line,
+ // [1, 10, 20, 10] to draw a dot-dash line, and so on.
+ this.linePattern = 'solid';
+ this.shadow = true;
+ // prop: shadowAngle
+ // Shadow angle in degrees
+ this.shadowAngle = 45;
+ // prop: shadowOffset
+ // Shadow offset from line in pixels
+ this.shadowOffset = 1.25;
+ // prop: shadowDepth
+ // Number of times shadow is stroked, each stroke offset shadowOffset from the last.
+ this.shadowDepth = 3;
+ // prop: shadowAlpha
+ // Alpha channel transparency of shadow. 0 = transparent.
+ this.shadowAlpha = '0.1';
+ // prop: breakOnNull
+ // Wether line segments should be be broken at null value.
+ // False will join point on either side of line.
+ this.breakOnNull = false;
+ // prop: markerRenderer
+ // A class of a renderer which will draw marker (e.g. circle, square, ...) at the data points,
+ // see <$.jqplot.MarkerRenderer>.
+ this.markerRenderer = $.jqplot.MarkerRenderer;
+ // prop: markerOptions
+ // renderer specific options to pass to the markerRenderer,
+ // see <$.jqplot.MarkerRenderer>.
+ this.markerOptions = {};
+ // prop: showLine
+ // wether to actually draw the line or not. Series will still be renderered, even if no line is drawn.
+ this.showLine = true;
+ // prop: showMarker
+ // wether or not to show the markers at the data points.
+ this.showMarker = true;
+ // prop: index
+ // 0 based index of this series in the plot series array.
+ this.index;
+ // prop: fill
+ // true or false, wether to fill under lines or in bars.
+ // May not be implemented in all renderers.
+ this.fill = false;
+ // prop: fillColor
+ // CSS color spec to use for fill under line. Defaults to line color.
+ this.fillColor;
+ // prop: fillAlpha
+ // Alpha transparency to apply to the fill under the line.
+ // Use this to adjust alpha separate from fill color.
+ this.fillAlpha;
+ // prop: fillAndStroke
+ // If true will stroke the line (with color this.color) as well as fill under it.
+ // Applies only when fill is true.
+ this.fillAndStroke = false;
+ // prop: disableStack
+ // true to not stack this series with other series in the plot.
+ // To render properly, non-stacked series must come after any stacked series
+ // in the plot's data series array. So, the plot's data series array would look like:
+ // > [stackedSeries1, stackedSeries2, ..., nonStackedSeries1, nonStackedSeries2, ...]
+ // disableStack will put a gap in the stacking order of series, and subsequent
+ // stacked series will not fill down through the non-stacked series and will
+ // most likely not stack properly on top of the non-stacked series.
+ this.disableStack = false;
+ // _stack is set by the Plot if the plot is a stacked chart.
+ // will stack lines or bars on top of one another to build a "mountain" style chart.
+ // May not be implemented in all renderers.
+ this._stack = false;
+ // prop: neighborThreshold
+ // how close or far (in pixels) the cursor must be from a point marker to detect the point.
+ this.neighborThreshold = 4;
+ // prop: fillToZero
+ // true will force bar and filled series to fill toward zero on the fill Axis.
+ this.fillToZero = false;
+ // prop: fillToValue
+ // fill a filled series to this value on the fill axis.
+ // Works in conjunction with fillToZero, so that must be true.
+ this.fillToValue = 0;
+ // prop: fillAxis
+ // Either 'x' or 'y'. Which axis to fill the line toward if fillToZero is true.
+ // 'y' means fill up/down to 0 on the y axis for this series.
+ this.fillAxis = 'y';
+ // prop: useNegativeColors
+ // true to color negative values differently in filled and bar charts.
+ this.useNegativeColors = true;
+ this._stackData = [];
+ // _plotData accounts for stacking. If plots not stacked, _plotData and data are same. If
+ // stacked, _plotData is accumulation of stacking data.
+ this._plotData = [];
+ // _plotValues hold the individual x and y values that will be plotted for this series.
+ this._plotValues = {x:[], y:[]};
+ // statistics about the intervals between data points. Used for auto scaling.
+ this._intervals = {x:{}, y:{}};
+ // data from the previous series, for stacked charts.
+ this._prevPlotData = [];
+ this._prevGridData = [];
+ this._stackAxis = 'y';
+ this._primaryAxis = '_xaxis';
+ // give each series a canvas to draw on. This should allow for redrawing speedups.
+ this.canvas = new $.jqplot.GenericCanvas();
+ this.shadowCanvas = new $.jqplot.GenericCanvas();
+ this.plugins = {};
+ // sum of y values in this series.
+ this._sumy = 0;
+ this._sumx = 0;
+ this._type = '';
+ }
+
+ Series.prototype = new $.jqplot.ElemContainer();
+ Series.prototype.constructor = Series;
+
+ Series.prototype.init = function(index, gridbw, plot) {
+ // weed out any null values in the data.
+ this.index = index;
+ this.gridBorderWidth = gridbw;
+ var d = this.data;
+ var temp = [], i, l;
+ for (i=0, l=d.length; i<l; i++) {
+ if (! this.breakOnNull) {
+ if (d[i] == null || d[i][0] == null || d[i][1] == null) {
+ continue;
+ }
+ else {
+ temp.push(d[i]);
+ }
+ }
+ else {
+ // TODO: figure out what to do with null values
+ // probably involve keeping nulls in data array
+ // and then updating renderers to break line
+ // when it hits null value.
+ // For now, just keep value.
+ temp.push(d[i]);
+ }
+ }
+ this.data = temp;
+
+ // parse the renderer options and apply default colors if not provided
+ // Set color even if not shown, so series don't change colors when other
+ // series on plot shown/hidden.
+ if (!this.color) {
+ this.color = plot.colorGenerator.get(this.index);
+ }
+ if (!this.negativeColor) {
+ this.negativeColor = plot.negativeColorGenerator.get(this.index);
+ }
+
+
+ if (!this.fillColor) {
+ this.fillColor = this.color;
+ }
+ if (this.fillAlpha) {
+ var comp = $.jqplot.normalize2rgb(this.fillColor);
+ var comp = $.jqplot.getColorComponents(comp);
+ this.fillColor = 'rgba('+comp[0]+','+comp[1]+','+comp[2]+','+this.fillAlpha+')';
+ }
+ if ($.isFunction(this.renderer)) {
+ this.renderer = new this.renderer();
+ }
+ this.renderer.init.call(this, this.rendererOptions, plot);
+ this.markerRenderer = new this.markerRenderer();
+ if (!this.markerOptions.color) {
+ this.markerOptions.color = this.color;
+ }
+ if (this.markerOptions.show == null) {
+ this.markerOptions.show = this.showMarker;
+ }
+ this.showMarker = this.markerOptions.show;
+ // the markerRenderer is called within it's own scaope, don't want to overwrite series options!!
+ this.markerRenderer.init(this.markerOptions);
+ };
+
+ // data - optional data point array to draw using this series renderer
+ // gridData - optional grid data point array to draw using this series renderer
+ // stackData - array of cumulative data for stacked plots.
+ Series.prototype.draw = function(sctx, opts, plot) {
+ var options = (opts == undefined) ? {} : opts;
+ sctx = (sctx == undefined) ? this.canvas._ctx : sctx;
+
+ var j, data, gridData;
+
+ // hooks get called even if series not shown
+ // we don't clear canvas here, it would wipe out all other series as well.
+ for (j=0; j<$.jqplot.preDrawSeriesHooks.length; j++) {
+ $.jqplot.preDrawSeriesHooks[j].call(this, sctx, options);
+ }
+ if (this.show) {
+ this.renderer.setGridData.call(this, plot);
+ if (!options.preventJqPlotSeriesDrawTrigger) {
+ $(sctx.canvas).trigger('jqplotSeriesDraw', [this.data, this.gridData]);
+ }
+ data = [];
+ if (options.data) {
+ data = options.data;
+ }
+ else if (!this._stack) {
+ data = this.data;
+ }
+ else {
+ data = this._plotData;
+ }
+ gridData = options.gridData || this.renderer.makeGridData.call(this, data, plot);
+
+ if (this._type === 'line' && this.renderer.smooth && this.renderer._smoothedData.length) {
+ gridData = this.renderer._smoothedData;
+ }
+
+ this.renderer.draw.call(this, sctx, gridData, options, plot);
+ }
+
+ for (j=0; j<$.jqplot.postDrawSeriesHooks.length; j++) {
+ $.jqplot.postDrawSeriesHooks[j].call(this, sctx, options, plot);
+ }
+
+ sctx = opts = plot = j = data = gridData = null;
+ };
+
+ Series.prototype.drawShadow = function(sctx, opts, plot) {
+ var options = (opts == undefined) ? {} : opts;
+ sctx = (sctx == undefined) ? this.shadowCanvas._ctx : sctx;
+
+ var j, data, gridData;
+
+ // hooks get called even if series not shown
+ // we don't clear canvas here, it would wipe out all other series as well.
+ for (j=0; j<$.jqplot.preDrawSeriesShadowHooks.length; j++) {
+ $.jqplot.preDrawSeriesShadowHooks[j].call(this, sctx, options);
+ }
+ if (this.shadow) {
+ this.renderer.setGridData.call(this, plot);
+
+ data = [];
+ if (options.data) {
+ data = options.data;
+ }
+ else if (!this._stack) {
+ data = this.data;
+ }
+ else {
+ data = this._plotData;
+ }
+ gridData = options.gridData || this.renderer.makeGridData.call(this, data, plot);
+
+ this.renderer.drawShadow.call(this, sctx, gridData, options, plot);
+ }
+
+ for (j=0; j<$.jqplot.postDrawSeriesShadowHooks.length; j++) {
+ $.jqplot.postDrawSeriesShadowHooks[j].call(this, sctx, options);
+ }
+
+ sctx = opts = plot = j = data = gridData = null;
+
+ };
+
+ // toggles series display on plot, e.g. show/hide series
+ Series.prototype.toggleDisplay = function(ev, callback) {
+ var s, speed;
+ if (ev.data.series) {
+ s = ev.data.series;
+ }
+ else {
+ s = this;
+ }
+
+ if (ev.data.speed) {
+ speed = ev.data.speed;
+ }
+ if (speed) {
+ // this can be tricky because series may not have a canvas element if replotting.
+ if (s.canvas._elem.is(':hidden') || !s.show) {
+ s.show = true;
+
+ s.canvas._elem.removeClass('jqplot-series-hidden');
+ if (s.shadowCanvas._elem) {
+ s.shadowCanvas._elem.fadeIn(speed);
+ }
+ s.canvas._elem.fadeIn(speed, callback);
+ s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).fadeIn(speed);
+ }
+ else {
+ s.show = false;
+
+ s.canvas._elem.addClass('jqplot-series-hidden');
+ if (s.shadowCanvas._elem) {
+ s.shadowCanvas._elem.fadeOut(speed);
+ }
+ s.canvas._elem.fadeOut(speed, callback);
+ s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).fadeOut(speed);
+ }
+ }
+ else {
+ // this can be tricky because series may not have a canvas element if replotting.
+ if (s.canvas._elem.is(':hidden') || !s.show) {
+ s.show = true;
+
+ s.canvas._elem.removeClass('jqplot-series-hidden');
+ if (s.shadowCanvas._elem) {
+ s.shadowCanvas._elem.show();
+ }
+ s.canvas._elem.show(0, callback);
+ s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).show();
+ }
+ else {
+ s.show = false;
+
+ s.canvas._elem.addClass('jqplot-series-hidden');
+ if (s.shadowCanvas._elem) {
+ s.shadowCanvas._elem.hide();
+ }
+ s.canvas._elem.hide(0, callback);
+ s.canvas._elem.nextAll('.jqplot-point-label.jqplot-series-'+s.index).hide();
+ }
+ }
+ };
+
+
+
+ /**
+ * Class: Grid
+ *
+ * Object representing the grid on which the plot is drawn. The grid in this
+ * context is the area bounded by the axes, the area which will contain the series.
+ * Note, the series are drawn on their own canvas.
+ * The Grid object cannot be instantiated directly, but is created by the Plot oject.
+ * Grid properties can be set or overriden by the options passed in from the user.
+ */
+ function Grid() {
+ $.jqplot.ElemContainer.call(this);
+ // Group: Properties
+
+ // prop: drawGridlines
+ // wether to draw the gridlines on the plot.
+ this.drawGridlines = true;
+ // prop: gridLineColor
+ // color of the grid lines.
+ this.gridLineColor = '#cccccc';
+ // prop: gridLineWidth
+ // width of the grid lines.
+ this.gridLineWidth = 1.0;
+ // prop: background
+ // css spec for the background color.
+ this.background = '#fffdf6';
+ // prop: borderColor
+ // css spec for the color of the grid border.
+ this.borderColor = '#999999';
+ // prop: borderWidth
+ // width of the border in pixels.
+ this.borderWidth = 2.0;
+ // prop: drawBorder
+ // True to draw border around grid.
+ this.drawBorder = true;
+ // prop: shadow
+ // wether to show a shadow behind the grid.
+ this.shadow = true;
+ // prop: shadowAngle
+ // shadow angle in degrees
+ this.shadowAngle = 45;
+ // prop: shadowOffset
+ // Offset of each shadow stroke from the border in pixels
+ this.shadowOffset = 1.5;
+ // prop: shadowWidth
+ // width of the stoke for the shadow
+ this.shadowWidth = 3;
+ // prop: shadowDepth
+ // Number of times shadow is stroked, each stroke offset shadowOffset from the last.
+ this.shadowDepth = 3;
+ // prop: shadowColor
+ // an optional css color spec for the shadow in 'rgba(n, n, n, n)' form
+ this.shadowColor = null;
+ // prop: shadowAlpha
+ // Alpha channel transparency of shadow. 0 = transparent.
+ this.shadowAlpha = '0.07';
+ this._left;
+ this._top;
+ this._right;
+ this._bottom;
+ this._width;
+ this._height;
+ this._axes = [];
+ // prop: renderer
+ // Instance of a renderer which will actually render the grid,
+ // see <$.jqplot.CanvasGridRenderer>.
+ this.renderer = $.jqplot.CanvasGridRenderer;
+ // prop: rendererOptions
+ // Options to pass on to the renderer,
+ // see <$.jqplot.CanvasGridRenderer>.
+ this.rendererOptions = {};
+ this._offsets = {top:null, bottom:null, left:null, right:null};
+ }
+
+ Grid.prototype = new $.jqplot.ElemContainer();
+ Grid.prototype.constructor = Grid;
+
+ Grid.prototype.init = function() {
+ if ($.isFunction(this.renderer)) {
+ this.renderer = new this.renderer();
+ }
+ this.renderer.init.call(this, this.rendererOptions);
+ };
+
+ Grid.prototype.createElement = function(offsets,plot) {
+ this._offsets = offsets;
+ return this.renderer.createElement.call(this, plot);
+ };
+
+ Grid.prototype.draw = function() {
+ this.renderer.draw.call(this);
+ };
+
+ $.jqplot.GenericCanvas = function() {
+ $.jqplot.ElemContainer.call(this);
+ this._ctx;
+ };
+
+ $.jqplot.GenericCanvas.prototype = new $.jqplot.ElemContainer();
+ $.jqplot.GenericCanvas.prototype.constructor = $.jqplot.GenericCanvas;
+
+ $.jqplot.GenericCanvas.prototype.createElement = function(offsets, clss, plotDimensions, plot) {
+ this._offsets = offsets;
+ var klass = 'jqplot';
+ if (clss != undefined) {
+ klass = clss;
+ }
+ var elem;
+
+ elem = plot.canvasManager.getCanvas();
+
+ // if new plotDimensions supplied, use them.
+ if (plotDimensions != null) {
+ this._plotDimensions = plotDimensions;
+ }
+
+ elem.width = this._plotDimensions.width - this._offsets.left - this._offsets.right;
+ elem.height = this._plotDimensions.height - this._offsets.top - this._offsets.bottom;
+ this._elem = $(elem);
+ this._elem.css({ position: 'absolute', left: this._offsets.left, top: this._offsets.top });
+
+ this._elem.addClass(klass);
+
+ elem = plot.canvasManager.initCanvas(elem);
+
+ elem = null;
+ return this._elem;
+ };
+
+ $.jqplot.GenericCanvas.prototype.setContext = function() {
+ this._ctx = this._elem.get(0).getContext("2d");
+ return this._ctx;
+ };
+
+ // Memory Leaks patch
+ $.jqplot.GenericCanvas.prototype.resetCanvas = function() {
+ if (this._elem) {
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ window.G_vmlCanvasManager.uninitElement(this._elem.get(0));
+ }
+
+ //this._elem.remove();
+ this._elem.emptyForce();
+ }
+
+ this._ctx = null;
+ };
+
+ $.jqplot.HooksManager = function () {
+ this.hooks =[];
+ this.args = [];
+ };
+
+ $.jqplot.HooksManager.prototype.addOnce = function(fn, args) {
+ args = args || [];
+ var havehook = false;
+ for (var i=0, l=this.hooks.length; i<l; i++) {
+ if (this.hooks[i] == fn) {
+ havehook = true;
+ }
+ }
+ if (!havehook) {
+ this.hooks.push(fn);
+ this.args.push(args);
+ }
+ };
+
+ $.jqplot.HooksManager.prototype.add = function(fn, args) {
+ args = args || [];
+ this.hooks.push(fn);
+ this.args.push(args);
+ };
+
+ $.jqplot.EventListenerManager = function () {
+ this.hooks =[];
+ };
+
+ $.jqplot.EventListenerManager.prototype.addOnce = function(ev, fn) {
+ var havehook = false, h, i;
+ for (var i=0, l=this.hooks.length; i<l; i++) {
+ h = this.hooks[i];
+ if (h[0] == ev && h[1] == fn) {
+ havehook = true;
+ }
+ }
+ if (!havehook) {
+ this.hooks.push([ev, fn]);
+ }
+ };
+
+ $.jqplot.EventListenerManager.prototype.add = function(ev, fn) {
+ this.hooks.push([ev, fn]);
+ };
+
+
+ var _axisNames = ['yMidAxis', 'xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis'];
+
+ /**
+ * Class: jqPlot
+ * Plot object returned by call to $.jqplot. Handles parsing user options,
+ * creating sub objects (Axes, legend, title, series) and rendering the plot.
+ */
+ function jqPlot() {
+ // Group: Properties
+ // These properties are specified at the top of the options object
+ // like so:
+ // > {
+ // > axesDefaults:{min:0},
+ // > series:[{color:'#6633dd'}],
+ // > title: 'A Plot'
+ // > }
+ //
+
+ // prop: animate
+ // True to animate the series on initial plot draw (renderer dependent).
+ // Actual animation functionality must be supported in the renderer.
+ this.animate = false;
+ // prop: animateReplot
+ // True to animate series after a call to the replot() method.
+ // Use with caution! Replots can happen very frequently under
+ // certain circumstances (e.g. resizing, dragging points) and
+ // animation in these situations can cause problems.
+ this.animateReplot = false;
+ // prop: axes
+ // up to 4 axes are supported, each with it's own options,
+ // See <Axis> for axis specific options.
+ this.axes = {xaxis: new Axis('xaxis'), yaxis: new Axis('yaxis'), x2axis: new Axis('x2axis'), y2axis: new Axis('y2axis'), y3axis: new Axis('y3axis'), y4axis: new Axis('y4axis'), y5axis: new Axis('y5axis'), y6axis: new Axis('y6axis'), y7axis: new Axis('y7axis'), y8axis: new Axis('y8axis'), y9axis: new Axis('y9axis'), yMidAxis: new Axis('yMidAxis')};
+ this.baseCanvas = new $.jqplot.GenericCanvas();
+ // true to intercept right click events and fire a 'jqplotRightClick' event.
+ // this will also block the context menu.
+ this.captureRightClick = false;
+ // prop: data
+ // user's data. Data should *NOT* be specified in the options object,
+ // but be passed in as the second argument to the $.jqplot() function.
+ // The data property is described here soley for reference.
+ // The data should be in the form of an array of 2D or 1D arrays like
+ // > [ [[x1, y1], [x2, y2],...], [y1, y2, ...] ].
+ this.data = [];
+ // prop: dataRenderer
+ // A callable which can be used to preprocess data passed into the plot.
+ // Will be called with 2 arguments, the plot data and a reference to the plot.
+ this.dataRenderer;
+ // prop: dataRendererOptions
+ // Options that will be passed to the dataRenderer.
+ // Can be of any type.
+ this.dataRendererOptions;
+ this.defaults = {
+ // prop: axesDefaults
+ // default options that will be applied to all axes.
+ // see <Axis> for axes options.
+ axesDefaults: {},
+ axes: {xaxis:{}, yaxis:{}, x2axis:{}, y2axis:{}, y3axis:{}, y4axis:{}, y5axis:{}, y6axis:{}, y7axis:{}, y8axis:{}, y9axis:{}, yMidAxis:{}},
+ // prop: seriesDefaults
+ // default options that will be applied to all series.
+ // see <Series> for series options.
+ seriesDefaults: {},
+ series:[]
+ };
+ // prop: defaultAxisStart
+ // 1-D data series are internally converted into 2-D [x,y] data point arrays
+ // by jqPlot. This is the default starting value for the missing x or y value.
+ // The added data will be a monotonically increasing series (e.g. [1, 2, 3, ...])
+ // starting at this value.
+ this.defaultAxisStart = 1;
+ // this.doCustomEventBinding = true;
+ // prop: drawIfHidden
+ // True to execute the draw method even if the plot target is hidden.
+ // Generally, this should be false. Most plot elements will not be sized/
+ // positioned correclty if renderered into a hidden container. To render into
+ // a hidden container, call the replot method when the container is shown.
+ this.drawIfHidden = false;
+ this.eventCanvas = new $.jqplot.GenericCanvas();
+ // prop: fillBetween
+ // Fill between 2 line series in a plot.
+ // Options object:
+ // {
+ // series1: first index (0 based) of series in fill
+ // series2: second index (0 based) of series in fill
+ // color: color of fill [default fillColor of series1]
+ // baseSeries: fill will be drawn below this series (0 based index)
+ // fill: false to turn off fill [default true].
+ // }
+ this.fillBetween = {
+ series1: null,
+ series2: null,
+ color: null,
+ baseSeries: 0,
+ fill: true
+ };
+ // prop; fontFamily
+ // css spec for the font-family attribute. Default for the entire plot.
+ this.fontFamily;
+ // prop: fontSize
+ // css spec for the font-size attribute. Default for the entire plot.
+ this.fontSize;
+ // prop: grid
+ // See <Grid> for grid specific options.
+ this.grid = new Grid();
+ // prop: legend
+ // see <$.jqplot.TableLegendRenderer>
+ this.legend = new Legend();
+ // prop: noDataIndicator
+ // Options to set up a mock plot with a data loading indicator if no data is specified.
+ this.negativeSeriesColors = $.jqplot.config.defaultNegativeColors;
+ this.noDataIndicator = {
+ show: false,
+ indicator: 'Loading Data...',
+ axes: {
+ xaxis: {
+ min: 0,
+ max: 10,
+ tickInterval: 2,
+ show: true
+ },
+ yaxis: {
+ min: 0,
+ max: 12,
+ tickInterval: 3,
+ show: true
+ }
+ }
+ };
+ // container to hold all of the merged options. Convienence for plugins.
+ this.options = {};
+ this.previousSeriesStack = [];
+ // Namespece to hold plugins. Generally non-renderer plugins add themselves to here.
+ this.plugins = {};
+ // prop: series
+ // Array of series object options.
+ // see <Series> for series specific options.
+ this.series = [];
+ // array of series indicies. Keep track of order
+ // which series canvases are displayed, lowest
+ // to highest, back to front.
+ this.seriesStack = [];
+ // prop: seriesColors
+ // Ann array of CSS color specifications that will be applied, in order,
+ // to the series in the plot. Colors will wrap around so, if their
+ // are more series than colors, colors will be reused starting at the
+ // beginning. For pie charts, this specifies the colors of the slices.
+ this.seriesColors = $.jqplot.config.defaultColors;
+ // prop: sortData
+ // false to not sort the data passed in by the user.
+ // Many bar, stakced and other graphs as well as many plugins depend on
+ // having sorted data.
+ this.sortData = true;
+ // prop: stackSeries
+ // true or false, creates a stack or "mountain" plot.
+ // Not all series renderers may implement this option.
+ this.stackSeries = false;
+ // a shortcut for axis syncTicks options. Not implemented yet.
+ this.syncXTicks = true;
+ // a shortcut for axis syncTicks options. Not implemented yet.
+ this.syncYTicks = true;
+ // the jquery object for the dom target.
+ this.target = null;
+ // The id of the dom element to render the plot into
+ this.targetId = null;
+ // prop textColor
+ // css spec for the css color attribute. Default for the entire plot.
+ this.textColor;
+ // prop: title
+ // Title object. See <Title> for specific options. As a shortcut, you
+ // can specify the title option as just a string like: title: 'My Plot'
+ // and this will create a new title object with the specified text.
+ this.title = new Title();
+ // Count how many times the draw method has been called while the plot is visible.
+ // Mostly used to test if plot has never been dran (=0), has been successfully drawn
+ // into a visible container once (=1) or draw more than once into a visible container.
+ // Can use this in tests to see if plot has been visibly drawn at least one time.
+ // After plot has been visibly drawn once, it generally doesn't need redrawn if its
+ // container is hidden and shown.
+ this._drawCount = 0;
+ // sum of y values for all series in plot.
+ // used in mekko chart.
+ this._sumy = 0;
+ this._sumx = 0;
+ // array to hold the cumulative stacked series data.
+ // used to ajust the individual series data, which won't have access to other
+ // series data.
+ this._stackData = [];
+ // array that holds the data to be plotted. This will be the series data
+ // merged with the the appropriate data from _stackData according to the stackAxis.
+ this._plotData = [];
+ this._width = null;
+ this._height = null;
+ this._plotDimensions = {height:null, width:null};
+ this._gridPadding = {top:null, right:null, bottom:null, left:null};
+ this._defaultGridPadding = {top:10, right:10, bottom:23, left:10};
+
+ this._addDomReference = $.jqplot.config.addDomReference;
+
+ this.preInitHooks = new $.jqplot.HooksManager();
+ this.postInitHooks = new $.jqplot.HooksManager();
+ this.preParseOptionsHooks = new $.jqplot.HooksManager();
+ this.postParseOptionsHooks = new $.jqplot.HooksManager();
+ this.preDrawHooks = new $.jqplot.HooksManager();
+ this.postDrawHooks = new $.jqplot.HooksManager();
+ this.preDrawSeriesHooks = new $.jqplot.HooksManager();
+ this.postDrawSeriesHooks = new $.jqplot.HooksManager();
+ this.preDrawLegendHooks = new $.jqplot.HooksManager();
+ this.addLegendRowHooks = new $.jqplot.HooksManager();
+ this.preSeriesInitHooks = new $.jqplot.HooksManager();
+ this.postSeriesInitHooks = new $.jqplot.HooksManager();
+ this.preParseSeriesOptionsHooks = new $.jqplot.HooksManager();
+ this.postParseSeriesOptionsHooks = new $.jqplot.HooksManager();
+ this.eventListenerHooks = new $.jqplot.EventListenerManager();
+ this.preDrawSeriesShadowHooks = new $.jqplot.HooksManager();
+ this.postDrawSeriesShadowHooks = new $.jqplot.HooksManager();
+
+ this.colorGenerator = new $.jqplot.ColorGenerator();
+ this.negativeColorGenerator = new $.jqplot.ColorGenerator();
+
+ this.canvasManager = new $.jqplot.CanvasManager();
+
+ this.themeEngine = new $.jqplot.ThemeEngine();
+
+ var seriesColorsIndex = 0;
+
+ // Group: methods
+ //
+ // method: init
+ // sets the plot target, checks data and applies user
+ // options to plot.
+ this.init = function(target, data, options) {
+ options = options || {};
+ for (var i=0; i<$.jqplot.preInitHooks.length; i++) {
+ $.jqplot.preInitHooks[i].call(this, target, data, options);
+ }
+
+ for (var i=0; i<this.preInitHooks.hooks.length; i++) {
+ this.preInitHooks.hooks[i].call(this, target, data, options);
+ }
+
+ this.targetId = '#'+target;
+ this.target = $('#'+target);
+
+ //////
+ // Add a reference to plot
+ //////
+ if (this._addDomReference) {
+ this.target.data('jqplot', this);
+ }
+ // remove any error class that may be stuck on target.
+ this.target.removeClass('jqplot-error');
+ if (!this.target.get(0)) {
+ throw "No plot target specified";
+ }
+
+ // make sure the target is positioned by some means and set css
+ if (this.target.css('position') == 'static') {
+ this.target.css('position', 'relative');
+ }
+ if (!this.target.hasClass('jqplot-target')) {
+ this.target.addClass('jqplot-target');
+ }
+
+ // if no height or width specified, use a default.
+ if (!this.target.height()) {
+ var h;
+ if (options && options.height) {
+ h = parseInt(options.height, 10);
+ }
+ else if (this.target.attr('data-height')) {
+ h = parseInt(this.target.attr('data-height'), 10);
+ }
+ else {
+ h = parseInt($.jqplot.config.defaultHeight, 10);
+ }
+ this._height = h;
+ this.target.css('height', h+'px');
+ }
+ else {
+ this._height = h = this.target.height();
+ }
+ if (!this.target.width()) {
+ var w;
+ if (options && options.width) {
+ w = parseInt(options.width, 10);
+ }
+ else if (this.target.attr('data-width')) {
+ w = parseInt(this.target.attr('data-width'), 10);
+ }
+ else {
+ w = parseInt($.jqplot.config.defaultWidth, 10);
+ }
+ this._width = w;
+ this.target.css('width', w+'px');
+ }
+ else {
+ this._width = w = this.target.width();
+ }
+
+ for (var i=0, l=_axisNames.length; i<l; i++) {
+ this.axes[_axisNames[i]] = new Axis(_axisNames[i]);
+ }
+
+ this._plotDimensions.height = this._height;
+ this._plotDimensions.width = this._width;
+ this.grid._plotDimensions = this._plotDimensions;
+ this.title._plotDimensions = this._plotDimensions;
+ this.baseCanvas._plotDimensions = this._plotDimensions;
+ this.eventCanvas._plotDimensions = this._plotDimensions;
+ this.legend._plotDimensions = this._plotDimensions;
+ if (this._height <=0 || this._width <=0 || !this._height || !this._width) {
+ throw "Canvas dimension not set";
+ }
+
+ if (options.dataRenderer && $.isFunction(options.dataRenderer)) {
+ if (options.dataRendererOptions) {
+ this.dataRendererOptions = options.dataRendererOptions;
+ }
+ this.dataRenderer = options.dataRenderer;
+ data = this.dataRenderer(data, this, this.dataRendererOptions);
+ }
+
+ if (options.noDataIndicator && $.isPlainObject(options.noDataIndicator)) {
+ $.extend(true, this.noDataIndicator, options.noDataIndicator);
+ }
+
+ if (data == null || $.isArray(data) == false || data.length == 0 || $.isArray(data[0]) == false || data[0].length == 0) {
+
+ if (this.noDataIndicator.show == false) {
+ throw "No Data";
+ }
+
+ else {
+ // have to be descructive here in order for plot to not try and render series.
+ // This means that $.jqplot() will have to be called again when there is data.
+ //delete options.series;
+
+ for (var ax in this.noDataIndicator.axes) {
+ for (var prop in this.noDataIndicator.axes[ax]) {
+ this.axes[ax][prop] = this.noDataIndicator.axes[ax][prop];
+ }
+ }
+
+ this.postDrawHooks.add(function() {
+ var eh = this.eventCanvas.getHeight();
+ var ew = this.eventCanvas.getWidth();
+ var temp = $('<div class="jqplot-noData-container" style="position:absolute;"></div>');
+ this.target.append(temp);
+ temp.height(eh);
+ temp.width(ew);
+ temp.css('top', this.eventCanvas._offsets.top);
+ temp.css('left', this.eventCanvas._offsets.left);
+
+ var temp2 = $('<div class="jqplot-noData-contents" style="text-align:center; position:relative; margin-left:auto; margin-right:auto;"></div>');
+ temp.append(temp2);
+ temp2.html(this.noDataIndicator.indicator);
+ var th = temp2.height();
+ var tw = temp2.width();
+ temp2.height(th);
+ temp2.width(tw);
+ temp2.css('top', (eh - th)/2 + 'px');
+ });
+
+ }
+ }
+
+ // make a copy of the data
+ this.data = $.extend(true, [], data);
+
+ this.parseOptions(options);
+
+ if (this.textColor) {
+ this.target.css('color', this.textColor);
+ }
+ if (this.fontFamily) {
+ this.target.css('font-family', this.fontFamily);
+ }
+ if (this.fontSize) {
+ this.target.css('font-size', this.fontSize);
+ }
+
+ this.title.init();
+ this.legend.init();
+ this._sumy = 0;
+ this._sumx = 0;
+ this.computePlotData();
+ for (var i=0; i<this.series.length; i++) {
+ // set default stacking order for series canvases
+ this.seriesStack.push(i);
+ this.previousSeriesStack.push(i);
+ this.series[i].shadowCanvas._plotDimensions = this._plotDimensions;
+ this.series[i].canvas._plotDimensions = this._plotDimensions;
+ for (var j=0; j<$.jqplot.preSeriesInitHooks.length; j++) {
+ $.jqplot.preSeriesInitHooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ for (var j=0; j<this.preSeriesInitHooks.hooks.length; j++) {
+ this.preSeriesInitHooks.hooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ // this.populatePlotData(this.series[i], i);
+ this.series[i]._plotDimensions = this._plotDimensions;
+ this.series[i].init(i, this.grid.borderWidth, this);
+ for (var j=0; j<$.jqplot.postSeriesInitHooks.length; j++) {
+ $.jqplot.postSeriesInitHooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ for (var j=0; j<this.postSeriesInitHooks.hooks.length; j++) {
+ this.postSeriesInitHooks.hooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ this._sumy += this.series[i]._sumy;
+ this._sumx += this.series[i]._sumx;
+ }
+
+ var name,
+ axis;
+ for (var i=0, l=_axisNames.length; i<l; i++) {
+ name = _axisNames[i];
+ axis = this.axes[name];
+ axis._plotDimensions = this._plotDimensions;
+ axis.init();
+ if (this.axes[name].borderColor == null) {
+ if (name.charAt(0) !== 'x' && axis.useSeriesColor === true && axis.show) {
+ axis.borderColor = axis._series[0].color;
+ }
+ else {
+ axis.borderColor = this.grid.borderColor;
+ }
+ }
+ }
+
+ if (this.sortData) {
+ sortData(this.series);
+ }
+ this.grid.init();
+ this.grid._axes = this.axes;
+
+ this.legend._series = this.series;
+
+ for (var i=0; i<$.jqplot.postInitHooks.length; i++) {
+ $.jqplot.postInitHooks[i].call(this, target, this.data, options);
+ }
+
+ for (var i=0; i<this.postInitHooks.hooks.length; i++) {
+ this.postInitHooks.hooks[i].call(this, target, this.data, options);
+ }
+ };
+
+ // method: resetAxesScale
+ // Reset the specified axes min, max, numberTicks and tickInterval properties to null
+ // or reset these properties on all axes if no list of axes is provided.
+ //
+ // Parameters:
+ // axes - Boolean to reset or not reset all axes or an array or object of axis names to reset.
+ this.resetAxesScale = function(axes, options) {
+ var opts = options || {};
+ var ax = axes || this.axes;
+ if (ax === true) {
+ ax = this.axes;
+ }
+ if ($.isArray(ax)) {
+ for (var i = 0; i < ax.length; i++) {
+ this.axes[ax[i]].resetScale(opts[ax[i]]);
+ }
+ }
+ else if (typeof(ax) === 'object') {
+ for (var name in ax) {
+ this.axes[name].resetScale(opts[name]);
+ }
+ }
+ };
+ // method: reInitialize
+ // reinitialize plot for replotting.
+ // not called directly.
+ this.reInitialize = function (data, opts) {
+ // Plot should be visible and have a height and width.
+ // If plot doesn't have height and width for some
+ // reason, set it by other means. Plot must not have
+ // a display:none attribute, however.
+
+ var options = $.extend(true, {}, this.options, opts);
+
+ var target = this.targetId.substr(1);
+ var tdata = (data == null) ? this.data : data;
+
+ for (var i=0; i<$.jqplot.preInitHooks.length; i++) {
+ $.jqplot.preInitHooks[i].call(this, target, tdata, options);
+ }
+
+ for (var i=0; i<this.preInitHooks.hooks.length; i++) {
+ this.preInitHooks.hooks[i].call(this, target, tdata, options);
+ }
+
+ this._height = this.target.height();
+ this._width = this.target.width();
+
+ if (this._height <=0 || this._width <=0 || !this._height || !this._width) {
+ throw "Target dimension not set";
+ }
+
+ this._plotDimensions.height = this._height;
+ this._plotDimensions.width = this._width;
+ this.grid._plotDimensions = this._plotDimensions;
+ this.title._plotDimensions = this._plotDimensions;
+ this.baseCanvas._plotDimensions = this._plotDimensions;
+ this.eventCanvas._plotDimensions = this._plotDimensions;
+ this.legend._plotDimensions = this._plotDimensions;
+
+ var name,
+ t,
+ j,
+ axis;
+
+ for (var i=0, l=_axisNames.length; i<l; i++) {
+ name = _axisNames[i];
+ axis = this.axes[name];
+
+ // Memory Leaks patch : clear ticks elements
+ t = axis._ticks;
+ for (var j = 0, tlen = t.length; j < tlen; j++) {
+ var el = t[j]._elem;
+ if (el) {
+ // if canvas renderer
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ window.G_vmlCanvasManager.uninitElement(el.get(0));
+ }
+ el.emptyForce();
+ el = null;
+ t._elem = null;
+ }
+ }
+ t = null;
+
+ delete axis.ticks;
+ delete axis._ticks;
+ this.axes[name] = new Axis(name);
+ this.axes[name]._plotWidth = this._width;
+ this.axes[name]._plotHeight = this._height;
+ }
+
+ if (data) {
+ if (options.dataRenderer && $.isFunction(options.dataRenderer)) {
+ if (options.dataRendererOptions) {
+ this.dataRendererOptions = options.dataRendererOptions;
+ }
+ this.dataRenderer = options.dataRenderer;
+ data = this.dataRenderer(data, this, this.dataRendererOptions);
+ }
+
+ // make a copy of the data
+ this.data = $.extend(true, [], data);
+ }
+
+ if (opts) {
+ this.parseOptions(options);
+ }
+
+ this.title._plotWidth = this._width;
+
+ if (this.textColor) {
+ this.target.css('color', this.textColor);
+ }
+ if (this.fontFamily) {
+ this.target.css('font-family', this.fontFamily);
+ }
+ if (this.fontSize) {
+ this.target.css('font-size', this.fontSize);
+ }
+
+ this.title.init();
+ this.legend.init();
+ this._sumy = 0;
+ this._sumx = 0;
+
+ this.seriesStack = [];
+ this.previousSeriesStack = [];
+
+ this.computePlotData();
+ for (var i=0, l=this.series.length; i<l; i++) {
+ // set default stacking order for series canvases
+ this.seriesStack.push(i);
+ this.previousSeriesStack.push(i);
+ this.series[i].shadowCanvas._plotDimensions = this._plotDimensions;
+ this.series[i].canvas._plotDimensions = this._plotDimensions;
+ for (var j=0; j<$.jqplot.preSeriesInitHooks.length; j++) {
+ $.jqplot.preSeriesInitHooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ for (var j=0; j<this.preSeriesInitHooks.hooks.length; j++) {
+ this.preSeriesInitHooks.hooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ // this.populatePlotData(this.series[i], i);
+ this.series[i]._plotDimensions = this._plotDimensions;
+ this.series[i].init(i, this.grid.borderWidth, this);
+ for (var j=0; j<$.jqplot.postSeriesInitHooks.length; j++) {
+ $.jqplot.postSeriesInitHooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ for (var j=0; j<this.postSeriesInitHooks.hooks.length; j++) {
+ this.postSeriesInitHooks.hooks[j].call(this.series[i], target, this.data, this.options.seriesDefaults, this.options.series[i], this);
+ }
+ this._sumy += this.series[i]._sumy;
+ this._sumx += this.series[i]._sumx;
+ }
+
+ for (var i=0, l=_axisNames.length; i<l; i++) {
+ name = _axisNames[i];
+ axis = this.axes[name];
+
+ axis._plotDimensions = this._plotDimensions;
+ axis.init();
+ if (axis.borderColor == null) {
+ if (name.charAt(0) !== 'x' && axis.useSeriesColor === true && axis.show) {
+ axis.borderColor = axis._series[0].color;
+ }
+ else {
+ axis.borderColor = this.grid.borderColor;
+ }
+ }
+ }
+
+ if (this.sortData) {
+ sortData(this.series);
+ }
+ this.grid.init();
+ this.grid._axes = this.axes;
+
+ this.legend._series = this.series;
+
+ for (var i=0, l=$.jqplot.postInitHooks.length; i<l; i++) {
+ $.jqplot.postInitHooks[i].call(this, target, this.data, options);
+ }
+
+ for (var i=0, l=this.postInitHooks.hooks.length; i<l; i++) {
+ this.postInitHooks.hooks[i].call(this, target, this.data, options);
+ }
+ };
+
+
+
+ // method: quickInit
+ //
+ // Quick reinitialization plot for replotting.
+ // Does not parse options ore recreate axes and series.
+ // not called directly.
+ this.quickInit = function () {
+ // Plot should be visible and have a height and width.
+ // If plot doesn't have height and width for some
+ // reason, set it by other means. Plot must not have
+ // a display:none attribute, however.
+
+ this._height = this.target.height();
+ this._width = this.target.width();
+
+ if (this._height <=0 || this._width <=0 || !this._height || !this._width) {
+ throw "Target dimension not set";
+ }
+
+ this._plotDimensions.height = this._height;
+ this._plotDimensions.width = this._width;
+ this.grid._plotDimensions = this._plotDimensions;
+ this.title._plotDimensions = this._plotDimensions;
+ this.baseCanvas._plotDimensions = this._plotDimensions;
+ this.eventCanvas._plotDimensions = this._plotDimensions;
+ this.legend._plotDimensions = this._plotDimensions;
+
+ for (var n in this.axes) {
+ this.axes[n]._plotWidth = this._width;
+ this.axes[n]._plotHeight = this._height;
+ }
+
+ this.title._plotWidth = this._width;
+
+ if (this.textColor) {
+ this.target.css('color', this.textColor);
+ }
+ if (this.fontFamily) {
+ this.target.css('font-family', this.fontFamily);
+ }
+ if (this.fontSize) {
+ this.target.css('font-size', this.fontSize);
+ }
+
+ this._sumy = 0;
+ this._sumx = 0;
+ this.computePlotData();
+ for (var i=0; i<this.series.length; i++) {
+ // this.populatePlotData(this.series[i], i);
+ if (this.series[i]._type === 'line' && this.series[i].renderer.bands.show) {
+ this.series[i].renderer.initBands.call(this.series[i], this.series[i].renderer.options, this);
+ }
+ this.series[i]._plotDimensions = this._plotDimensions;
+ this.series[i].canvas._plotDimensions = this._plotDimensions;
+ //this.series[i].init(i, this.grid.borderWidth);
+ this._sumy += this.series[i]._sumy;
+ this._sumx += this.series[i]._sumx;
+ }
+
+ var name;
+
+ for (var j=0; j<12; j++) {
+ name = _axisNames[j];
+ // Memory Leaks patch : clear ticks elements
+ var t = this.axes[name]._ticks;
+ for (var i = 0; i < t.length; i++) {
+ var el = t[i]._elem;
+ if (el) {
+ // if canvas renderer
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ window.G_vmlCanvasManager.uninitElement(el.get(0));
+ }
+ el.emptyForce();
+ el = null;
+ t._elem = null;
+ }
+ }
+ t = null;
+
+ this.axes[name]._plotDimensions = this._plotDimensions;
+ this.axes[name]._ticks = [];
+ // this.axes[name].renderer.init.call(this.axes[name], {});
+ }
+
+ if (this.sortData) {
+ sortData(this.series);
+ }
+
+ this.grid._axes = this.axes;
+
+ this.legend._series = this.series;
+ };
+
+ // sort the series data in increasing order.
+ function sortData(series) {
+ var d, sd, pd, ppd, ret;
+ for (var i=0; i<series.length; i++) {
+ var check;
+ var bat = [series[i].data, series[i]._stackData, series[i]._plotData, series[i]._prevPlotData];
+ for (var n=0; n<4; n++) {
+ check = true;
+ d = bat[n];
+ if (series[i]._stackAxis == 'x') {
+ for (var j = 0; j < d.length; j++) {
+ if (typeof(d[j][1]) != "number") {
+ check = false;
+ break;
+ }
+ }
+ if (check) {
+ d.sort(function(a,b) { return a[1] - b[1]; });
+ }
+ }
+ else {
+ for (var j = 0; j < d.length; j++) {
+ if (typeof(d[j][0]) != "number") {
+ check = false;
+ break;
+ }
+ }
+ if (check) {
+ d.sort(function(a,b) { return a[0] - b[0]; });
+ }
+ }
+ }
+
+ }
+ }
+
+ this.computePlotData = function() {
+ this._plotData = [];
+ this._stackData = [];
+ var series,
+ index,
+ l;
+
+
+ for (index=0, l=this.series.length; index<l; index++) {
+ series = this.series[index];
+ this._plotData.push([]);
+ this._stackData.push([]);
+ var cd = series.data;
+ this._plotData[index] = $.extend(true, [], cd);
+ this._stackData[index] = $.extend(true, [], cd);
+ series._plotData = this._plotData[index];
+ series._stackData = this._stackData[index];
+ var plotValues = {x:[], y:[]};
+
+ if (this.stackSeries && !series.disableStack) {
+ series._stack = true;
+ ///////////////////////////
+ // have to check for nulls
+ ///////////////////////////
+ var sidx = (series._stackAxis === 'x') ? 0 : 1;
+
+ for (var k=0, cdl=cd.length; k<cdl; k++) {
+ var temp = cd[k][sidx];
+ if (temp == null) {
+ temp = 0;
+ }
+ this._plotData[index][k][sidx] = temp;
+ this._stackData[index][k][sidx] = temp;
+
+ if (index > 0) {
+ for (var j=index; j--;) {
+ var prevval = this._plotData[j][k][sidx];
+ // only need to sum up the stack axis column of data
+ // and only sum if it is of same sign.
+ // if previous series isn't same sign, keep looking
+ // at earlier series untill we find one of same sign.
+ if (temp * prevval >= 0) {
+ this._plotData[index][k][sidx] += prevval;
+ this._stackData[index][k][sidx] += prevval;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+ else {
+ for (var i=0; i<series.data.length; i++) {
+ plotValues.x.push(series.data[i][0]);
+ plotValues.y.push(series.data[i][1]);
+ }
+ this._stackData.push(series.data);
+ this.series[index]._stackData = series.data;
+ this._plotData.push(series.data);
+ series._plotData = series.data;
+ series._plotValues = plotValues;
+ }
+ if (index>0) {
+ series._prevPlotData = this.series[index-1]._plotData;
+ }
+ series._sumy = 0;
+ series._sumx = 0;
+ for (i=series.data.length-1; i>-1; i--) {
+ series._sumy += series.data[i][1];
+ series._sumx += series.data[i][0];
+ }
+ }
+
+ };
+
+ // populate the _stackData and _plotData arrays for the plot and the series.
+ this.populatePlotData = function(series, index) {
+ // if a stacked chart, compute the stacked data
+ this._plotData = [];
+ this._stackData = [];
+ series._stackData = [];
+ series._plotData = [];
+ var plotValues = {x:[], y:[]};
+ if (this.stackSeries && !series.disableStack) {
+ series._stack = true;
+ var sidx = (series._stackAxis === 'x') ? 0 : 1;
+ // var idx = sidx ? 0 : 1;
+ // push the current data into stackData
+ //this._stackData.push(this.series[i].data);
+ var temp = $.extend(true, [], series.data);
+ // create the data that will be plotted for this series
+ var plotdata = $.extend(true, [], series.data);
+ var tempx, tempy, dval, stackval, comparator;
+ // for first series, nothing to add to stackData.
+ for (var j=0; j<index; j++) {
+ var cd = this.series[j].data;
+ for (var k=0; k<cd.length; k++) {
+ dval = cd[k];
+ tempx = (dval[0] != null) ? dval[0] : 0;
+ tempy = (dval[1] != null) ? dval[1] : 0;
+ temp[k][0] += tempx;
+ temp[k][1] += tempy;
+ stackval = (sidx) ? tempy : tempx;
+ // only need to sum up the stack axis column of data
+ // and only sum if it is of same sign.
+ if (series.data[k][sidx] * stackval >= 0) {
+ plotdata[k][sidx] += stackval;
+ }
+ }
+ }
+ for (var i=0; i<plotdata.length; i++) {
+ plotValues.x.push(plotdata[i][0]);
+ plotValues.y.push(plotdata[i][1]);
+ }
+ this._plotData.push(plotdata);
+ this._stackData.push(temp);
+ series._stackData = temp;
+ series._plotData = plotdata;
+ series._plotValues = plotValues;
+ }
+ else {
+ for (var i=0; i<series.data.length; i++) {
+ plotValues.x.push(series.data[i][0]);
+ plotValues.y.push(series.data[i][1]);
+ }
+ this._stackData.push(series.data);
+ this.series[index]._stackData = series.data;
+ this._plotData.push(series.data);
+ series._plotData = series.data;
+ series._plotValues = plotValues;
+ }
+ if (index>0) {
+ series._prevPlotData = this.series[index-1]._plotData;
+ }
+ series._sumy = 0;
+ series._sumx = 0;
+ for (i=series.data.length-1; i>-1; i--) {
+ series._sumy += series.data[i][1];
+ series._sumx += series.data[i][0];
+ }
+ };
+
+ // function to safely return colors from the color array and wrap around at the end.
+ this.getNextSeriesColor = (function(t) {
+ var idx = 0;
+ var sc = t.seriesColors;
+
+ return function () {
+ if (idx < sc.length) {
+ return sc[idx++];
+ }
+ else {
+ idx = 0;
+ return sc[idx++];
+ }
+ };
+ })(this);
+
+ this.parseOptions = function(options){
+ for (var i=0; i<this.preParseOptionsHooks.hooks.length; i++) {
+ this.preParseOptionsHooks.hooks[i].call(this, options);
+ }
+ for (var i=0; i<$.jqplot.preParseOptionsHooks.length; i++) {
+ $.jqplot.preParseOptionsHooks[i].call(this, options);
+ }
+ this.options = $.extend(true, {}, this.defaults, options);
+ var opts = this.options;
+ this.animate = opts.animate;
+ this.animateReplot = opts.animateReplot;
+ this.stackSeries = opts.stackSeries;
+ if ($.isPlainObject(opts.fillBetween)) {
+
+ var temp = ['series1', 'series2', 'color', 'baseSeries', 'fill'],
+ tempi;
+
+ for (var i=0, l=temp.length; i<l; i++) {
+ tempi = temp[i];
+ if (opts.fillBetween[tempi] != null) {
+ this.fillBetween[tempi] = opts.fillBetween[tempi];
+ }
+ }
+ }
+
+ if (opts.seriesColors) {
+ this.seriesColors = opts.seriesColors;
+ }
+ if (opts.negativeSeriesColors) {
+ this.negativeSeriesColors = opts.negativeSeriesColors;
+ }
+ if (opts.captureRightClick) {
+ this.captureRightClick = opts.captureRightClick;
+ }
+ this.defaultAxisStart = (options && options.defaultAxisStart != null) ? options.defaultAxisStart : this.defaultAxisStart;
+ this.colorGenerator.setColors(this.seriesColors);
+ this.negativeColorGenerator.setColors(this.negativeSeriesColors);
+ // var cg = new this.colorGenerator(this.seriesColors);
+ // var ncg = new this.colorGenerator(this.negativeSeriesColors);
+ // this._gridPadding = this.options.gridPadding;
+ $.extend(true, this._gridPadding, opts.gridPadding);
+ this.sortData = (opts.sortData != null) ? opts.sortData : this.sortData;
+ for (var i=0; i<12; i++) {
+ var n = _axisNames[i];
+ var axis = this.axes[n];
+ axis._options = $.extend(true, {}, opts.axesDefaults, opts.axes[n]);
+ $.extend(true, axis, opts.axesDefaults, opts.axes[n]);
+ axis._plotWidth = this._width;
+ axis._plotHeight = this._height;
+ }
+ // if (this.data.length == 0) {
+ // this.data = [];
+ // for (var i=0; i<this.options.series.length; i++) {
+ // this.data.push(this.options.series.data);
+ // }
+ // }
+
+ var normalizeData = function(data, dir, start) {
+ // return data as an array of point arrays,
+ // in form [[x1,y1...], [x2,y2...], ...]
+ var temp = [];
+ var i, l;
+ dir = dir || 'vertical';
+ if (!$.isArray(data[0])) {
+ // we have a series of scalars. One line with just y values.
+ // turn the scalar list of data into a data array of form:
+ // [[1, data[0]], [2, data[1]], ...]
+ for (i=0, l=data.length; i<l; i++) {
+ if (dir == 'vertical') {
+ temp.push([start + i, data[i]]);
+ }
+ else {
+ temp.push([data[i], start+i]);
+ }
+ }
+ }
+ else {
+ // we have a properly formatted data series, copy it.
+ $.extend(true, temp, data);
+ }
+ return temp;
+ };
+
+ var colorIndex = 0;
+ this.series = [];
+ for (var i=0; i<this.data.length; i++) {
+ var sopts = $.extend(true, {index: i}, {seriesColors:this.seriesColors, negativeSeriesColors:this.negativeSeriesColors}, this.options.seriesDefaults, this.options.series[i], {rendererOptions:{animation:{show: this.animate}}});
+ // pass in options in case something needs set prior to initialization.
+ var temp = new Series(sopts);
+ for (var j=0; j<$.jqplot.preParseSeriesOptionsHooks.length; j++) {
+ $.jqplot.preParseSeriesOptionsHooks[j].call(temp, this.options.seriesDefaults, this.options.series[i]);
+ }
+ for (var j=0; j<this.preParseSeriesOptionsHooks.hooks.length; j++) {
+ this.preParseSeriesOptionsHooks.hooks[j].call(temp, this.options.seriesDefaults, this.options.series[i]);
+ }
+ // Now go back and apply the options to the series. Really should just do this during initializaiton, but don't want to
+ // mess up preParseSeriesOptionsHooks at this point.
+ $.extend(true, temp, sopts);
+ var dir = 'vertical';
+ if (temp.renderer === $.jqplot.BarRenderer && temp.rendererOptions && temp.rendererOptions.barDirection == 'horizontal') {
+ dir = 'horizontal';
+ temp._stackAxis = 'x';
+ temp._primaryAxis = '_yaxis';
+ }
+ temp.data = normalizeData(this.data[i], dir, this.defaultAxisStart);
+ switch (temp.xaxis) {
+ case 'xaxis':
+ temp._xaxis = this.axes.xaxis;
+ break;
+ case 'x2axis':
+ temp._xaxis = this.axes.x2axis;
+ break;
+ default:
+ break;
+ }
+ temp._yaxis = this.axes[temp.yaxis];
+ temp._xaxis._series.push(temp);
+ temp._yaxis._series.push(temp);
+ if (temp.show) {
+ temp._xaxis.show = true;
+ temp._yaxis.show = true;
+ }
+ else {
+ if (temp._xaxis.scaleToHiddenSeries) {
+ temp._xaxis.show = true;
+ }
+ if (temp._yaxis.scaleToHiddenSeries) {
+ temp._yaxis.show = true;
+ }
+ }
+
+ // // parse the renderer options and apply default colors if not provided
+ // if (!temp.color && temp.show != false) {
+ // temp.color = cg.next();
+ // colorIndex = cg.getIndex() - 1;;
+ // }
+ // if (!temp.negativeColor && temp.show != false) {
+ // temp.negativeColor = ncg.get(colorIndex);
+ // ncg.setIndex(colorIndex);
+ // }
+ if (!temp.label) {
+ temp.label = 'Series '+ (i+1).toString();
+ }
+ // temp.rendererOptions.show = temp.show;
+ // $.extend(true, temp.renderer, {color:this.seriesColors[i]}, this.rendererOptions);
+ this.series.push(temp);
+ for (var j=0; j<$.jqplot.postParseSeriesOptionsHooks.length; j++) {
+ $.jqplot.postParseSeriesOptionsHooks[j].call(this.series[i], this.options.seriesDefaults, this.options.series[i]);
+ }
+ for (var j=0; j<this.postParseSeriesOptionsHooks.hooks.length; j++) {
+ this.postParseSeriesOptionsHooks.hooks[j].call(this.series[i], this.options.seriesDefaults, this.options.series[i]);
+ }
+ }
+
+ // copy the grid and title options into this object.
+ $.extend(true, this.grid, this.options.grid);
+ // if axis border properties aren't set, set default.
+ for (var i=0, l=_axisNames.length; i<l; i++) {
+ var n = _axisNames[i];
+ var axis = this.axes[n];
+ if (axis.borderWidth == null) {
+ axis.borderWidth =this.grid.borderWidth;
+ }
+ }
+
+ if (typeof this.options.title == 'string') {
+ this.title.text = this.options.title;
+ }
+ else if (typeof this.options.title == 'object') {
+ $.extend(true, this.title, this.options.title);
+ }
+ this.title._plotWidth = this._width;
+ this.legend.setOptions(this.options.legend);
+
+ for (var i=0; i<$.jqplot.postParseOptionsHooks.length; i++) {
+ $.jqplot.postParseOptionsHooks[i].call(this, options);
+ }
+ for (var i=0; i<this.postParseOptionsHooks.hooks.length; i++) {
+ this.postParseOptionsHooks.hooks[i].call(this, options);
+ }
+ };
+
+ // method: destroy
+ // Releases all resources occupied by the plot
+ this.destroy = function() {
+ this.canvasManager.freeAllCanvases();
+ if (this.eventCanvas && this.eventCanvas._elem) {
+ this.eventCanvas._elem.unbind();
+ }
+ // Couple of posts on Stack Overflow indicate that empty() doesn't
+ // always cear up the dom and release memory. Sometimes setting
+ // innerHTML property to null is needed. Particularly on IE, may
+ // have to directly set it to null, bypassing $.
+ this.target.empty();
+
+ this.target[0].innerHTML = '';
+ };
+
+ // method: replot
+ // Does a reinitialization of the plot followed by
+ // a redraw. Method could be used to interactively
+ // change plot characteristics and then replot.
+ //
+ // Parameters:
+ // options - Options used for replotting.
+ //
+ // Properties:
+ // clear - false to not clear (empty) the plot container before replotting (default: true).
+ // resetAxes - true to reset all axes min, max, numberTicks and tickInterval setting so axes will rescale themselves.
+ // optionally pass in list of axes to reset (e.g. ['xaxis', 'y2axis']) (default: false).
+ this.replot = function(options) {
+ var opts = options || {};
+ var data = opts.data || null;
+ var clear = (opts.clear === false) ? false : true;
+ var resetAxes = opts.resetAxes || false;
+ delete opts.data;
+ delete opts.clear;
+ delete opts.resetAxes;
+
+ this.target.trigger('jqplotPreReplot');
+
+ if (clear) {
+ this.destroy();
+ }
+ // if have data or other options, full reinit.
+ // otherwise, quickinit.
+ if (data || !$.isEmptyObject(opts)) {
+ this.reInitialize(data, opts);
+ }
+ else {
+ this.quickInit();
+ }
+
+ if (resetAxes) {
+ this.resetAxesScale(resetAxes, opts.axes);
+ }
+ this.draw();
+ this.target.trigger('jqplotPostReplot');
+ };
+
+ // method: redraw
+ // Empties the plot target div and redraws the plot.
+ // This enables plot data and properties to be changed
+ // and then to comletely clear the plot and redraw.
+ // redraw *will not* reinitialize any plot elements.
+ // That is, axes will not be autoscaled and defaults
+ // will not be reapplied to any plot elements. redraw
+ // is used primarily with zooming.
+ //
+ // Parameters:
+ // clear - false to not clear (empty) the plot container before redrawing (default: true).
+ this.redraw = function(clear) {
+ clear = (clear != null) ? clear : true;
+ this.target.trigger('jqplotPreRedraw');
+ if (clear) {
+ this.canvasManager.freeAllCanvases();
+ this.eventCanvas._elem.unbind();
+ // Dont think I bind any events to the target, this shouldn't be necessary.
+ // It will remove user's events.
+ // this.target.unbind();
+ this.target.empty();
+ }
+ for (var ax in this.axes) {
+ this.axes[ax]._ticks = [];
+ }
+ this.computePlotData();
+ // for (var i=0; i<this.series.length; i++) {
+ // this.populatePlotData(this.series[i], i);
+ // }
+ this._sumy = 0;
+ this._sumx = 0;
+ for (var i=0, tsl = this.series.length; i<tsl; i++) {
+ this._sumy += this.series[i]._sumy;
+ this._sumx += this.series[i]._sumx;
+ }
+ this.draw();
+ this.target.trigger('jqplotPostRedraw');
+ };
+
+ // method: draw
+ // Draws all elements of the plot into the container.
+ // Does not clear the container before drawing.
+ this.draw = function(){
+ if (this.drawIfHidden || this.target.is(':visible')) {
+ this.target.trigger('jqplotPreDraw');
+ var i,
+ j,
+ l,
+ tempseries;
+ for (i=0, l=$.jqplot.preDrawHooks.length; i<l; i++) {
+ $.jqplot.preDrawHooks[i].call(this);
+ }
+ for (i=0, l=this.preDrawHooks.length; i<l; i++) {
+ this.preDrawHooks.hooks[i].apply(this, this.preDrawSeriesHooks.args[i]);
+ }
+ // create an underlying canvas to be used for special features.
+ this.target.append(this.baseCanvas.createElement({left:0, right:0, top:0, bottom:0}, 'jqplot-base-canvas', null, this));
+ this.baseCanvas.setContext();
+ this.target.append(this.title.draw());
+ this.title.pack({top:0, left:0});
+
+ // make room for the legend between the grid and the edge.
+ // pass a dummy offsets object and a reference to the plot.
+ var legendElem = this.legend.draw({}, this);
+
+ var gridPadding = {top:0, left:0, bottom:0, right:0};
+
+ if (this.legend.placement == "outsideGrid") {
+ // temporarily append the legend to get dimensions
+ this.target.append(legendElem);
+ switch (this.legend.location) {
+ case 'n':
+ gridPadding.top += this.legend.getHeight();
+ break;
+ case 's':
+ gridPadding.bottom += this.legend.getHeight();
+ break;
+ case 'ne':
+ case 'e':
+ case 'se':
+ gridPadding.right += this.legend.getWidth();
+ break;
+ case 'nw':
+ case 'w':
+ case 'sw':
+ gridPadding.left += this.legend.getWidth();
+ break;
+ default: // same as 'ne'
+ gridPadding.right += this.legend.getWidth();
+ break;
+ }
+ legendElem = legendElem.detach();
+ }
+
+ var ax = this.axes;
+ var name;
+ // draw the yMidAxis first, so xaxis of pyramid chart can adjust itself if needed.
+ for (i=0; i<12; i++) {
+ name = _axisNames[i];
+ this.target.append(ax[name].draw(this.baseCanvas._ctx, this));
+ ax[name].set();
+ }
+ if (ax.yaxis.show) {
+ gridPadding.left += ax.yaxis.getWidth();
+ }
+ var ra = ['y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis'];
+ var rapad = [0, 0, 0, 0, 0, 0, 0, 0];
+ var gpr = 0;
+ var n;
+ for (n=0; n<8; n++) {
+ if (ax[ra[n]].show) {
+ gpr += ax[ra[n]].getWidth();
+ rapad[n] = gpr;
+ }
+ }
+ gridPadding.right += gpr;
+ if (ax.x2axis.show) {
+ gridPadding.top += ax.x2axis.getHeight();
+ }
+ if (this.title.show) {
+ gridPadding.top += this.title.getHeight();
+ }
+ if (ax.xaxis.show) {
+ gridPadding.bottom += ax.xaxis.getHeight();
+ }
+
+ // end of gridPadding adjustments.
+
+ // if user passed in gridDimensions option, check against calculated gridPadding
+ if (this.options.gridDimensions && $.isPlainObject(this.options.gridDimensions)) {
+ var gdw = parseInt(this.options.gridDimensions.width, 10) || 0;
+ var gdh = parseInt(this.options.gridDimensions.height, 10) || 0;
+ var widthAdj = (this._width - gridPadding.left - gridPadding.right - gdw)/2;
+ var heightAdj = (this._height - gridPadding.top - gridPadding.bottom - gdh)/2;
+
+ if (heightAdj >= 0 && widthAdj >= 0) {
+ gridPadding.top += heightAdj;
+ gridPadding.bottom += heightAdj;
+ gridPadding.left += widthAdj;
+ gridPadding.right += widthAdj;
+ }
+ }
+ var arr = ['top', 'bottom', 'left', 'right'];
+ for (var n in arr) {
+ if (this._gridPadding[arr[n]] == null && gridPadding[arr[n]] > 0) {
+ this._gridPadding[arr[n]] = gridPadding[arr[n]];
+ }
+ else if (this._gridPadding[arr[n]] == null) {
+ this._gridPadding[arr[n]] = this._defaultGridPadding[arr[n]];
+ }
+ }
+
+ var legendPadding = this._gridPadding;
+
+ if (this.legend.placement === 'outsideGrid') {
+ legendPadding = {top:this.title.getHeight(), left: 0, right: 0, bottom: 0};
+ if (this.legend.location === 's') {
+ legendPadding.left = this._gridPadding.left;
+ legendPadding.right = this._gridPadding.right;
+ }
+ }
+
+ ax.xaxis.pack({position:'absolute', bottom:this._gridPadding.bottom - ax.xaxis.getHeight(), left:0, width:this._width}, {min:this._gridPadding.left, max:this._width - this._gridPadding.right});
+ ax.yaxis.pack({position:'absolute', top:0, left:this._gridPadding.left - ax.yaxis.getWidth(), height:this._height}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top});
+ ax.x2axis.pack({position:'absolute', top:this._gridPadding.top - ax.x2axis.getHeight(), left:0, width:this._width}, {min:this._gridPadding.left, max:this._width - this._gridPadding.right});
+ for (i=8; i>0; i--) {
+ ax[ra[i-1]].pack({position:'absolute', top:0, right:this._gridPadding.right - rapad[i-1]}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top});
+ }
+ var ltemp = (this._width - this._gridPadding.left - this._gridPadding.right)/2.0 + this._gridPadding.left - ax.yMidAxis.getWidth()/2.0;
+ ax.yMidAxis.pack({position:'absolute', top:0, left:ltemp, zIndex:9, textAlign: 'center'}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top});
+
+ this.target.append(this.grid.createElement(this._gridPadding, this));
+ this.grid.draw();
+
+ var series = this.series;
+ var seriesLength = series.length;
+ // put the shadow canvases behind the series canvases so shadows don't overlap on stacked bars.
+ for (i=0, l=seriesLength; i<l; i++) {
+ // draw series in order of stacking. This affects only
+ // order in which canvases are added to dom.
+ j = this.seriesStack[i];
+ this.target.append(series[j].shadowCanvas.createElement(this._gridPadding, 'jqplot-series-shadowCanvas', null, this));
+ series[j].shadowCanvas.setContext();
+ series[j].shadowCanvas._elem.data('seriesIndex', j);
+ }
+
+ for (i=0, l=seriesLength; i<l; i++) {
+ // draw series in order of stacking. This affects only
+ // order in which canvases are added to dom.
+ j = this.seriesStack[i];
+ this.target.append(series[j].canvas.createElement(this._gridPadding, 'jqplot-series-canvas', null, this));
+ series[j].canvas.setContext();
+ series[j].canvas._elem.data('seriesIndex', j);
+ }
+ // Need to use filled canvas to capture events in IE.
+ // Also, canvas seems to block selection of other elements in document on FF.
+ this.target.append(this.eventCanvas.createElement(this._gridPadding, 'jqplot-event-canvas', null, this));
+ this.eventCanvas.setContext();
+ this.eventCanvas._ctx.fillStyle = 'rgba(0,0,0,0)';
+ this.eventCanvas._ctx.fillRect(0,0,this.eventCanvas._ctx.canvas.width, this.eventCanvas._ctx.canvas.height);
+
+ // bind custom event handlers to regular events.
+ this.bindCustomEvents();
+
+ // draw legend before series if the series needs to know the legend dimensions.
+ if (this.legend.preDraw) {
+ this.eventCanvas._elem.before(legendElem);
+ this.legend.pack(legendPadding);
+ if (this.legend._elem) {
+ this.drawSeries({legendInfo:{location:this.legend.location, placement:this.legend.placement, width:this.legend.getWidth(), height:this.legend.getHeight(), xoffset:this.legend.xoffset, yoffset:this.legend.yoffset}});
+ }
+ else {
+ this.drawSeries();
+ }
+ }
+ else { // draw series before legend
+ this.drawSeries();
+ if (seriesLength) {
+ $(series[seriesLength-1].canvas._elem).after(legendElem);
+ }
+ this.legend.pack(legendPadding);
+ }
+
+ // register event listeners on the overlay canvas
+ for (var i=0, l=$.jqplot.eventListenerHooks.length; i<l; i++) {
+ // in the handler, this will refer to the eventCanvas dom element.
+ // make sure there are references back into plot objects.
+ this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]);
+ }
+
+ // register event listeners on the overlay canvas
+ for (var i=0, l=this.eventListenerHooks.hooks.length; i<l; i++) {
+ // in the handler, this will refer to the eventCanvas dom element.
+ // make sure there are references back into plot objects.
+ this.eventCanvas._elem.bind(this.eventListenerHooks.hooks[i][0], {plot:this}, this.eventListenerHooks.hooks[i][1]);
+ }
+
+ var fb = this.fillBetween;
+ if (fb.fill && fb.series1 !== fb.series2 && fb.series1 < seriesLength && fb.series2 < seriesLength && series[fb.series1]._type === 'line' && series[fb.series2]._type === 'line') {
+ this.doFillBetweenLines();
+ }
+
+ for (var i=0, l=$.jqplot.postDrawHooks.length; i<l; i++) {
+ $.jqplot.postDrawHooks[i].call(this);
+ }
+
+ for (var i=0, l=this.postDrawHooks.hooks.length; i<l; i++) {
+ this.postDrawHooks.hooks[i].apply(this, this.postDrawHooks.args[i]);
+ }
+
+ if (this.target.is(':visible')) {
+ this._drawCount += 1;
+ }
+
+ var temps,
+ tempr,
+ sel,
+ _els;
+ // ughh. ideally would hide all series then show them.
+ for (i=0, l=seriesLength; i<l; i++) {
+ temps = series[i];
+ tempr = temps.renderer;
+ sel = '.jqplot-point-label.jqplot-series-'+i;
+ if (tempr.animation && tempr.animation._supported && tempr.animation.show && (this._drawCount < 2 || this.animateReplot)) {
+ _els = this.target.find(sel);
+ _els.stop(true, true).hide();
+ temps.canvas._elem.stop(true, true).hide();
+ temps.shadowCanvas._elem.stop(true, true).hide();
+ temps.canvas._elem.jqplotEffect('blind', {mode: 'show', direction: tempr.animation.direction}, tempr.animation.speed);
+ temps.shadowCanvas._elem.jqplotEffect('blind', {mode: 'show', direction: tempr.animation.direction}, tempr.animation.speed);
+ _els.fadeIn(tempr.animation.speed*0.8);
+ }
+ }
+ _els = null;
+
+ this.target.trigger('jqplotPostDraw', [this]);
+ }
+ };
+
+ jqPlot.prototype.doFillBetweenLines = function () {
+ var fb = this.fillBetween;
+ var sid1 = fb.series1;
+ var sid2 = fb.series2;
+ // first series should always be lowest index
+ var id1 = (sid1 < sid2) ? sid1 : sid2;
+ var id2 = (sid2 > sid1) ? sid2 : sid1;
+
+ var series1 = this.series[id1];
+ var series2 = this.series[id2];
+
+ if (series2.renderer.smooth) {
+ var tempgd = series2.renderer._smoothedData.slice(0).reverse();
+ }
+ else {
+ var tempgd = series2.gridData.slice(0).reverse();
+ }
+
+ if (series1.renderer.smooth) {
+ var gd = series1.renderer._smoothedData.concat(tempgd);
+ }
+ else {
+ var gd = series1.gridData.concat(tempgd);
+ }
+
+ var color = (fb.color !== null) ? fb.color : this.series[sid1].fillColor;
+ var baseSeries = (fb.baseSeries !== null) ? fb.baseSeries : id1;
+
+ // now apply a fill to the shape on the lower series shadow canvas,
+ // so it is behind both series.
+ var sr = this.series[baseSeries].renderer.shapeRenderer;
+ var opts = {fillStyle: color, fill: true, closePath: true};
+ sr.draw(series1.shadowCanvas._ctx, gd, opts);
+ };
+
+ this.bindCustomEvents = function() {
+ this.eventCanvas._elem.bind('click', {plot:this}, this.onClick);
+ this.eventCanvas._elem.bind('dblclick', {plot:this}, this.onDblClick);
+ this.eventCanvas._elem.bind('mousedown', {plot:this}, this.onMouseDown);
+ this.eventCanvas._elem.bind('mousemove', {plot:this}, this.onMouseMove);
+ this.eventCanvas._elem.bind('mouseenter', {plot:this}, this.onMouseEnter);
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, this.onMouseLeave);
+ if (this.captureRightClick) {
+ this.eventCanvas._elem.bind('mouseup', {plot:this}, this.onRightClick);
+ this.eventCanvas._elem.get(0).oncontextmenu = function() {
+ return false;
+ };
+ }
+ else {
+ this.eventCanvas._elem.bind('mouseup', {plot:this}, this.onMouseUp);
+ }
+ };
+
+ function getEventPosition(ev) {
+ var plot = ev.data.plot;
+ var go = plot.eventCanvas._elem.offset();
+ var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top};
+ var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null, yMidAxis:null};
+ var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis', 'yMidAxis'];
+ var ax = plot.axes;
+ var n, axis;
+ for (n=11; n>0; n--) {
+ axis = an[n-1];
+ if (ax[axis].show) {
+ dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]);
+ }
+ }
+
+ return {offsets:go, gridPos:gridPos, dataPos:dataPos};
+ }
+
+
+ // function to check if event location is over a area area
+ function checkIntersection(gridpos, plot) {
+ var series = plot.series;
+ var i, j, k, s, r, x, y, theta, sm, sa, minang, maxang;
+ var d0, d, p, pp, points, bw, hp;
+ var threshold, t;
+ for (k=plot.seriesStack.length-1; k>=0; k--) {
+ i = plot.seriesStack[k];
+ s = series[i];
+ hp = s._highlightThreshold;
+ switch (s.renderer.constructor) {
+ case $.jqplot.BarRenderer:
+ x = gridpos.x;
+ y = gridpos.y;
+ for (j=0; j<s._barPoints.length; j++) {
+ points = s._barPoints[j];
+ p = s.gridData[j];
+ if (x>points[0][0] && x<points[2][0] && y>points[2][1] && y<points[0][1]) {
+ return {seriesIndex:s.index, pointIndex:j, gridData:p, data:s.data[j], points:s._barPoints[j]};
+ }
+ }
+ break;
+ case $.jqplot.PyramidRenderer:
+ x = gridpos.x;
+ y = gridpos.y;
+ for (j=0; j<s._barPoints.length; j++) {
+ points = s._barPoints[j];
+ p = s.gridData[j];
+ if (x > points[0][0] + hp[0][0] && x < points[2][0] + hp[2][0] && y > points[2][1] && y < points[0][1]) {
+ return {seriesIndex:s.index, pointIndex:j, gridData:p, data:s.data[j], points:s._barPoints[j]};
+ }
+ }
+ break;
+
+ case $.jqplot.DonutRenderer:
+ sa = s.startAngle/180*Math.PI;
+ x = gridpos.x - s._center[0];
+ y = gridpos.y - s._center[1];
+ r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
+ if (x > 0 && -y >= 0) {
+ theta = 2*Math.PI - Math.atan(-y/x);
+ }
+ else if (x > 0 && -y < 0) {
+ theta = -Math.atan(-y/x);
+ }
+ else if (x < 0) {
+ theta = Math.PI - Math.atan(-y/x);
+ }
+ else if (x == 0 && -y > 0) {
+ theta = 3*Math.PI/2;
+ }
+ else if (x == 0 && -y < 0) {
+ theta = Math.PI/2;
+ }
+ else if (x == 0 && y == 0) {
+ theta = 0;
+ }
+ if (sa) {
+ theta -= sa;
+ if (theta < 0) {
+ theta += 2*Math.PI;
+ }
+ else if (theta > 2*Math.PI) {
+ theta -= 2*Math.PI;
+ }
+ }
+
+ sm = s.sliceMargin/180*Math.PI;
+ if (r < s._radius && r > s._innerRadius) {
+ for (j=0; j<s.gridData.length; j++) {
+ minang = (j>0) ? s.gridData[j-1][1]+sm : sm;
+ maxang = s.gridData[j][1];
+ if (theta > minang && theta < maxang) {
+ return {seriesIndex:s.index, pointIndex:j, gridData:s.gridData[j], data:s.data[j]};
+ }
+ }
+ }
+ break;
+
+ case $.jqplot.PieRenderer:
+ sa = s.startAngle/180*Math.PI;
+ x = gridpos.x - s._center[0];
+ y = gridpos.y - s._center[1];
+ r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
+ if (x > 0 && -y >= 0) {
+ theta = 2*Math.PI - Math.atan(-y/x);
+ }
+ else if (x > 0 && -y < 0) {
+ theta = -Math.atan(-y/x);
+ }
+ else if (x < 0) {
+ theta = Math.PI - Math.atan(-y/x);
+ }
+ else if (x == 0 && -y > 0) {
+ theta = 3*Math.PI/2;
+ }
+ else if (x == 0 && -y < 0) {
+ theta = Math.PI/2;
+ }
+ else if (x == 0 && y == 0) {
+ theta = 0;
+ }
+ if (sa) {
+ theta -= sa;
+ if (theta < 0) {
+ theta += 2*Math.PI;
+ }
+ else if (theta > 2*Math.PI) {
+ theta -= 2*Math.PI;
+ }
+ }
+
+ sm = s.sliceMargin/180*Math.PI;
+ if (r < s._radius) {
+ for (j=0; j<s.gridData.length; j++) {
+ minang = (j>0) ? s.gridData[j-1][1]+sm : sm;
+ maxang = s.gridData[j][1];
+ if (theta > minang && theta < maxang) {
+ return {seriesIndex:s.index, pointIndex:j, gridData:s.gridData[j], data:s.data[j]};
+ }
+ }
+ }
+ break;
+
+ case $.jqplot.BubbleRenderer:
+ x = gridpos.x;
+ y = gridpos.y;
+ var ret = null;
+
+ if (s.show) {
+ for (var j=0; j<s.gridData.length; j++) {
+ p = s.gridData[j];
+ d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) );
+ if (d <= p[2] && (d <= d0 || d0 == null)) {
+ d0 = d;
+ ret = {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ if (ret != null) {
+ return ret;
+ }
+ }
+ break;
+
+ case $.jqplot.FunnelRenderer:
+ x = gridpos.x;
+ y = gridpos.y;
+ var v = s._vertices,
+ vfirst = v[0],
+ vlast = v[v.length-1],
+ lex,
+ rex,
+ cv;
+
+ // equations of right and left sides, returns x, y values given height of section (y value and 2 points)
+
+ function findedge (l, p1 , p2) {
+ var m = (p1[1] - p2[1])/(p1[0] - p2[0]);
+ var b = p1[1] - m*p1[0];
+ var y = l + p1[1];
+
+ return [(y - b)/m, y];
+ }
+
+ // check each section
+ lex = findedge(y, vfirst[0], vlast[3]);
+ rex = findedge(y, vfirst[1], vlast[2]);
+ for (j=0; j<v.length; j++) {
+ cv = v[j];
+ if (y >= cv[0][1] && y <= cv[3][1] && x >= lex[0] && x <= rex[0]) {
+ return {seriesIndex:s.index, pointIndex:j, gridData:null, data:s.data[j]};
+ }
+ }
+ break;
+
+ case $.jqplot.LineRenderer:
+ x = gridpos.x;
+ y = gridpos.y;
+ r = s.renderer;
+ if (s.show) {
+ if ((s.fill || (s.renderer.bands.show && s.renderer.bands.fill)) && (!plot.plugins.highlighter || !plot.plugins.highlighter.show)) {
+ // first check if it is in bounding box
+ var inside = false;
+ if (x>s._boundingBox[0][0] && x<s._boundingBox[1][0] && y>s._boundingBox[1][1] && y<s._boundingBox[0][1]) {
+ // now check the crossing number
+
+ var numPoints = s._areaPoints.length;
+ var ii;
+ var j = numPoints-1;
+
+ for(var ii=0; ii < numPoints; ii++) {
+ var vertex1 = [s._areaPoints[ii][0], s._areaPoints[ii][1]];
+ var vertex2 = [s._areaPoints[j][0], s._areaPoints[j][1]];
+
+ if (vertex1[1] < y && vertex2[1] >= y || vertex2[1] < y && vertex1[1] >= y) {
+ if (vertex1[0] + (y - vertex1[1]) / (vertex2[1] - vertex1[1]) * (vertex2[0] - vertex1[0]) < x) {
+ inside = !inside;
+ }
+ }
+
+ j = ii;
+ }
+ }
+ if (inside) {
+ return {seriesIndex:i, pointIndex:null, gridData:s.gridData, data:s.data, points:s._areaPoints};
+ }
+ break;
+
+ }
+
+ else {
+ t = s.markerRenderer.size/2+s.neighborThreshold;
+ threshold = (t > 0) ? t : 0;
+ for (var j=0; j<s.gridData.length; j++) {
+ p = s.gridData[j];
+ // neighbor looks different to OHLC chart.
+ if (r.constructor == $.jqplot.OHLCRenderer) {
+ if (r.candleStick) {
+ var yp = s._yaxis.series_u2p;
+ if (x >= p[0]-r._bodyWidth/2 && x <= p[0]+r._bodyWidth/2 && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) {
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ // if an open hi low close chart
+ else if (!r.hlc){
+ var yp = s._yaxis.series_u2p;
+ if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) {
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ // a hi low close chart
+ else {
+ var yp = s._yaxis.series_u2p;
+ if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][1]) && y <= yp(s.data[j][2])) {
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+
+ }
+ else if (p[0] != null && p[1] != null){
+ d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) );
+ if (d <= threshold && (d <= d0 || d0 == null)) {
+ d0 = d;
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ x = gridpos.x;
+ y = gridpos.y;
+ r = s.renderer;
+ if (s.show) {
+ t = s.markerRenderer.size/2+s.neighborThreshold;
+ threshold = (t > 0) ? t : 0;
+ for (var j=0; j<s.gridData.length; j++) {
+ p = s.gridData[j];
+ // neighbor looks different to OHLC chart.
+ if (r.constructor == $.jqplot.OHLCRenderer) {
+ if (r.candleStick) {
+ var yp = s._yaxis.series_u2p;
+ if (x >= p[0]-r._bodyWidth/2 && x <= p[0]+r._bodyWidth/2 && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) {
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ // if an open hi low close chart
+ else if (!r.hlc){
+ var yp = s._yaxis.series_u2p;
+ if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) {
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ // a hi low close chart
+ else {
+ var yp = s._yaxis.series_u2p;
+ if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][1]) && y <= yp(s.data[j][2])) {
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+
+ }
+ else {
+ d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) );
+ if (d <= threshold && (d <= d0 || d0 == null)) {
+ d0 = d;
+ return {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ return null;
+ }
+
+
+
+ this.onClick = function(ev) {
+ // Event passed in is normalized and will have data attribute.
+ // Event passed out is unnormalized.
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var neighbor = checkIntersection(positions.gridPos, p);
+ var evt = $.Event('jqplotClick');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
+ };
+
+ this.onDblClick = function(ev) {
+ // Event passed in is normalized and will have data attribute.
+ // Event passed out is unnormalized.
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var neighbor = checkIntersection(positions.gridPos, p);
+ var evt = $.Event('jqplotDblClick');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
+ };
+
+ this.onMouseDown = function(ev) {
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var neighbor = checkIntersection(positions.gridPos, p);
+ var evt = $.Event('jqplotMouseDown');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
+ };
+
+ this.onMouseUp = function(ev) {
+ var positions = getEventPosition(ev);
+ var evt = $.Event('jqplotMouseUp');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, ev.data.plot]);
+ };
+
+ this.onRightClick = function(ev) {
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var neighbor = checkIntersection(positions.gridPos, p);
+ if (p.captureRightClick) {
+ if (ev.which == 3) {
+ var evt = $.Event('jqplotRightClick');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
+ }
+ else {
+ var evt = $.Event('jqplotMouseUp');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
+ }
+ }
+ };
+
+ this.onMouseMove = function(ev) {
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var neighbor = checkIntersection(positions.gridPos, p);
+ var evt = $.Event('jqplotMouseMove');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, neighbor, p]);
+ };
+
+ this.onMouseEnter = function(ev) {
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var evt = $.Event('jqplotMouseEnter');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ evt.relatedTarget = ev.relatedTarget;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, p]);
+ };
+
+ this.onMouseLeave = function(ev) {
+ var positions = getEventPosition(ev);
+ var p = ev.data.plot;
+ var evt = $.Event('jqplotMouseLeave');
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ evt.relatedTarget = ev.relatedTarget;
+ $(this).trigger(evt, [positions.gridPos, positions.dataPos, null, p]);
+ };
+
+ // method: drawSeries
+ // Redraws all or just one series on the plot. No axis scaling
+ // is performed and no other elements on the plot are redrawn.
+ // options is an options object to pass on to the series renderers.
+ // It can be an empty object {}. idx is the series index
+ // to redraw if only one series is to be redrawn.
+ this.drawSeries = function(options, idx){
+ var i, series, ctx;
+ // if only one argument passed in and it is a number, use it ad idx.
+ idx = (typeof(options) === "number" && idx == null) ? options : idx;
+ options = (typeof(options) === "object") ? options : {};
+ // draw specified series
+ if (idx != undefined) {
+ series = this.series[idx];
+ ctx = series.shadowCanvas._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ series.drawShadow(ctx, options, this);
+ ctx = series.canvas._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ series.draw(ctx, options, this);
+ if (series.renderer.constructor == $.jqplot.BezierCurveRenderer) {
+ if (idx < this.series.length - 1) {
+ this.drawSeries(idx+1);
+ }
+ }
+ }
+
+ else {
+ // if call series drawShadow method first, in case all series shadows
+ // should be drawn before any series. This will ensure, like for
+ // stacked bar plots, that shadows don't overlap series.
+ for (i=0; i<this.series.length; i++) {
+ // first clear the canvas
+ series = this.series[i];
+ ctx = series.shadowCanvas._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ series.drawShadow(ctx, options, this);
+ ctx = series.canvas._ctx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ series.draw(ctx, options, this);
+ }
+ }
+ options = idx = i = series = ctx = null;
+ };
+
+ // method: moveSeriesToFront
+ // This method requires jQuery 1.4+
+ // Moves the specified series canvas in front of all other series canvases.
+ // This effectively "draws" the specified series on top of all other series,
+ // although it is performed through DOM manipulation, no redrawing is performed.
+ //
+ // Parameters:
+ // idx - 0 based index of the series to move. This will be the index of the series
+ // as it was first passed into the jqplot function.
+ this.moveSeriesToFront = function (idx) {
+ idx = parseInt(idx, 10);
+ var stackIndex = $.inArray(idx, this.seriesStack);
+ // if already in front, return
+ if (stackIndex == -1) {
+ return;
+ }
+ if (stackIndex == this.seriesStack.length -1) {
+ this.previousSeriesStack = this.seriesStack.slice(0);
+ return;
+ }
+ var opidx = this.seriesStack[this.seriesStack.length -1];
+ var serelem = this.series[idx].canvas._elem.detach();
+ var shadelem = this.series[idx].shadowCanvas._elem.detach();
+ this.series[opidx].shadowCanvas._elem.after(shadelem);
+ this.series[opidx].canvas._elem.after(serelem);
+ this.previousSeriesStack = this.seriesStack.slice(0);
+ this.seriesStack.splice(stackIndex, 1);
+ this.seriesStack.push(idx);
+ };
+
+ // method: moveSeriesToBack
+ // This method requires jQuery 1.4+
+ // Moves the specified series canvas behind all other series canvases.
+ //
+ // Parameters:
+ // idx - 0 based index of the series to move. This will be the index of the series
+ // as it was first passed into the jqplot function.
+ this.moveSeriesToBack = function (idx) {
+ idx = parseInt(idx, 10);
+ var stackIndex = $.inArray(idx, this.seriesStack);
+ // if already in back, return
+ if (stackIndex == 0 || stackIndex == -1) {
+ return;
+ }
+ var opidx = this.seriesStack[0];
+ var serelem = this.series[idx].canvas._elem.detach();
+ var shadelem = this.series[idx].shadowCanvas._elem.detach();
+ this.series[opidx].shadowCanvas._elem.before(shadelem);
+ this.series[opidx].canvas._elem.before(serelem);
+ this.previousSeriesStack = this.seriesStack.slice(0);
+ this.seriesStack.splice(stackIndex, 1);
+ this.seriesStack.unshift(idx);
+ };
+
+ // method: restorePreviousSeriesOrder
+ // This method requires jQuery 1.4+
+ // Restore the series canvas order to its previous state.
+ // Useful to put a series back where it belongs after moving
+ // it to the front.
+ this.restorePreviousSeriesOrder = function () {
+ var i, j, serelem, shadelem, temp, move, keep;
+ // if no change, return.
+ if (this.seriesStack == this.previousSeriesStack) {
+ return;
+ }
+ for (i=1; i<this.previousSeriesStack.length; i++) {
+ move = this.previousSeriesStack[i];
+ keep = this.previousSeriesStack[i-1];
+ serelem = this.series[move].canvas._elem.detach();
+ shadelem = this.series[move].shadowCanvas._elem.detach();
+ this.series[keep].shadowCanvas._elem.after(shadelem);
+ this.series[keep].canvas._elem.after(serelem);
+ }
+ temp = this.seriesStack.slice(0);
+ this.seriesStack = this.previousSeriesStack.slice(0);
+ this.previousSeriesStack = temp;
+ };
+
+ // method: restoreOriginalSeriesOrder
+ // This method requires jQuery 1.4+
+ // Restore the series canvas order to its original order
+ // when the plot was created.
+ this.restoreOriginalSeriesOrder = function () {
+ var i, j, arr=[], serelem, shadelem;
+ for (i=0; i<this.series.length; i++) {
+ arr.push(i);
+ }
+ if (this.seriesStack == arr) {
+ return;
+ }
+ this.previousSeriesStack = this.seriesStack.slice(0);
+ this.seriesStack = arr;
+ for (i=1; i<this.seriesStack.length; i++) {
+ serelem = this.series[i].canvas._elem.detach();
+ shadelem = this.series[i].shadowCanvas._elem.detach();
+ this.series[i-1].shadowCanvas._elem.after(shadelem);
+ this.series[i-1].canvas._elem.after(serelem);
+ }
+ };
+
+ this.activateTheme = function (name) {
+ this.themeEngine.activate(this, name);
+ };
+ }
+
+
+ // conpute a highlight color or array of highlight colors from given colors.
+ $.jqplot.computeHighlightColors = function(colors) {
+ var ret;
+ if ($.isArray(colors)) {
+ ret = [];
+ for (var i=0; i<colors.length; i++){
+ var rgba = $.jqplot.getColorComponents(colors[i]);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ newrgb[j] = (sum > 660) ? newrgb[j] * 0.85 : 0.73 * newrgb[j] + 90;
+ newrgb[j] = parseInt(newrgb[j], 10);
+ (newrgb[j] > 255) ? 255 : newrgb[j];
+ }
+ // newrgb[3] = (rgba[3] > 0.4) ? rgba[3] * 0.4 : rgba[3] * 1.5;
+ // newrgb[3] = (rgba[3] > 0.5) ? 0.8 * rgba[3] - .1 : rgba[3] + 0.2;
+ newrgb[3] = 0.3 + 0.35 * rgba[3];
+ ret.push('rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+newrgb[3]+')');
+ }
+ }
+ else {
+ var rgba = $.jqplot.getColorComponents(colors);
+ var newrgb = [rgba[0], rgba[1], rgba[2]];
+ var sum = newrgb[0] + newrgb[1] + newrgb[2];
+ for (var j=0; j<3; j++) {
+ // when darkening, lowest color component can be is 60.
+ // newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]);
+ // newrgb[j] = parseInt(newrgb[j], 10);
+ newrgb[j] = (sum > 660) ? newrgb[j] * 0.85 : 0.73 * newrgb[j] + 90;
+ newrgb[j] = parseInt(newrgb[j], 10);
+ (newrgb[j] > 255) ? 255 : newrgb[j];
+ }
+ // newrgb[3] = (rgba[3] > 0.4) ? rgba[3] * 0.4 : rgba[3] * 1.5;
+ // newrgb[3] = (rgba[3] > 0.5) ? 0.8 * rgba[3] - .1 : rgba[3] + 0.2;
+ newrgb[3] = 0.3 + 0.35 * rgba[3];
+ ret = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+newrgb[3]+')';
+ }
+ return ret;
+ };
+
+ $.jqplot.ColorGenerator = function(colors) {
+ colors = colors || $.jqplot.config.defaultColors;
+ var idx = 0;
+
+ this.next = function () {
+ if (idx < colors.length) {
+ return colors[idx++];
+ }
+ else {
+ idx = 0;
+ return colors[idx++];
+ }
+ };
+
+ this.previous = function () {
+ if (idx > 0) {
+ return colors[idx--];
+ }
+ else {
+ idx = colors.length-1;
+ return colors[idx];
+ }
+ };
+
+ // get a color by index without advancing pointer.
+ this.get = function(i) {
+ var idx = i - colors.length * Math.floor(i/colors.length);
+ return colors[idx];
+ };
+
+ this.setColors = function(c) {
+ colors = c;
+ };
+
+ this.reset = function() {
+ idx = 0;
+ };
+
+ this.getIndex = function() {
+ return idx;
+ };
+
+ this.setIndex = function(index) {
+ idx = index;
+ };
+ };
+
+ // convert a hex color string to rgb string.
+ // h - 3 or 6 character hex string, with or without leading #
+ // a - optional alpha
+ $.jqplot.hex2rgb = function(h, a) {
+ h = h.replace('#', '');
+ if (h.length == 3) {
+ h = h.charAt(0)+h.charAt(0)+h.charAt(1)+h.charAt(1)+h.charAt(2)+h.charAt(2);
+ }
+ var rgb;
+ rgb = 'rgba('+parseInt(h.slice(0,2), 16)+', '+parseInt(h.slice(2,4), 16)+', '+parseInt(h.slice(4,6), 16);
+ if (a) {
+ rgb += ', '+a;
+ }
+ rgb += ')';
+ return rgb;
+ };
+
+ // convert an rgb color spec to a hex spec. ignore any alpha specification.
+ $.jqplot.rgb2hex = function(s) {
+ var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *(?:, *[0-9.]*)?\)/;
+ var m = s.match(pat);
+ var h = '#';
+ for (var i=1; i<4; i++) {
+ var temp;
+ if (m[i].search(/%/) != -1) {
+ temp = parseInt(255*m[i]/100, 10).toString(16);
+ if (temp.length == 1) {
+ temp = '0'+temp;
+ }
+ }
+ else {
+ temp = parseInt(m[i], 10).toString(16);
+ if (temp.length == 1) {
+ temp = '0'+temp;
+ }
+ }
+ h += temp;
+ }
+ return h;
+ };
+
+ // given a css color spec, return an rgb css color spec
+ $.jqplot.normalize2rgb = function(s, a) {
+ if (s.search(/^ *rgba?\(/) != -1) {
+ return s;
+ }
+ else if (s.search(/^ *#?[0-9a-fA-F]?[0-9a-fA-F]/) != -1) {
+ return $.jqplot.hex2rgb(s, a);
+ }
+ else {
+ throw 'invalid color spec';
+ }
+ };
+
+ // extract the r, g, b, a color components out of a css color spec.
+ $.jqplot.getColorComponents = function(s) {
+ // check to see if a color keyword.
+ s = $.jqplot.colorKeywordMap[s] || s;
+ var rgb = $.jqplot.normalize2rgb(s);
+ var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *,? *([0-9.]* *)?\)/;
+ var m = rgb.match(pat);
+ var ret = [];
+ for (var i=1; i<4; i++) {
+ if (m[i].search(/%/) != -1) {
+ ret[i-1] = parseInt(255*m[i]/100, 10);
+ }
+ else {
+ ret[i-1] = parseInt(m[i], 10);
+ }
+ }
+ ret[3] = parseFloat(m[4]) ? parseFloat(m[4]) : 1.0;
+ return ret;
+ };
+
+ $.jqplot.colorKeywordMap = {
+ aliceblue: 'rgb(240, 248, 255)',
+ antiquewhite: 'rgb(250, 235, 215)',
+ aqua: 'rgb( 0, 255, 255)',
+ aquamarine: 'rgb(127, 255, 212)',
+ azure: 'rgb(240, 255, 255)',
+ beige: 'rgb(245, 245, 220)',
+ bisque: 'rgb(255, 228, 196)',
+ black: 'rgb( 0, 0, 0)',
+ blanchedalmond: 'rgb(255, 235, 205)',
+ blue: 'rgb( 0, 0, 255)',
+ blueviolet: 'rgb(138, 43, 226)',
+ brown: 'rgb(165, 42, 42)',
+ burlywood: 'rgb(222, 184, 135)',
+ cadetblue: 'rgb( 95, 158, 160)',
+ chartreuse: 'rgb(127, 255, 0)',
+ chocolate: 'rgb(210, 105, 30)',
+ coral: 'rgb(255, 127, 80)',
+ cornflowerblue: 'rgb(100, 149, 237)',
+ cornsilk: 'rgb(255, 248, 220)',
+ crimson: 'rgb(220, 20, 60)',
+ cyan: 'rgb( 0, 255, 255)',
+ darkblue: 'rgb( 0, 0, 139)',
+ darkcyan: 'rgb( 0, 139, 139)',
+ darkgoldenrod: 'rgb(184, 134, 11)',
+ darkgray: 'rgb(169, 169, 169)',
+ darkgreen: 'rgb( 0, 100, 0)',
+ darkgrey: 'rgb(169, 169, 169)',
+ darkkhaki: 'rgb(189, 183, 107)',
+ darkmagenta: 'rgb(139, 0, 139)',
+ darkolivegreen: 'rgb( 85, 107, 47)',
+ darkorange: 'rgb(255, 140, 0)',
+ darkorchid: 'rgb(153, 50, 204)',
+ darkred: 'rgb(139, 0, 0)',
+ darksalmon: 'rgb(233, 150, 122)',
+ darkseagreen: 'rgb(143, 188, 143)',
+ darkslateblue: 'rgb( 72, 61, 139)',
+ darkslategray: 'rgb( 47, 79, 79)',
+ darkslategrey: 'rgb( 47, 79, 79)',
+ darkturquoise: 'rgb( 0, 206, 209)',
+ darkviolet: 'rgb(148, 0, 211)',
+ deeppink: 'rgb(255, 20, 147)',
+ deepskyblue: 'rgb( 0, 191, 255)',
+ dimgray: 'rgb(105, 105, 105)',
+ dimgrey: 'rgb(105, 105, 105)',
+ dodgerblue: 'rgb( 30, 144, 255)',
+ firebrick: 'rgb(178, 34, 34)',
+ floralwhite: 'rgb(255, 250, 240)',
+ forestgreen: 'rgb( 34, 139, 34)',
+ fuchsia: 'rgb(255, 0, 255)',
+ gainsboro: 'rgb(220, 220, 220)',
+ ghostwhite: 'rgb(248, 248, 255)',
+ gold: 'rgb(255, 215, 0)',
+ goldenrod: 'rgb(218, 165, 32)',
+ gray: 'rgb(128, 128, 128)',
+ grey: 'rgb(128, 128, 128)',
+ green: 'rgb( 0, 128, 0)',
+ greenyellow: 'rgb(173, 255, 47)',
+ honeydew: 'rgb(240, 255, 240)',
+ hotpink: 'rgb(255, 105, 180)',
+ indianred: 'rgb(205, 92, 92)',
+ indigo: 'rgb( 75, 0, 130)',
+ ivory: 'rgb(255, 255, 240)',
+ khaki: 'rgb(240, 230, 140)',
+ lavender: 'rgb(230, 230, 250)',
+ lavenderblush: 'rgb(255, 240, 245)',
+ lawngreen: 'rgb(124, 252, 0)',
+ lemonchiffon: 'rgb(255, 250, 205)',
+ lightblue: 'rgb(173, 216, 230)',
+ lightcoral: 'rgb(240, 128, 128)',
+ lightcyan: 'rgb(224, 255, 255)',
+ lightgoldenrodyellow: 'rgb(250, 250, 210)',
+ lightgray: 'rgb(211, 211, 211)',
+ lightgreen: 'rgb(144, 238, 144)',
+ lightgrey: 'rgb(211, 211, 211)',
+ lightpink: 'rgb(255, 182, 193)',
+ lightsalmon: 'rgb(255, 160, 122)',
+ lightseagreen: 'rgb( 32, 178, 170)',
+ lightskyblue: 'rgb(135, 206, 250)',
+ lightslategray: 'rgb(119, 136, 153)',
+ lightslategrey: 'rgb(119, 136, 153)',
+ lightsteelblue: 'rgb(176, 196, 222)',
+ lightyellow: 'rgb(255, 255, 224)',
+ lime: 'rgb( 0, 255, 0)',
+ limegreen: 'rgb( 50, 205, 50)',
+ linen: 'rgb(250, 240, 230)',
+ magenta: 'rgb(255, 0, 255)',
+ maroon: 'rgb(128, 0, 0)',
+ mediumaquamarine: 'rgb(102, 205, 170)',
+ mediumblue: 'rgb( 0, 0, 205)',
+ mediumorchid: 'rgb(186, 85, 211)',
+ mediumpurple: 'rgb(147, 112, 219)',
+ mediumseagreen: 'rgb( 60, 179, 113)',
+ mediumslateblue: 'rgb(123, 104, 238)',
+ mediumspringgreen: 'rgb( 0, 250, 154)',
+ mediumturquoise: 'rgb( 72, 209, 204)',
+ mediumvioletred: 'rgb(199, 21, 133)',
+ midnightblue: 'rgb( 25, 25, 112)',
+ mintcream: 'rgb(245, 255, 250)',
+ mistyrose: 'rgb(255, 228, 225)',
+ moccasin: 'rgb(255, 228, 181)',
+ navajowhite: 'rgb(255, 222, 173)',
+ navy: 'rgb( 0, 0, 128)',
+ oldlace: 'rgb(253, 245, 230)',
+ olive: 'rgb(128, 128, 0)',
+ olivedrab: 'rgb(107, 142, 35)',
+ orange: 'rgb(255, 165, 0)',
+ orangered: 'rgb(255, 69, 0)',
+ orchid: 'rgb(218, 112, 214)',
+ palegoldenrod: 'rgb(238, 232, 170)',
+ palegreen: 'rgb(152, 251, 152)',
+ paleturquoise: 'rgb(175, 238, 238)',
+ palevioletred: 'rgb(219, 112, 147)',
+ papayawhip: 'rgb(255, 239, 213)',
+ peachpuff: 'rgb(255, 218, 185)',
+ peru: 'rgb(205, 133, 63)',
+ pink: 'rgb(255, 192, 203)',
+ plum: 'rgb(221, 160, 221)',
+ powderblue: 'rgb(176, 224, 230)',
+ purple: 'rgb(128, 0, 128)',
+ red: 'rgb(255, 0, 0)',
+ rosybrown: 'rgb(188, 143, 143)',
+ royalblue: 'rgb( 65, 105, 225)',
+ saddlebrown: 'rgb(139, 69, 19)',
+ salmon: 'rgb(250, 128, 114)',
+ sandybrown: 'rgb(244, 164, 96)',
+ seagreen: 'rgb( 46, 139, 87)',
+ seashell: 'rgb(255, 245, 238)',
+ sienna: 'rgb(160, 82, 45)',
+ silver: 'rgb(192, 192, 192)',
+ skyblue: 'rgb(135, 206, 235)',
+ slateblue: 'rgb(106, 90, 205)',
+ slategray: 'rgb(112, 128, 144)',
+ slategrey: 'rgb(112, 128, 144)',
+ snow: 'rgb(255, 250, 250)',
+ springgreen: 'rgb( 0, 255, 127)',
+ steelblue: 'rgb( 70, 130, 180)',
+ tan: 'rgb(210, 180, 140)',
+ teal: 'rgb( 0, 128, 128)',
+ thistle: 'rgb(216, 191, 216)',
+ tomato: 'rgb(255, 99, 71)',
+ turquoise: 'rgb( 64, 224, 208)',
+ violet: 'rgb(238, 130, 238)',
+ wheat: 'rgb(245, 222, 179)',
+ white: 'rgb(255, 255, 255)',
+ whitesmoke: 'rgb(245, 245, 245)',
+ yellow: 'rgb(255, 255, 0)',
+ yellowgreen: 'rgb(154, 205, 50)'
+ };
+
+
+
+ // class: $.jqplot.AxisLabelRenderer
+ // Renderer to place labels on the axes.
+ $.jqplot.AxisLabelRenderer = function(options) {
+ // Group: Properties
+ $.jqplot.ElemContainer.call(this);
+ // name of the axis associated with this tick
+ this.axis;
+ // prop: show
+ // wether or not to show the tick (mark and label).
+ this.show = true;
+ // prop: label
+ // The text or html for the label.
+ this.label = '';
+ this.fontFamily = null;
+ this.fontSize = null;
+ this.textColor = null;
+ this._elem;
+ // prop: escapeHTML
+ // true to escape HTML entities in the label.
+ this.escapeHTML = false;
+
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.AxisLabelRenderer.prototype = new $.jqplot.ElemContainer();
+ $.jqplot.AxisLabelRenderer.prototype.constructor = $.jqplot.AxisLabelRenderer;
+
+ $.jqplot.AxisLabelRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.AxisLabelRenderer.prototype.draw = function(ctx, plot) {
+ // Memory Leaks patch
+ if (this._elem) {
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ this._elem = $('<div style="position:absolute;" class="jqplot-'+this.axis+'-label"></div>');
+
+ if (Number(this.label)) {
+ this._elem.css('white-space', 'nowrap');
+ }
+
+ if (!this.escapeHTML) {
+ this._elem.html(this.label);
+ }
+ else {
+ this._elem.text(this.label);
+ }
+ if (this.fontFamily) {
+ this._elem.css('font-family', this.fontFamily);
+ }
+ if (this.fontSize) {
+ this._elem.css('font-size', this.fontSize);
+ }
+ if (this.textColor) {
+ this._elem.css('color', this.textColor);
+ }
+
+ return this._elem;
+ };
+
+ $.jqplot.AxisLabelRenderer.prototype.pack = function() {
+ };
+
+ // class: $.jqplot.AxisTickRenderer
+ // A "tick" object showing the value of a tick/gridline on the plot.
+ $.jqplot.AxisTickRenderer = function(options) {
+ // Group: Properties
+ $.jqplot.ElemContainer.call(this);
+ // prop: mark
+ // tick mark on the axis. One of 'inside', 'outside', 'cross', '' or null.
+ this.mark = 'outside';
+ // name of the axis associated with this tick
+ this.axis;
+ // prop: showMark
+ // wether or not to show the mark on the axis.
+ this.showMark = true;
+ // prop: showGridline
+ // wether or not to draw the gridline on the grid at this tick.
+ this.showGridline = true;
+ // prop: isMinorTick
+ // if this is a minor tick.
+ this.isMinorTick = false;
+ // prop: size
+ // Length of the tick beyond the grid in pixels.
+ // DEPRECATED: This has been superceeded by markSize
+ this.size = 4;
+ // prop: markSize
+ // Length of the tick marks in pixels. For 'cross' style, length
+ // will be stoked above and below axis, so total length will be twice this.
+ this.markSize = 6;
+ // prop: show
+ // wether or not to show the tick (mark and label).
+ // Setting this to false requires more testing. It is recommended
+ // to set showLabel and showMark to false instead.
+ this.show = true;
+ // prop: showLabel
+ // wether or not to show the label.
+ this.showLabel = true;
+ this.label = null;
+ this.value = null;
+ this._styles = {};
+ // prop: formatter
+ // A class of a formatter for the tick text. sprintf by default.
+ this.formatter = $.jqplot.DefaultTickFormatter;
+ // prop: prefix
+ // String to prepend to the tick label.
+ // Prefix is prepended to the formatted tick label.
+ this.prefix = '';
+ // prop: suffix
+ // String to append to the tick label.
+ // Suffix is appended to the formatted tick label.
+ this.suffix = '';
+ // prop: formatString
+ // string passed to the formatter.
+ this.formatString = '';
+ // prop: fontFamily
+ // css spec for the font-family css attribute.
+ this.fontFamily;
+ // prop: fontSize
+ // css spec for the font-size css attribute.
+ this.fontSize;
+ // prop: textColor
+ // css spec for the color attribute.
+ this.textColor;
+ // prop: escapeHTML
+ // true to escape HTML entities in the label.
+ this.escapeHTML = false;
+ this._elem;
+ this._breakTick = false;
+
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.AxisTickRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.AxisTickRenderer.prototype = new $.jqplot.ElemContainer();
+ $.jqplot.AxisTickRenderer.prototype.constructor = $.jqplot.AxisTickRenderer;
+
+ $.jqplot.AxisTickRenderer.prototype.setTick = function(value, axisName, isMinor) {
+ this.value = value;
+ this.axis = axisName;
+ if (isMinor) {
+ this.isMinorTick = true;
+ }
+ return this;
+ };
+
+ $.jqplot.AxisTickRenderer.prototype.draw = function() {
+ if (this.label === null) {
+ this.label = this.prefix + this.formatter(this.formatString, this.value) + this.suffix;
+ }
+ var style = {position: 'absolute'};
+ if (Number(this.label)) {
+ style['whitSpace'] = 'nowrap';
+ }
+
+ // Memory Leaks patch
+ if (this._elem) {
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ this._elem = $(document.createElement('div'));
+ this._elem.addClass("jqplot-"+this.axis+"-tick");
+
+ if (!this.escapeHTML) {
+ this._elem.html(this.label);
+ }
+ else {
+ this._elem.text(this.label);
+ }
+
+ this._elem.css(style);
+
+ for (var s in this._styles) {
+ this._elem.css(s, this._styles[s]);
+ }
+ if (this.fontFamily) {
+ this._elem.css('font-family', this.fontFamily);
+ }
+ if (this.fontSize) {
+ this._elem.css('font-size', this.fontSize);
+ }
+ if (this.textColor) {
+ this._elem.css('color', this.textColor);
+ }
+ if (this._breakTick) {
+ this._elem.addClass('jqplot-breakTick');
+ }
+
+ return this._elem;
+ };
+
+ $.jqplot.DefaultTickFormatter = function (format, val) {
+ if (typeof val == 'number') {
+ if (!format) {
+ format = $.jqplot.config.defaultTickFormatString;
+ }
+ return $.jqplot.sprintf(format, val);
+ }
+ else {
+ return String(val);
+ }
+ };
+
+ $.jqplot.PercentTickFormatter = function (format, val) {
+ if (typeof val == 'number') {
+ val = 100 * val;
+ if (!format) {
+ format = $.jqplot.config.defaultTickFormatString;
+ }
+ return $.jqplot.sprintf(format, val);
+ }
+ else {
+ return String(val);
+ }
+ };
+
+ $.jqplot.AxisTickRenderer.prototype.pack = function() {
+ };
+
+ // Class: $.jqplot.CanvasGridRenderer
+ // The default jqPlot grid renderer, creating a grid on a canvas element.
+ // The renderer has no additional options beyond the <Grid> class.
+ $.jqplot.CanvasGridRenderer = function(){
+ this.shadowRenderer = new $.jqplot.ShadowRenderer();
+ };
+
+ // called with context of Grid object
+ $.jqplot.CanvasGridRenderer.prototype.init = function(options) {
+ this._ctx;
+ $.extend(true, this, options);
+ // set the shadow renderer options
+ var sopts = {lineJoin:'miter', lineCap:'round', fill:false, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.shadowWidth, closePath:false, strokeStyle:this.shadowColor};
+ this.renderer.shadowRenderer.init(sopts);
+ };
+
+ // called with context of Grid.
+ $.jqplot.CanvasGridRenderer.prototype.createElement = function(plot) {
+ var elem;
+ // Memory Leaks patch
+ if (this._elem) {
+ if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
+ elem = this._elem.get(0);
+ window.G_vmlCanvasManager.uninitElement(elem);
+ elem = null;
+ }
+
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ elem = plot.canvasManager.getCanvas();
+
+ var w = this._plotDimensions.width;
+ var h = this._plotDimensions.height;
+ elem.width = w;
+ elem.height = h;
+ this._elem = $(elem);
+ this._elem.addClass('jqplot-grid-canvas');
+ this._elem.css({ position: 'absolute', left: 0, top: 0 });
+
+ elem = plot.canvasManager.initCanvas(elem);
+
+ this._top = this._offsets.top;
+ this._bottom = h - this._offsets.bottom;
+ this._left = this._offsets.left;
+ this._right = w - this._offsets.right;
+ this._width = this._right - this._left;
+ this._height = this._bottom - this._top;
+ // avoid memory leak
+ elem = null;
+ return this._elem;
+ };
+
+ $.jqplot.CanvasGridRenderer.prototype.draw = function() {
+ this._ctx = this._elem.get(0).getContext("2d");
+ var ctx = this._ctx;
+ var axes = this._axes;
+ // Add the grid onto the grid canvas. This is the bottom most layer.
+ ctx.save();
+ ctx.clearRect(0, 0, this._plotDimensions.width, this._plotDimensions.height);
+ ctx.fillStyle = this.backgroundColor || this.background;
+ ctx.fillRect(this._left, this._top, this._width, this._height);
+
+ ctx.save();
+ ctx.lineJoin = 'miter';
+ ctx.lineCap = 'butt';
+ ctx.lineWidth = this.gridLineWidth;
+ ctx.strokeStyle = this.gridLineColor;
+ var b, e, s, m;
+ var ax = ['xaxis', 'yaxis', 'x2axis', 'y2axis'];
+ for (var i=4; i>0; i--) {
+ var name = ax[i-1];
+ var axis = axes[name];
+ var ticks = axis._ticks;
+ var numticks = ticks.length;
+ if (axis.show) {
+ if (axis.drawBaseline) {
+ var bopts = {};
+ if (axis.baselineWidth !== null) {
+ bopts.lineWidth = axis.baselineWidth;
+ }
+ if (axis.baselineColor !== null) {
+ bopts.strokeStyle = axis.baselineColor;
+ }
+ switch (name) {
+ case 'xaxis':
+ drawLine (this._left, this._bottom, this._right, this._bottom, bopts);
+ break;
+ case 'yaxis':
+ drawLine (this._left, this._bottom, this._left, this._top, bopts);
+ break;
+ case 'x2axis':
+ drawLine (this._left, this._bottom, this._right, this._bottom, bopts);
+ break;
+ case 'y2axis':
+ drawLine (this._right, this._bottom, this._right, this._top, bopts);
+ break;
+ }
+ }
+ for (var j=numticks; j>0; j--) {
+ var t = ticks[j-1];
+ if (t.show) {
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (name) {
+ case 'xaxis':
+ // draw the grid line if we should
+ if (t.showGridline && this.drawGridlines && ((!t.isMinorTick && axis.drawMajorGridlines) || (t.isMinorTick && axis.drawMinorGridlines)) ) {
+ drawLine(pos, this._top, pos, this._bottom);
+ }
+ // draw the mark
+ if (t.showMark && t.mark && ((!t.isMinorTick && axis.drawMajorTickMarks) || (t.isMinorTick && axis.drawMinorTickMarks)) ) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._bottom;
+ e = this._bottom+s;
+ break;
+ case 'inside':
+ b = this._bottom-s;
+ e = this._bottom;
+ break;
+ case 'cross':
+ b = this._bottom-s;
+ e = this._bottom+s;
+ break;
+ default:
+ b = this._bottom;
+ e = this._bottom+s;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false});
+ }
+ // draw the line
+ drawLine(pos, b, pos, e);
+ }
+ break;
+ case 'yaxis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && ((!t.isMinorTick && axis.drawMajorGridlines) || (t.isMinorTick && axis.drawMinorGridlines)) ) {
+ drawLine(this._right, pos, this._left, pos);
+ }
+ // draw the mark
+ if (t.showMark && t.mark && ((!t.isMinorTick && axis.drawMajorTickMarks) || (t.isMinorTick && axis.drawMinorTickMarks)) ) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._left-s;
+ e = this._left;
+ break;
+ case 'inside':
+ b = this._left;
+ e = this._left+s;
+ break;
+ case 'cross':
+ b = this._left-s;
+ e = this._left+s;
+ break;
+ default:
+ b = this._left-s;
+ e = this._left;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+ }
+ break;
+ case 'x2axis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && ((!t.isMinorTick && axis.drawMajorGridlines) || (t.isMinorTick && axis.drawMinorGridlines)) ) {
+ drawLine(pos, this._bottom, pos, this._top);
+ }
+ // draw the mark
+ if (t.showMark && t.mark && ((!t.isMinorTick && axis.drawMajorTickMarks) || (t.isMinorTick && axis.drawMinorTickMarks)) ) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._top-s;
+ e = this._top;
+ break;
+ case 'inside':
+ b = this._top;
+ e = this._top+s;
+ break;
+ case 'cross':
+ b = this._top-s;
+ e = this._top+s;
+ break;
+ default:
+ b = this._top-s;
+ e = this._top;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false});
+ }
+ drawLine(pos, b, pos, e);
+ }
+ break;
+ case 'y2axis':
+ // draw the grid line
+ if (t.showGridline && this.drawGridlines && ((!t.isMinorTick && axis.drawMajorGridlines) || (t.isMinorTick && axis.drawMinorGridlines)) ) {
+ drawLine(this._left, pos, this._right, pos);
+ }
+ // draw the mark
+ if (t.showMark && t.mark && ((!t.isMinorTick && axis.drawMajorTickMarks) || (t.isMinorTick && axis.drawMinorTickMarks)) ) {
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ switch (m) {
+ case 'outside':
+ b = this._right;
+ e = this._right+s;
+ break;
+ case 'inside':
+ b = this._right-s;
+ e = this._right;
+ break;
+ case 'cross':
+ b = this._right-s;
+ e = this._right+s;
+ break;
+ default:
+ b = this._right;
+ e = this._right+s;
+ break;
+ }
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ t = null;
+ }
+ axis = null;
+ ticks = null;
+ }
+ // Now draw grid lines for additional y axes
+ //////
+ // TO DO: handle yMidAxis
+ //////
+ ax = ['y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis', 'yMidAxis'];
+ for (var i=7; i>0; i--) {
+ var axis = axes[ax[i-1]];
+ var ticks = axis._ticks;
+ if (axis.show) {
+ var tn = ticks[axis.numberTicks-1];
+ var t0 = ticks[0];
+ var left = axis.getLeft();
+ var points = [[left, tn.getTop() + tn.getHeight()/2], [left, t0.getTop() + t0.getHeight()/2 + 1.0]];
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, points, {lineCap:'butt', fill:false, closePath:false});
+ }
+ // draw the line
+ drawLine(points[0][0], points[0][1], points[1][0], points[1][1], {lineCap:'butt', strokeStyle:axis.borderColor, lineWidth:axis.borderWidth});
+ // draw the tick marks
+ for (var j=ticks.length; j>0; j--) {
+ var t = ticks[j-1];
+ s = t.markSize;
+ m = t.mark;
+ var pos = Math.round(axis.u2p(t.value)) + 0.5;
+ if (t.showMark && t.mark) {
+ switch (m) {
+ case 'outside':
+ b = left;
+ e = left+s;
+ break;
+ case 'inside':
+ b = left-s;
+ e = left;
+ break;
+ case 'cross':
+ b = left-s;
+ e = left+s;
+ break;
+ default:
+ b = left;
+ e = left+s;
+ break;
+ }
+ points = [[b,pos], [e,pos]];
+ // draw the shadow
+ if (this.shadow) {
+ this.renderer.shadowRenderer.draw(ctx, points, {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
+ }
+ // draw the line
+ drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
+ }
+ t = null;
+ }
+ t0 = null;
+ }
+ axis = null;
+ ticks = null;
+ }
+
+ ctx.restore();
+
+ function drawLine(bx, by, ex, ey, opts) {
+ ctx.save();
+ opts = opts || {};
+ if (opts.lineWidth == null || opts.lineWidth != 0){
+ $.extend(true, ctx, opts);
+ ctx.beginPath();
+ ctx.moveTo(bx, by);
+ ctx.lineTo(ex, ey);
+ ctx.stroke();
+ ctx.restore();
+ }
+ }
+
+ if (this.shadow) {
+ var points = [[this._left, this._bottom], [this._right, this._bottom], [this._right, this._top]];
+ this.renderer.shadowRenderer.draw(ctx, points);
+ }
+ // Now draw border around grid. Use axis border definitions. start at
+ // upper left and go clockwise.
+ if (this.borderWidth != 0 && this.drawBorder) {
+ drawLine (this._left, this._top, this._right, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth});
+ drawLine (this._right, this._top, this._right, this._bottom, {lineCap:'round', strokeStyle:axes.y2axis.borderColor, lineWidth:axes.y2axis.borderWidth});
+ drawLine (this._right, this._bottom, this._left, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth});
+ drawLine (this._left, this._bottom, this._left, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth});
+ }
+ // ctx.lineWidth = this.borderWidth;
+ // ctx.strokeStyle = this.borderColor;
+ // ctx.strokeRect(this._left, this._top, this._width, this._height);
+
+ ctx.restore();
+ ctx = null;
+ axes = null;
+ };
+
+ // Class: $.jqplot.DivTitleRenderer
+ // The default title renderer for jqPlot. This class has no options beyond the <Title> class.
+ $.jqplot.DivTitleRenderer = function() {
+ };
+
+ $.jqplot.DivTitleRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.DivTitleRenderer.prototype.draw = function() {
+ // Memory Leaks patch
+ if (this._elem) {
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ var r = this.renderer;
+ var elem = document.createElement('div');
+ this._elem = $(elem);
+ this._elem.addClass('jqplot-title');
+
+ if (!this.text) {
+ this.show = false;
+ this._elem.height(0);
+ this._elem.width(0);
+ }
+ else if (this.text) {
+ var color;
+ if (this.color) {
+ color = this.color;
+ }
+ else if (this.textColor) {
+ color = this.textColor;
+ }
+
+ // don't trust that a stylesheet is present, set the position.
+ var styles = {position:'absolute', top:'0px', left:'0px'};
+
+ if (this._plotWidth) {
+ styles['width'] = this._plotWidth+'px';
+ }
+ if (this.fontSize) {
+ styles['fontSize'] = this.fontSize;
+ }
+ if (typeof this.textAlign === 'string') {
+ styles['textAlign'] = this.textAlign;
+ }
+ else {
+ styles['textAlign'] = 'center';
+ }
+ if (color) {
+ styles['color'] = color;
+ }
+ if (this.paddingBottom) {
+ styles['paddingBottom'] = this.paddingBottom;
+ }
+ if (this.fontFamily) {
+ styles['fontFamily'] = this.fontFamily;
+ }
+
+ this._elem.css(styles);
+ if (this.escapeHtml) {
+ this._elem.text(this.text);
+ }
+ else {
+ this._elem.html(this.text);
+ }
+
+
+ // styletext += (this._plotWidth) ? 'width:'+this._plotWidth+'px;' : '';
+ // styletext += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
+ // styletext += (this.textAlign) ? 'text-align:'+this.textAlign+';' : 'text-align:center;';
+ // styletext += (color) ? 'color:'+color+';' : '';
+ // styletext += (this.paddingBottom) ? 'padding-bottom:'+this.paddingBottom+';' : '';
+ // this._elem = $('<div class="jqplot-title" style="'+styletext+'">'+this.text+'</div>');
+ // if (this.fontFamily) {
+ // this._elem.css('font-family', this.fontFamily);
+ // }
+ }
+
+ elem = null;
+
+ return this._elem;
+ };
+
+ $.jqplot.DivTitleRenderer.prototype.pack = function() {
+ // nothing to do here
+ };
+
+
+ var dotlen = 0.1;
+
+ $.jqplot.LinePattern = function (ctx, pattern) {
+
+ var defaultLinePatterns = {
+ dotted: [ dotlen, $.jqplot.config.dotGapLength ],
+ dashed: [ $.jqplot.config.dashLength, $.jqplot.config.gapLength ],
+ solid: null
+ };
+
+ if (typeof pattern === 'string') {
+ if (pattern[0] === '.' || pattern[0] === '-') {
+ var s = pattern;
+ pattern = [];
+ for (var i=0, imax=s.length; i<imax; i++) {
+ if (s[i] === '.') {
+ pattern.push( dotlen );
+ }
+ else if (s[i] === '-') {
+ pattern.push( $.jqplot.config.dashLength );
+ }
+ else {
+ continue;
+ }
+ pattern.push( $.jqplot.config.gapLength );
+ }
+ }
+ else {
+ pattern = defaultLinePatterns[pattern];
+ }
+ }
+
+ if (!(pattern && pattern.length)) {
+ return ctx;
+ }
+
+ var patternIndex = 0;
+ var patternDistance = pattern[0];
+ var px = 0;
+ var py = 0;
+ var pathx0 = 0;
+ var pathy0 = 0;
+
+ var moveTo = function (x, y) {
+ ctx.moveTo( x, y );
+ px = x;
+ py = y;
+ pathx0 = x;
+ pathy0 = y;
+ };
+
+ var lineTo = function (x, y) {
+ var scale = ctx.lineWidth;
+ var dx = x - px;
+ var dy = y - py;
+ var dist = Math.sqrt(dx*dx+dy*dy);
+ if ((dist > 0) && (scale > 0)) {
+ dx /= dist;
+ dy /= dist;
+ while (true) {
+ var dp = scale * patternDistance;
+ if (dp < dist) {
+ px += dp * dx;
+ py += dp * dy;
+ if ((patternIndex & 1) == 0) {
+ ctx.lineTo( px, py );
+ }
+ else {
+ ctx.moveTo( px, py );
+ }
+ dist -= dp;
+ patternIndex++;
+ if (patternIndex >= pattern.length) {
+ patternIndex = 0;
+ }
+ patternDistance = pattern[patternIndex];
+ }
+ else {
+ px = x;
+ py = y;
+ if ((patternIndex & 1) == 0) {
+ ctx.lineTo( px, py );
+ }
+ else {
+ ctx.moveTo( px, py );
+ }
+ patternDistance -= dist / scale;
+ break;
+ }
+ }
+ }
+ };
+
+ var beginPath = function () {
+ ctx.beginPath();
+ };
+
+ var closePath = function () {
+ lineTo( pathx0, pathy0 );
+ };
+
+ return {
+ moveTo: moveTo,
+ lineTo: lineTo,
+ beginPath: beginPath,
+ closePath: closePath
+ };
+ };
+
+ // Class: $.jqplot.LineRenderer
+ // The default line renderer for jqPlot, this class has no options beyond the <Series> class.
+ // Draws series as a line.
+ $.jqplot.LineRenderer = function(){
+ this.shapeRenderer = new $.jqplot.ShapeRenderer();
+ this.shadowRenderer = new $.jqplot.ShadowRenderer();
+ };
+
+ // called with scope of series.
+ $.jqplot.LineRenderer.prototype.init = function(options, plot) {
+ // Group: Properties
+ //
+ options = options || {};
+ this._type='line';
+ this.renderer.animation = {
+ show: false,
+ direction: 'left',
+ speed: 2500,
+ _supported: true
+ };
+ // prop: smooth
+ // True to draw a smoothed (interpolated) line through the data points
+ // with automatically computed number of smoothing points.
+ // Set to an integer number > 2 to specify number of smoothing points
+ // to use between each data point.
+ this.renderer.smooth = false; // true or a number > 2 for smoothing.
+ this.renderer.tension = null; // null to auto compute or a number typically > 6. Fewer points requires higher tension.
+ // prop: constrainSmoothing
+ // True to use a more accurate smoothing algorithm that will
+ // not overshoot any data points. False to allow overshoot but
+ // produce a smoother looking line.
+ this.renderer.constrainSmoothing = true;
+ // this is smoothed data in grid coordinates, like gridData
+ this.renderer._smoothedData = [];
+ // this is smoothed data in plot units (plot coordinates), like plotData.
+ this.renderer._smoothedPlotData = [];
+ this.renderer._hiBandGridData = [];
+ this.renderer._lowBandGridData = [];
+ this.renderer._hiBandSmoothedData = [];
+ this.renderer._lowBandSmoothedData = [];
+
+ // prop: bandData
+ // Data used to draw error bands or confidence intervals above/below a line.
+ //
+ // bandData can be input in 3 forms. jqPlot will figure out which is the
+ // low band line and which is the high band line for all forms:
+ //
+ // A 2 dimensional array like [[yl1, yl2, ...], [yu1, yu2, ...]] where
+ // [yl1, yl2, ...] are y values of the lower line and
+ // [yu1, yu2, ...] are y values of the upper line.
+ // In this case there must be the same number of y data points as data points
+ // in the series and the bands will inherit the x values of the series.
+ //
+ // A 2 dimensional array like [[[xl1, yl1], [xl2, yl2], ...], [[xh1, yh1], [xh2, yh2], ...]]
+ // where [xl1, yl1] are x,y data points for the lower line and
+ // [xh1, yh1] are x,y data points for the high line.
+ // x values do not have to correspond to the x values of the series and can
+ // be of any arbitrary length.
+ //
+ // Can be of form [[yl1, yu1], [yl2, yu2], [yl3, yu3], ...] where
+ // there must be 3 or more arrays and there must be the same number of arrays
+ // as there are data points in the series. In this case,
+ // [yl1, yu1] specifies the lower and upper y values for the 1st
+ // data point and so on. The bands will inherit the x
+ // values from the series.
+ this.renderer.bandData = [];
+
+ // Group: bands
+ // Banding around line, e.g error bands or confidence intervals.
+ this.renderer.bands = {
+ // prop: show
+ // true to show the bands. If bandData or interval is
+ // supplied, show will be set to true by default.
+ show: false,
+ hiData: [],
+ lowData: [],
+ // prop: color
+ // color of lines at top and bottom of bands [default: series color].
+ color: this.color,
+ // prop: showLines
+ // True to show lines at top and bottom of bands [default: false].
+ showLines: false,
+ // prop: fill
+ // True to fill area between bands [default: true].
+ fill: true,
+ // prop: fillColor
+ // css color spec for filled area. [default: series color].
+ fillColor: null,
+ _min: null,
+ _max: null,
+ // prop: interval
+ // User specified interval above and below line for bands [default: '3%''].
+ // Can be a value like 3 or a string like '3%'
+ // or an upper/lower array like [1, -2] or ['2%', '-1.5%']
+ interval: '3%'
+ };
+
+
+ var lopts = {highlightMouseOver: options.highlightMouseOver, highlightMouseDown: options.highlightMouseDown, highlightColor: options.highlightColor};
+
+ delete (options.highlightMouseOver);
+ delete (options.highlightMouseDown);
+ delete (options.highlightColor);
+
+ $.extend(true, this.renderer, options);
+
+ this.renderer.options = options;
+
+ // if we are given some band data, and bands aren't explicity set to false in options, turn them on.
+ if (this.renderer.bandData.length > 1 && (!options.bands || options.bands.show == null)) {
+ this.renderer.bands.show = true;
+ }
+
+ // if we are given an interval, and bands aren't explicity set to false in options, turn them on.
+ else if (options.bands && options.bands.show == null && options.bands.interval != null) {
+ this.renderer.bands.show = true;
+ }
+
+ // if plot is filled, turn off bands.
+ if (this.fill) {
+ this.renderer.bands.show = false;
+ }
+
+ if (this.renderer.bands.show) {
+ this.renderer.initBands.call(this, this.renderer.options, plot);
+ }
+
+
+ // smoothing is not compatible with stacked lines, disable
+ if (this._stack) {
+ this.renderer.smooth = false;
+ }
+
+ // set the shape renderer options
+ var opts = {lineJoin:this.lineJoin, lineCap:this.lineCap, fill:this.fill, isarc:false, strokeStyle:this.color, fillStyle:this.fillColor, lineWidth:this.lineWidth, linePattern:this.linePattern, closePath:this.fill};
+ this.renderer.shapeRenderer.init(opts);
+
+ var shadow_offset = options.shadowOffset;
+ // set the shadow renderer options
+ if (shadow_offset == null) {
+ // scale the shadowOffset to the width of the line.
+ if (this.lineWidth > 2.5) {
+ shadow_offset = 1.25 * (1 + (Math.atan((this.lineWidth/2.5))/0.785398163 - 1)*0.6);
+ // var shadow_offset = this.shadowOffset;
+ }
+ // for skinny lines, don't make such a big shadow.
+ else {
+ shadow_offset = 1.25 * Math.atan((this.lineWidth/2.5))/0.785398163;
+ }
+ }
+
+ var sopts = {lineJoin:this.lineJoin, lineCap:this.lineCap, fill:this.fill, isarc:false, angle:this.shadowAngle, offset:shadow_offset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.lineWidth, linePattern:this.linePattern, closePath:this.fill};
+ this.renderer.shadowRenderer.init(sopts);
+ this._areaPoints = [];
+ this._boundingBox = [[],[]];
+
+ if (!this.isTrendline && this.fill || this.renderer.bands.show) {
+ // Group: Properties
+ //
+ // prop: highlightMouseOver
+ // True to highlight area on a filled plot when moused over.
+ // This must be false to enable highlightMouseDown to highlight when clicking on an area on a filled plot.
+ this.highlightMouseOver = true;
+ // prop: highlightMouseDown
+ // True to highlight when a mouse button is pressed over an area on a filled plot.
+ // This will be disabled if highlightMouseOver is true.
+ this.highlightMouseDown = false;
+ // prop: highlightColor
+ // color to use when highlighting an area on a filled plot.
+ this.highlightColor = null;
+ // if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver
+ if (lopts.highlightMouseDown && lopts.highlightMouseOver == null) {
+ lopts.highlightMouseOver = false;
+ }
+
+ $.extend(true, this, {highlightMouseOver: lopts.highlightMouseOver, highlightMouseDown: lopts.highlightMouseDown, highlightColor: lopts.highlightColor});
+
+ if (!this.highlightColor) {
+ var fc = (this.renderer.bands.show) ? this.renderer.bands.fillColor : this.fillColor;
+ this.highlightColor = $.jqplot.computeHighlightColors(fc);
+ }
+ // turn off (disable) the highlighter plugin
+ if (this.highlighter) {
+ this.highlighter.show = false;
+ }
+ }
+
+ if (!this.isTrendline && plot) {
+ plot.plugins.lineRenderer = {};
+ plot.postInitHooks.addOnce(postInit);
+ plot.postDrawHooks.addOnce(postPlotDraw);
+ plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove);
+ plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown);
+ plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp);
+ plot.eventListenerHooks.addOnce('jqplotClick', handleClick);
+ plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick);
+ }
+
+ };
+
+ $.jqplot.LineRenderer.prototype.initBands = function(options, plot) {
+ // use bandData if no data specified in bands option
+ //var bd = this.renderer.bandData;
+ var bd = options.bandData || [];
+ var bands = this.renderer.bands;
+ bands.hiData = [];
+ bands.lowData = [];
+ var data = this.data;
+ bands._max = null;
+ bands._min = null;
+ // If 2 arrays, and each array greater than 2 elements, assume it is hi and low data bands of y values.
+ if (bd.length == 2) {
+ // Do we have an array of x,y values?
+ // like [[[1,1], [2,4], [3,3]], [[1,3], [2,6], [3,5]]]
+ if ($.isArray(bd[0][0])) {
+ // since an arbitrary array of points, spin through all of them to determine max and min lines.
+
+ var p;
+ var bdminidx = 0, bdmaxidx = 0;
+ for (var i = 0, l = bd[0].length; i<l; i++) {
+ p = bd[0][i];
+ if ((p[1] != null && p[1] > bands._max) || bands._max == null) {
+ bands._max = p[1];
+ }
+ if ((p[1] != null && p[1] < bands._min) || bands._min == null) {
+ bands._min = p[1];
+ }
+ }
+ for (var i = 0, l = bd[1].length; i<l; i++) {
+ p = bd[1][i];
+ if ((p[1] != null && p[1] > bands._max) || bands._max == null) {
+ bands._max = p[1];
+ bdmaxidx = 1;
+ }
+ if ((p[1] != null && p[1] < bands._min) || bands._min == null) {
+ bands._min = p[1];
+ bdminidx = 1;
+ }
+ }
+
+ if (bdmaxidx === bdminidx) {
+ bands.show = false;
+ }
+
+ bands.hiData = bd[bdmaxidx];
+ bands.lowData = bd[bdminidx];
+ }
+ // else data is arrays of y values
+ // like [[1,4,3], [3,6,5]]
+ // must have same number of band data points as points in series
+ else if (bd[0].length === data.length && bd[1].length === data.length) {
+ var hi = (bd[0][0] > bd[1][0]) ? 0 : 1;
+ var low = (hi) ? 0 : 1;
+ for (var i=0, l=data.length; i < l; i++) {
+ bands.hiData.push([data[i][0], bd[hi][i]]);
+ bands.lowData.push([data[i][0], bd[low][i]]);
+ }
+ }
+
+ // we don't have proper data array, don't show bands.
+ else {
+ bands.show = false;
+ }
+ }
+
+ // if more than 2 arrays, have arrays of [ylow, yhi] values.
+ // note, can't distinguish case of [[ylow, yhi], [ylow, yhi]] from [[ylow, ylow], [yhi, yhi]]
+ // this is assumed to be of the latter form.
+ else if (bd.length > 2 && !$.isArray(bd[0][0])) {
+ var hi = (bd[0][0] > bd[0][1]) ? 0 : 1;
+ var low = (hi) ? 0 : 1;
+ for (var i=0, l=bd.length; i<l; i++) {
+ bands.hiData.push([data[i][0], bd[i][hi]]);
+ bands.lowData.push([data[i][0], bd[i][low]]);
+ }
+ }
+
+ // don't have proper data, auto calculate
+ else {
+ var intrv = bands.interval;
+ var a = null;
+ var b = null;
+ var afunc = null;
+ var bfunc = null;
+
+ if ($.isArray(intrv)) {
+ a = intrv[0];
+ b = intrv[1];
+ }
+ else {
+ a = intrv;
+ }
+
+ if (isNaN(a)) {
+ // we have a string
+ if (a.charAt(a.length - 1) === '%') {
+ afunc = 'multiply';
+ a = parseFloat(a)/100 + 1;
+ }
+ }
+
+ else {
+ a = parseFloat(a);
+ afunc = 'add';
+ }
+
+ if (b !== null && isNaN(b)) {
+ // we have a string
+ if (b.charAt(b.length - 1) === '%') {
+ bfunc = 'multiply';
+ b = parseFloat(b)/100 + 1;
+ }
+ }
+
+ else if (b !== null) {
+ b = parseFloat(b);
+ bfunc = 'add';
+ }
+
+ if (a !== null) {
+ if (b === null) {
+ b = -a;
+ bfunc = afunc;
+ if (bfunc === 'multiply') {
+ b += 2;
+ }
+ }
+
+ // make sure a always applies to hi band.
+ if (a < b) {
+ var temp = a;
+ a = b;
+ b = temp;
+ temp = afunc;
+ afunc = bfunc;
+ bfunc = temp;
+ }
+
+ for (var i=0, l = data.length; i < l; i++) {
+ switch (afunc) {
+ case 'add':
+ bands.hiData.push([data[i][0], data[i][1] + a]);
+ break;
+ case 'multiply':
+ bands.hiData.push([data[i][0], data[i][1] * a]);
+ break;
+ }
+ switch (bfunc) {
+ case 'add':
+ bands.lowData.push([data[i][0], data[i][1] + b]);
+ break;
+ case 'multiply':
+ bands.lowData.push([data[i][0], data[i][1] * b]);
+ break;
+ }
+ }
+ }
+
+ else {
+ bands.show = false;
+ }
+ }
+
+ var hd = bands.hiData;
+ var ld = bands.lowData;
+ for (var i = 0, l = hd.length; i<l; i++) {
+ if ((hd[i][1] != null && hd[i][1] > bands._max) || bands._max == null) {
+ bands._max = hd[i][1];
+ }
+ }
+ for (var i = 0, l = ld.length; i<l; i++) {
+ if ((ld[i][1] != null && ld[i][1] < bands._min) || bands._min == null) {
+ bands._min = ld[i][1];
+ }
+ }
+
+ // one last check for proper data
+ // these don't apply any more since allowing arbitrary x,y values
+ // if (bands.hiData.length != bands.lowData.length) {
+ // bands.show = false;
+ // }
+
+ // if (bands.hiData.length != this.data.length) {
+ // bands.show = false;
+ // }
+
+ if (bands.fillColor === null) {
+ var c = $.jqplot.getColorComponents(bands.color);
+ // now adjust alpha to differentiate fill
+ c[3] = c[3] * 0.5;
+ bands.fillColor = 'rgba(' + c[0] +', '+ c[1] +', '+ c[2] +', '+ c[3] + ')';
+ }
+ };
+
+ function getSteps (d, f) {
+ return (3.4182054+f) * Math.pow(d, -0.3534992);
+ }
+
+ function computeSteps (d1, d2) {
+ var s = Math.sqrt(Math.pow((d2[0]- d1[0]), 2) + Math.pow ((d2[1] - d1[1]), 2));
+ return 5.7648 * Math.log(s) + 7.4456;
+ }
+
+ function tanh (x) {
+ var a = (Math.exp(2*x) - 1) / (Math.exp(2*x) + 1);
+ return a;
+ }
+
+ //////////
+ // computeConstrainedSmoothedData
+ // An implementation of the constrained cubic spline interpolation
+ // method as presented in:
+ //
+ // Kruger, CJC, Constrained Cubic Spine Interpolation for Chemical Engineering Applications
+ // http://www.korf.co.uk/spline.pdf
+ //
+ // The implementation below borrows heavily from the sample Visual Basic
+ // implementation by CJC Kruger found in http://www.korf.co.uk/spline.xls
+ //
+ /////////
+
+ // called with scope of series
+ function computeConstrainedSmoothedData (gd) {
+ var smooth = this.renderer.smooth;
+ var dim = this.canvas.getWidth();
+ var xp = this._xaxis.series_p2u;
+ var yp = this._yaxis.series_p2u;
+ var steps =null;
+ var _steps = null;
+ var dist = gd.length/dim;
+ var _smoothedData = [];
+ var _smoothedPlotData = [];
+
+ if (!isNaN(parseFloat(smooth))) {
+ steps = parseFloat(smooth);
+ }
+ else {
+ steps = getSteps(dist, 0.5);
+ }
+
+ var yy = [];
+ var xx = [];
+
+ for (var i=0, l = gd.length; i<l; i++) {
+ yy.push(gd[i][1]);
+ xx.push(gd[i][0]);
+ }
+
+ function dxx(x1, x0) {
+ if (x1 - x0 == 0) {
+ return Math.pow(10,10);
+ }
+ else {
+ return x1 - x0;
+ }
+ }
+
+ var A, B, C, D;
+ // loop through each line segment. Have # points - 1 line segments. Nmber segments starting at 1.
+ var nmax = gd.length - 1;
+ for (var num = 1, gdl = gd.length; num<gdl; num++) {
+ var gxx = [];
+ var ggxx = [];
+ // point at each end of segment.
+ for (var j = 0; j < 2; j++) {
+ var i = num - 1 + j; // point number, 0 to # points.
+
+ if (i == 0 || i == nmax) {
+ gxx[j] = Math.pow(10, 10);
+ }
+ else if (yy[i+1] - yy[i] == 0 || yy[i] - yy[i-1] == 0) {
+ gxx[j] = 0;
+ }
+ else if (((xx[i+1] - xx[i]) / (yy[i+1] - yy[i]) + (xx[i] - xx[i-1]) / (yy[i] - yy[i-1])) == 0 ) {
+ gxx[j] = 0;
+ }
+ else if ( (yy[i+1] - yy[i]) * (yy[i] - yy[i-1]) < 0 ) {
+ gxx[j] = 0;
+ }
+
+ else {
+ gxx[j] = 2 / (dxx(xx[i + 1], xx[i]) / (yy[i + 1] - yy[i]) + dxx(xx[i], xx[i - 1]) / (yy[i] - yy[i - 1]));
+ }
+ }
+
+ // Reset first derivative (slope) at first and last point
+ if (num == 1) {
+ // First point has 0 2nd derivative
+ gxx[0] = 3 / 2 * (yy[1] - yy[0]) / dxx(xx[1], xx[0]) - gxx[1] / 2;
+ }
+ else if (num == nmax) {
+ // Last point has 0 2nd derivative
+ gxx[1] = 3 / 2 * (yy[nmax] - yy[nmax - 1]) / dxx(xx[nmax], xx[nmax - 1]) - gxx[0] / 2;
+ }
+
+ // Calc second derivative at points
+ ggxx[0] = -2 * (gxx[1] + 2 * gxx[0]) / dxx(xx[num], xx[num - 1]) + 6 * (yy[num] - yy[num - 1]) / Math.pow(dxx(xx[num], xx[num - 1]), 2);
+ ggxx[1] = 2 * (2 * gxx[1] + gxx[0]) / dxx(xx[num], xx[num - 1]) - 6 * (yy[num] - yy[num - 1]) / Math.pow(dxx(xx[num], xx[num - 1]), 2);
+
+ // Calc constants for cubic interpolation
+ D = 1 / 6 * (ggxx[1] - ggxx[0]) / dxx(xx[num], xx[num - 1]);
+ C = 1 / 2 * (xx[num] * ggxx[0] - xx[num - 1] * ggxx[1]) / dxx(xx[num], xx[num - 1]);
+ B = (yy[num] - yy[num - 1] - C * (Math.pow(xx[num], 2) - Math.pow(xx[num - 1], 2)) - D * (Math.pow(xx[num], 3) - Math.pow(xx[num - 1], 3))) / dxx(xx[num], xx[num - 1]);
+ A = yy[num - 1] - B * xx[num - 1] - C * Math.pow(xx[num - 1], 2) - D * Math.pow(xx[num - 1], 3);
+
+ var increment = (xx[num] - xx[num - 1]) / steps;
+ var temp, tempx;
+
+ for (var j = 0, l = steps; j < l; j++) {
+ temp = [];
+ tempx = xx[num - 1] + j * increment;
+ temp.push(tempx);
+ temp.push(A + B * tempx + C * Math.pow(tempx, 2) + D * Math.pow(tempx, 3));
+ _smoothedData.push(temp);
+ _smoothedPlotData.push([xp(temp[0]), yp(temp[1])]);
+ }
+ }
+
+ _smoothedData.push(gd[i]);
+ _smoothedPlotData.push([xp(gd[i][0]), yp(gd[i][1])]);
+
+ return [_smoothedData, _smoothedPlotData];
+ }
+
+ ///////
+ // computeHermiteSmoothedData
+ // A hermite spline smoothing of the plot data.
+ // This implementation is derived from the one posted
+ // by krypin on the jqplot-users mailing list:
+ //
+ // http://groups.google.com/group/jqplot-users/browse_thread/thread/748be6a445723cea?pli=1
+ //
+ // with a blog post:
+ //
+ // http://blog.statscollector.com/a-plugin-renderer-for-jqplot-to-draw-a-hermite-spline/
+ //
+ // and download of the original plugin:
+ //
+ // http://blog.statscollector.com/wp-content/uploads/2010/02/jqplot.hermiteSplineRenderer.js
+ //////////
+
+ // called with scope of series
+ function computeHermiteSmoothedData (gd) {
+ var smooth = this.renderer.smooth;
+ var tension = this.renderer.tension;
+ var dim = this.canvas.getWidth();
+ var xp = this._xaxis.series_p2u;
+ var yp = this._yaxis.series_p2u;
+ var steps =null;
+ var _steps = null;
+ var a = null;
+ var a1 = null;
+ var a2 = null;
+ var slope = null;
+ var slope2 = null;
+ var temp = null;
+ var t, s, h1, h2, h3, h4;
+ var TiX, TiY, Ti1X, Ti1Y;
+ var pX, pY, p;
+ var sd = [];
+ var spd = [];
+ var dist = gd.length/dim;
+ var min, max, stretch, scale, shift;
+ var _smoothedData = [];
+ var _smoothedPlotData = [];
+ if (!isNaN(parseFloat(smooth))) {
+ steps = parseFloat(smooth);
+ }
+ else {
+ steps = getSteps(dist, 0.5);
+ }
+ if (!isNaN(parseFloat(tension))) {
+ tension = parseFloat(tension);
+ }
+
+ for (var i=0, l = gd.length-1; i < l; i++) {
+
+ if (tension === null) {
+ slope = Math.abs((gd[i+1][1] - gd[i][1]) / (gd[i+1][0] - gd[i][0]));
+
+ min = 0.3;
+ max = 0.6;
+ stretch = (max - min)/2.0;
+ scale = 2.5;
+ shift = -1.4;
+
+ temp = slope/scale + shift;
+
+ a1 = stretch * tanh(temp) - stretch * tanh(shift) + min;
+
+ // if have both left and right line segments, will use minimum tension.
+ if (i > 0) {
+ slope2 = Math.abs((gd[i][1] - gd[i-1][1]) / (gd[i][0] - gd[i-1][0]));
+ }
+ temp = slope2/scale + shift;
+
+ a2 = stretch * tanh(temp) - stretch * tanh(shift) + min;
+
+ a = (a1 + a2)/2.0;
+
+ }
+ else {
+ a = tension;
+ }
+ for (t=0; t < steps; t++) {
+ s = t / steps;
+ h1 = (1 + 2*s)*Math.pow((1-s),2);
+ h2 = s*Math.pow((1-s),2);
+ h3 = Math.pow(s,2)*(3-2*s);
+ h4 = Math.pow(s,2)*(s-1);
+
+ if (gd[i-1]) {
+ TiX = a * (gd[i+1][0] - gd[i-1][0]);
+ TiY = a * (gd[i+1][1] - gd[i-1][1]);
+ } else {
+ TiX = a * (gd[i+1][0] - gd[i][0]);
+ TiY = a * (gd[i+1][1] - gd[i][1]);
+ }
+ if (gd[i+2]) {
+ Ti1X = a * (gd[i+2][0] - gd[i][0]);
+ Ti1Y = a * (gd[i+2][1] - gd[i][1]);
+ } else {
+ Ti1X = a * (gd[i+1][0] - gd[i][0]);
+ Ti1Y = a * (gd[i+1][1] - gd[i][1]);
+ }
+
+ pX = h1*gd[i][0] + h3*gd[i+1][0] + h2*TiX + h4*Ti1X;
+ pY = h1*gd[i][1] + h3*gd[i+1][1] + h2*TiY + h4*Ti1Y;
+ p = [pX, pY];
+
+ _smoothedData.push(p);
+ _smoothedPlotData.push([xp(pX), yp(pY)]);
+ }
+ }
+ _smoothedData.push(gd[l]);
+ _smoothedPlotData.push([xp(gd[l][0]), yp(gd[l][1])]);
+
+ return [_smoothedData, _smoothedPlotData];
+ }
+
+ // setGridData
+ // converts the user data values to grid coordinates and stores them
+ // in the gridData array.
+ // Called with scope of a series.
+ $.jqplot.LineRenderer.prototype.setGridData = function(plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var data = this._plotData;
+ var pdata = this._prevPlotData;
+ this.gridData = [];
+ this._prevGridData = [];
+ this.renderer._smoothedData = [];
+ this.renderer._smoothedPlotData = [];
+ this.renderer._hiBandGridData = [];
+ this.renderer._lowBandGridData = [];
+ this.renderer._hiBandSmoothedData = [];
+ this.renderer._lowBandSmoothedData = [];
+ var bands = this.renderer.bands;
+ var hasNull = false;
+ for (var i=0, l=data.length; i < l; i++) {
+ // if not a line series or if no nulls in data, push the converted point onto the array.
+ if (data[i][0] != null && data[i][1] != null) {
+ this.gridData.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]);
+ }
+ // else if there is a null, preserve it.
+ else if (data[i][0] == null) {
+ hasNull = true;
+ this.gridData.push([null, yp.call(this._yaxis, data[i][1])]);
+ }
+ else if (data[i][1] == null) {
+ hasNull = true;
+ this.gridData.push([xp.call(this._xaxis, data[i][0]), null]);
+ }
+ // if not a line series or if no nulls in data, push the converted point onto the array.
+ if (pdata[i] != null && pdata[i][0] != null && pdata[i][1] != null) {
+ this._prevGridData.push([xp.call(this._xaxis, pdata[i][0]), yp.call(this._yaxis, pdata[i][1])]);
+ }
+ // else if there is a null, preserve it.
+ else if (pdata[i] != null && pdata[i][0] == null) {
+ this._prevGridData.push([null, yp.call(this._yaxis, pdata[i][1])]);
+ }
+ else if (pdata[i] != null && pdata[i][0] != null && pdata[i][1] == null) {
+ this._prevGridData.push([xp.call(this._xaxis, pdata[i][0]), null]);
+ }
+ }
+
+ // don't do smoothing or bands on broken lines.
+ if (hasNull) {
+ this.renderer.smooth = false;
+ if (this._type === 'line') {
+ bands.show = false;
+ }
+ }
+
+ if (this._type === 'line' && bands.show) {
+ for (var i=0, l=bands.hiData.length; i<l; i++) {
+ this.renderer._hiBandGridData.push([xp.call(this._xaxis, bands.hiData[i][0]), yp.call(this._yaxis, bands.hiData[i][1])]);
+ }
+ for (var i=0, l=bands.lowData.length; i<l; i++) {
+ this.renderer._lowBandGridData.push([xp.call(this._xaxis, bands.lowData[i][0]), yp.call(this._yaxis, bands.lowData[i][1])]);
+ }
+ }
+
+ // calculate smoothed data if enough points and no nulls
+ if (this._type === 'line' && this.renderer.smooth && this.gridData.length > 2) {
+ var ret;
+ if (this.renderer.constrainSmoothing) {
+ ret = computeConstrainedSmoothedData.call(this, this.gridData);
+ this.renderer._smoothedData = ret[0];
+ this.renderer._smoothedPlotData = ret[1];
+
+ if (bands.show) {
+ ret = computeConstrainedSmoothedData.call(this, this.renderer._hiBandGridData);
+ this.renderer._hiBandSmoothedData = ret[0];
+ ret = computeConstrainedSmoothedData.call(this, this.renderer._lowBandGridData);
+ this.renderer._lowBandSmoothedData = ret[0];
+ }
+
+ ret = null;
+ }
+ else {
+ ret = computeHermiteSmoothedData.call(this, this.gridData);
+ this.renderer._smoothedData = ret[0];
+ this.renderer._smoothedPlotData = ret[1];
+
+ if (bands.show) {
+ ret = computeHermiteSmoothedData.call(this, this.renderer._hiBandGridData);
+ this.renderer._hiBandSmoothedData = ret[0];
+ ret = computeHermiteSmoothedData.call(this, this.renderer._lowBandGridData);
+ this.renderer._lowBandSmoothedData = ret[0];
+ }
+
+ ret = null;
+ }
+ }
+ };
+
+ // makeGridData
+ // converts any arbitrary data values to grid coordinates and
+ // returns them. This method exists so that plugins can use a series'
+ // linerenderer to generate grid data points without overwriting the
+ // grid data associated with that series.
+ // Called with scope of a series.
+ $.jqplot.LineRenderer.prototype.makeGridData = function(data, plot) {
+ // recalculate the grid data
+ var xp = this._xaxis.series_u2p;
+ var yp = this._yaxis.series_u2p;
+ var gd = [];
+ var pgd = [];
+ this.renderer._smoothedData = [];
+ this.renderer._smoothedPlotData = [];
+ this.renderer._hiBandGridData = [];
+ this.renderer._lowBandGridData = [];
+ this.renderer._hiBandSmoothedData = [];
+ this.renderer._lowBandSmoothedData = [];
+ var bands = this.renderer.bands;
+ var hasNull = false;
+ for (var i=0; i<data.length; i++) {
+ // if not a line series or if no nulls in data, push the converted point onto the array.
+ if (data[i][0] != null && data[i][1] != null) {
+ gd.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]);
+ }
+ // else if there is a null, preserve it.
+ else if (data[i][0] == null) {
+ hasNull = true;
+ gd.push([null, yp.call(this._yaxis, data[i][1])]);
+ }
+ else if (data[i][1] == null) {
+ hasNull = true;
+ gd.push([xp.call(this._xaxis, data[i][0]), null]);
+ }
+ }
+
+ // don't do smoothing or bands on broken lines.
+ if (hasNull) {
+ this.renderer.smooth = false;
+ if (this._type === 'line') {
+ bands.show = false;
+ }
+ }
+
+ if (this._type === 'line' && bands.show) {
+ for (var i=0, l=bands.hiData.length; i<l; i++) {
+ this.renderer._hiBandGridData.push([xp.call(this._xaxis, bands.hiData[i][0]), yp.call(this._yaxis, bands.hiData[i][1])]);
+ }
+ for (var i=0, l=bands.lowData.length; i<l; i++) {
+ this.renderer._lowBandGridData.push([xp.call(this._xaxis, bands.lowData[i][0]), yp.call(this._yaxis, bands.lowData[i][1])]);
+ }
+ }
+
+ if (this._type === 'line' && this.renderer.smooth && gd.length > 2) {
+ var ret;
+ if (this.renderer.constrainSmoothing) {
+ ret = computeConstrainedSmoothedData.call(this, gd);
+ this.renderer._smoothedData = ret[0];
+ this.renderer._smoothedPlotData = ret[1];
+
+ if (bands.show) {
+ ret = computeConstrainedSmoothedData.call(this, this.renderer._hiBandGridData);
+ this.renderer._hiBandSmoothedData = ret[0];
+ ret = computeConstrainedSmoothedData.call(this, this.renderer._lowBandGridData);
+ this.renderer._lowBandSmoothedData = ret[0];
+ }
+
+ ret = null;
+ }
+ else {
+ ret = computeHermiteSmoothedData.call(this, gd);
+ this.renderer._smoothedData = ret[0];
+ this.renderer._smoothedPlotData = ret[1];
+
+ if (bands.show) {
+ ret = computeHermiteSmoothedData.call(this, this.renderer._hiBandGridData);
+ this.renderer._hiBandSmoothedData = ret[0];
+ ret = computeHermiteSmoothedData.call(this, this.renderer._lowBandGridData);
+ this.renderer._lowBandSmoothedData = ret[0];
+ }
+
+ ret = null;
+ }
+ }
+ return gd;
+ };
+
+
+ // called within scope of series.
+ $.jqplot.LineRenderer.prototype.draw = function(ctx, gd, options, plot) {
+ var i;
+ // get a copy of the options, so we don't modify the original object.
+ var opts = $.extend(true, {}, options);
+ var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
+ var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
+ var fill = (opts.fill != undefined) ? opts.fill : this.fill;
+ var fillAndStroke = (opts.fillAndStroke != undefined) ? opts.fillAndStroke : this.fillAndStroke;
+ var xmin, ymin, xmax, ymax;
+ ctx.save();
+ if (gd.length) {
+ if (showLine) {
+ // if we fill, we'll have to add points to close the curve.
+ if (fill) {
+ if (this.fillToZero) {
+ // have to break line up into shapes at axis crossings
+ var negativeColor = this.negativeColor;
+ if (! this.useNegativeColors) {
+ negativeColor = opts.fillStyle;
+ }
+ var isnegative = false;
+ var posfs = opts.fillStyle;
+
+ // if stoking line as well as filling, get a copy of line data.
+ if (fillAndStroke) {
+ var fasgd = gd.slice(0);
+ }
+ // if not stacked, fill down to axis
+ if (this.index == 0 || !this._stack) {
+
+ var tempgd = [];
+ var pd = (this.renderer.smooth) ? this.renderer._smoothedPlotData : this._plotData;
+ this._areaPoints = [];
+ var pyzero = this._yaxis.series_u2p(this.fillToValue);
+ var pxzero = this._xaxis.series_u2p(this.fillToValue);
+
+ opts.closePath = true;
+
+ if (this.fillAxis == 'y') {
+ tempgd.push([gd[0][0], pyzero]);
+ this._areaPoints.push([gd[0][0], pyzero]);
+
+ for (var i=0; i<gd.length-1; i++) {
+ tempgd.push(gd[i]);
+ this._areaPoints.push(gd[i]);
+ // do we have an axis crossing?
+ if (pd[i][1] * pd[i+1][1] < 0) {
+ if (pd[i][1] < 0) {
+ isnegative = true;
+ opts.fillStyle = negativeColor;
+ }
+ else {
+ isnegative = false;
+ opts.fillStyle = posfs;
+ }
+
+ var xintercept = gd[i][0] + (gd[i+1][0] - gd[i][0]) * (pyzero-gd[i][1])/(gd[i+1][1] - gd[i][1]);
+ tempgd.push([xintercept, pyzero]);
+ this._areaPoints.push([xintercept, pyzero]);
+ // now draw this shape and shadow.
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, tempgd, opts);
+ }
+ this.renderer.shapeRenderer.draw(ctx, tempgd, opts);
+ // now empty temp array and continue
+ tempgd = [[xintercept, pyzero]];
+ // this._areaPoints = [[xintercept, pyzero]];
+ }
+ }
+ if (pd[gd.length-1][1] < 0) {
+ isnegative = true;
+ opts.fillStyle = negativeColor;
+ }
+ else {
+ isnegative = false;
+ opts.fillStyle = posfs;
+ }
+ tempgd.push(gd[gd.length-1]);
+ this._areaPoints.push(gd[gd.length-1]);
+ tempgd.push([gd[gd.length-1][0], pyzero]);
+ this._areaPoints.push([gd[gd.length-1][0], pyzero]);
+ }
+ // now draw the last area.
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, tempgd, opts);
+ }
+ this.renderer.shapeRenderer.draw(ctx, tempgd, opts);
+
+
+ // var gridymin = this._yaxis.series_u2p(0);
+ // // IE doesn't return new length on unshift
+ // gd.unshift([gd[0][0], gridymin]);
+ // len = gd.length;
+ // gd.push([gd[len - 1][0], gridymin]);
+ }
+ // if stacked, fill to line below
+ else {
+ var prev = this._prevGridData;
+ for (var i=prev.length; i>0; i--) {
+ gd.push(prev[i-1]);
+ // this._areaPoints.push(prev[i-1]);
+ }
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, gd, opts);
+ }
+ this._areaPoints = gd;
+ this.renderer.shapeRenderer.draw(ctx, gd, opts);
+ }
+ }
+ /////////////////////////
+ // Not filled to zero
+ ////////////////////////
+ else {
+ // if stoking line as well as filling, get a copy of line data.
+ if (fillAndStroke) {
+ var fasgd = gd.slice(0);
+ }
+ // if not stacked, fill down to axis
+ if (this.index == 0 || !this._stack) {
+ // var gridymin = this._yaxis.series_u2p(this._yaxis.min) - this.gridBorderWidth / 2;
+ var gridymin = ctx.canvas.height;
+ // IE doesn't return new length on unshift
+ gd.unshift([gd[0][0], gridymin]);
+ var len = gd.length;
+ gd.push([gd[len - 1][0], gridymin]);
+ }
+ // if stacked, fill to line below
+ else {
+ var prev = this._prevGridData;
+ for (var i=prev.length; i>0; i--) {
+ gd.push(prev[i-1]);
+ }
+ }
+ this._areaPoints = gd;
+
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, gd, opts);
+ }
+
+ this.renderer.shapeRenderer.draw(ctx, gd, opts);
+ }
+ if (fillAndStroke) {
+ var fasopts = $.extend(true, {}, opts, {fill:false, closePath:false});
+ this.renderer.shapeRenderer.draw(ctx, fasgd, fasopts);
+ //////////
+ // TODO: figure out some way to do shadows nicely
+ // if (shadow) {
+ // this.renderer.shadowRenderer.draw(ctx, fasgd, fasopts);
+ // }
+ // now draw the markers
+ if (this.markerRenderer.show) {
+ if (this.renderer.smooth) {
+ fasgd = this.gridData;
+ }
+ for (i=0; i<fasgd.length; i++) {
+ this.markerRenderer.draw(fasgd[i][0], fasgd[i][1], ctx, opts.markerOptions);
+ }
+ }
+ }
+ }
+ else {
+
+ if (this.renderer.bands.show) {
+ var bdat;
+ var bopts = $.extend(true, {}, opts);
+ if (this.renderer.bands.showLines) {
+ bdat = (this.renderer.smooth) ? this.renderer._hiBandSmoothedData : this.renderer._hiBandGridData;
+ this.renderer.shapeRenderer.draw(ctx, bdat, opts);
+ bdat = (this.renderer.smooth) ? this.renderer._lowBandSmoothedData : this.renderer._lowBandGridData;
+ this.renderer.shapeRenderer.draw(ctx, bdat, bopts);
+ }
+
+ if (this.renderer.bands.fill) {
+ if (this.renderer.smooth) {
+ bdat = this.renderer._hiBandSmoothedData.concat(this.renderer._lowBandSmoothedData.reverse());
+ }
+ else {
+ bdat = this.renderer._hiBandGridData.concat(this.renderer._lowBandGridData.reverse());
+ }
+ this._areaPoints = bdat;
+ bopts.closePath = true;
+ bopts.fill = true;
+ bopts.fillStyle = this.renderer.bands.fillColor;
+ this.renderer.shapeRenderer.draw(ctx, bdat, bopts);
+ }
+ }
+
+ if (shadow) {
+ this.renderer.shadowRenderer.draw(ctx, gd, opts);
+ }
+
+ this.renderer.shapeRenderer.draw(ctx, gd, opts);
+ }
+ }
+ // calculate the bounding box
+ var xmin = xmax = ymin = ymax = null;
+ for (i=0; i<this._areaPoints.length; i++) {
+ var p = this._areaPoints[i];
+ if (xmin > p[0] || xmin == null) {
+ xmin = p[0];
+ }
+ if (ymax < p[1] || ymax == null) {
+ ymax = p[1];
+ }
+ if (xmax < p[0] || xmax == null) {
+ xmax = p[0];
+ }
+ if (ymin > p[1] || ymin == null) {
+ ymin = p[1];
+ }
+ }
+
+ if (this.type === 'line' && this.renderer.bands.show) {
+ ymax = this._yaxis.series_u2p(this.renderer.bands._min);
+ ymin = this._yaxis.series_u2p(this.renderer.bands._max);
+ }
+
+ this._boundingBox = [[xmin, ymax], [xmax, ymin]];
+
+ // now draw the markers
+ if (this.markerRenderer.show && !fill) {
+ if (this.renderer.smooth) {
+ gd = this.gridData;
+ }
+ for (i=0; i<gd.length; i++) {
+ if (gd[i][0] != null && gd[i][1] != null) {
+ this.markerRenderer.draw(gd[i][0], gd[i][1], ctx, opts.markerOptions);
+ }
+ }
+ }
+ }
+
+ ctx.restore();
+ };
+
+ $.jqplot.LineRenderer.prototype.drawShadow = function(ctx, gd, options) {
+ // This is a no-op, shadows drawn with lines.
+ };
+
+ // called with scope of plot.
+ // make sure to not leave anything highlighted.
+ function postInit(target, data, options) {
+ for (var i=0; i<this.series.length; i++) {
+ if (this.series[i].renderer.constructor == $.jqplot.LineRenderer) {
+ // don't allow mouseover and mousedown at same time.
+ if (this.series[i].highlightMouseOver) {
+ this.series[i].highlightMouseDown = false;
+ }
+ }
+ }
+ }
+
+ // called within context of plot
+ // create a canvas which we can draw on.
+ // insert it before the eventCanvas, so eventCanvas will still capture events.
+ function postPlotDraw() {
+ // Memory Leaks patch
+ if (this.plugins.lineRenderer && this.plugins.lineRenderer.highlightCanvas) {
+ this.plugins.lineRenderer.highlightCanvas.resetCanvas();
+ this.plugins.lineRenderer.highlightCanvas = null;
+ }
+
+ this.plugins.lineRenderer.highlightedSeriesIndex = null;
+ this.plugins.lineRenderer.highlightCanvas = new $.jqplot.GenericCanvas();
+
+ this.eventCanvas._elem.before(this.plugins.lineRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-lineRenderer-highlight-canvas', this._plotDimensions, this));
+ this.plugins.lineRenderer.highlightCanvas.setContext();
+ this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
+ }
+
+ function highlight (plot, sidx, pidx, points) {
+ var s = plot.series[sidx];
+ var canvas = plot.plugins.lineRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ s._highlightedPoint = pidx;
+ plot.plugins.lineRenderer.highlightedSeriesIndex = sidx;
+ var opts = {fillStyle: s.highlightColor};
+ if (s.type === 'line' && s.renderer.bands.show) {
+ opts.fill = true;
+ opts.closePath = true;
+ }
+ s.renderer.shapeRenderer.draw(canvas._ctx, points, opts);
+ canvas = null;
+ }
+
+ function unhighlight (plot) {
+ var canvas = plot.plugins.lineRenderer.highlightCanvas;
+ canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height);
+ for (var i=0; i<plot.series.length; i++) {
+ plot.series[i]._highlightedPoint = null;
+ }
+ plot.plugins.lineRenderer.highlightedSeriesIndex = null;
+ plot.target.trigger('jqplotDataUnhighlight');
+ canvas = null;
+ }
+
+
+ function handleMove(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt1 = jQuery.Event('jqplotDataMouseOver');
+ evt1.pageX = ev.pageX;
+ evt1.pageY = ev.pageY;
+ plot.target.trigger(evt1, ins);
+ if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.lineRenderer.highlightedSeriesIndex)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseDown(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.lineRenderer.highlightedSeriesIndex)) {
+ var evt = jQuery.Event('jqplotDataHighlight');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points);
+ }
+ }
+ else if (neighbor == null) {
+ unhighlight (plot);
+ }
+ }
+
+ function handleMouseUp(ev, gridpos, datapos, neighbor, plot) {
+ var idx = plot.plugins.lineRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ }
+
+ function handleClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var evt = jQuery.Event('jqplotDataClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+ function handleRightClick(ev, gridpos, datapos, neighbor, plot) {
+ if (neighbor) {
+ var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data];
+ var idx = plot.plugins.lineRenderer.highlightedSeriesIndex;
+ if (idx != null && plot.series[idx].highlightMouseDown) {
+ unhighlight(plot);
+ }
+ var evt = jQuery.Event('jqplotDataRightClick');
+ evt.which = ev.which;
+ evt.pageX = ev.pageX;
+ evt.pageY = ev.pageY;
+ plot.target.trigger(evt, ins);
+ }
+ }
+
+
+ // class: $.jqplot.LinearAxisRenderer
+ // The default jqPlot axis renderer, creating a numeric axis.
+ $.jqplot.LinearAxisRenderer = function() {
+ };
+
+ // called with scope of axis object.
+ $.jqplot.LinearAxisRenderer.prototype.init = function(options){
+ // prop: breakPoints
+ // EXPERIMENTAL!! Use at your own risk!
+ // Works only with linear axes and the default tick renderer.
+ // Array of [start, stop] points to create a broken axis.
+ // Broken axes have a "jump" in them, which is an immediate
+ // transition from a smaller value to a larger value.
+ // Currently, axis ticks MUST be manually assigned if using breakPoints
+ // by using the axis ticks array option.
+ this.breakPoints = null;
+ // prop: breakTickLabel
+ // Label to use at the axis break if breakPoints are specified.
+ this.breakTickLabel = "&asymp;";
+ // prop: drawBaseline
+ // True to draw the axis baseline.
+ this.drawBaseline = true;
+ // prop: baselineWidth
+ // width of the baseline in pixels.
+ this.baselineWidth = null;
+ // prop: baselineColor
+ // CSS color spec for the baseline.
+ this.baselineColor = null;
+ // prop: forceTickAt0
+ // This will ensure that there is always a tick mark at 0.
+ // If data range is strictly positive or negative,
+ // this will force 0 to be inside the axis bounds unless
+ // the appropriate axis pad (pad, padMin or padMax) is set
+ // to 0, then this will force an axis min or max value at 0.
+ // This has know effect when any of the following options
+ // are set: autoscale, min, max, numberTicks or tickInterval.
+ this.forceTickAt0 = false;
+ // prop: forceTickAt100
+ // This will ensure that there is always a tick mark at 100.
+ // If data range is strictly above or below 100,
+ // this will force 100 to be inside the axis bounds unless
+ // the appropriate axis pad (pad, padMin or padMax) is set
+ // to 0, then this will force an axis min or max value at 100.
+ // This has know effect when any of the following options
+ // are set: autoscale, min, max, numberTicks or tickInterval.
+ this.forceTickAt100 = false;
+ // prop: tickInset
+ // Controls the amount to inset the first and last ticks from
+ // the edges of the grid, in multiples of the tick interval.
+ // 0 is no inset, 0.5 is one half a tick interval, 1 is a full
+ // tick interval, etc.
+ this.tickInset = 0;
+ // prop: minorTicks
+ // Number of ticks to add between "major" ticks.
+ // Major ticks are ticks supplied by user or auto computed.
+ // Minor ticks cannot be created by user.
+ this.minorTicks = 0;
+ // prop: alignTicks
+ // true to align tick marks across opposed axes
+ // such as from the y2axis to yaxis.
+ this.alignTicks = false;
+ this._autoFormatString = '';
+ this._overrideFormatString = false;
+ this._scalefact = 1.0;
+ $.extend(true, this, options);
+ if (this.breakPoints) {
+ if (!$.isArray(this.breakPoints)) {
+ this.breakPoints = null;
+ }
+ else if (this.breakPoints.length < 2 || this.breakPoints[1] <= this.breakPoints[0]) {
+ this.breakPoints = null;
+ }
+ }
+ if (this.numberTicks != null && this.numberTicks < 2) {
+ this.numberTicks = 2;
+ }
+ this.resetDataBounds();
+ };
+
+ // called with scope of axis
+ $.jqplot.LinearAxisRenderer.prototype.draw = function(ctx, plot) {
+ if (this.show) {
+ // populate the axis label and value properties.
+ // createTicks is a method on the renderer, but
+ // call it within the scope of the axis.
+ this.renderer.createTicks.call(this, plot);
+ // fill a div with axes labels in the right direction.
+ // Need to pregenerate each axis to get it's bounds and
+ // position it and the labels correctly on the plot.
+ var dim=0;
+ var temp;
+ // Added for theming.
+ if (this._elem) {
+ // Memory Leaks patch
+ //this._elem.empty();
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ this._elem = $(document.createElement('div'));
+ this._elem.addClass('jqplot-axis jqplot-'+this.name);
+ this._elem.css('position', 'absolute');
+
+
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ this._elem.width(this._plotDimensions.width);
+ }
+ else {
+ this._elem.height(this._plotDimensions.height);
+ }
+
+ // create a _label object.
+ this.labelOptions.axis = this.name;
+ this._label = new this.labelRenderer(this.labelOptions);
+ if (this._label.show) {
+ var elem = this._label.draw(ctx, plot);
+ elem.appendTo(this._elem);
+ elem = null;
+ }
+
+ var t = this._ticks;
+ var tick;
+ for (var i=0; i<t.length; i++) {
+ tick = t[i];
+ if (tick.show && tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
+ this._elem.append(tick.draw(ctx, plot));
+ }
+ }
+ tick = null;
+ t = null;
+ }
+ return this._elem;
+ };
+
+ // called with scope of an axis
+ $.jqplot.LinearAxisRenderer.prototype.reset = function() {
+ this.min = this._options.min;
+ this.max = this._options.max;
+ this.tickInterval = this._options.tickInterval;
+ this.numberTicks = this._options.numberTicks;
+ this._autoFormatString = '';
+ if (this._overrideFormatString && this.tickOptions && this.tickOptions.formatString) {
+ this.tickOptions.formatString = '';
+ }
+
+ // this._ticks = this.__ticks;
+ };
+
+ // called with scope of axis
+ $.jqplot.LinearAxisRenderer.prototype.set = function() {
+ var dim = 0;
+ var temp;
+ var w = 0;
+ var h = 0;
+ var lshow = (this._label == null) ? false : this._label.show;
+ if (this.show) {
+ var t = this._ticks;
+ var tick;
+ for (var i=0; i<t.length; i++) {
+ tick = t[i];
+ if (!tick._breakTick && tick.show && tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ temp = tick._elem.outerHeight(true);
+ }
+ else {
+ temp = tick._elem.outerWidth(true);
+ }
+ if (temp > dim) {
+ dim = temp;
+ }
+ }
+ }
+ tick = null;
+ t = null;
+
+ if (lshow) {
+ w = this._label._elem.outerWidth(true);
+ h = this._label._elem.outerHeight(true);
+ }
+ if (this.name == 'xaxis') {
+ dim = dim + h;
+ this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});
+ }
+ else if (this.name == 'x2axis') {
+ dim = dim + h;
+ this._elem.css({'height':dim+'px', left:'0px', top:'0px'});
+ }
+ else if (this.name == 'yaxis') {
+ dim = dim + w;
+ this._elem.css({'width':dim+'px', left:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ else {
+ dim = dim + w;
+ this._elem.css({'width':dim+'px', right:'0px', top:'0px'});
+ if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
+ this._label._elem.css('width', w+'px');
+ }
+ }
+ }
+ };
+
+ // called with scope of axis
+ $.jqplot.LinearAxisRenderer.prototype.createTicks = function(plot) {
+ // we're are operating on an axis here
+ var ticks = this._ticks;
+ var userTicks = this.ticks;
+ var name = this.name;
+ // databounds were set on axis initialization.
+ var db = this._dataBounds;
+ var dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height;
+ var interval;
+ var min, max;
+ var pos1, pos2;
+ var tt, i;
+ // get a copy of user's settings for min/max.
+ var userMin = this.min;
+ var userMax = this.max;
+ var userNT = this.numberTicks;
+ var userTI = this.tickInterval;
+
+ var threshold = 30;
+ this._scalefact = (Math.max(dim, threshold+1) - threshold)/300.0;
+
+ // if we already have ticks, use them.
+ // ticks must be in order of increasing value.
+
+ if (userTicks.length) {
+ // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
+ for (i=0; i<userTicks.length; i++){
+ var ut = userTicks[i];
+ var t = new this.tickRenderer(this.tickOptions);
+ if ($.isArray(ut)) {
+ t.value = ut[0];
+ if (this.breakPoints) {
+ if (ut[0] == this.breakPoints[0]) {
+ t.label = this.breakTickLabel;
+ t._breakTick = true;
+ t.showGridline = false;
+ t.showMark = false;
+ }
+ else if (ut[0] > this.breakPoints[0] && ut[0] <= this.breakPoints[1]) {
+ t.show = false;
+ t.showGridline = false;
+ t.label = ut[1];
+ }
+ else {
+ t.label = ut[1];
+ }
+ }
+ else {
+ t.label = ut[1];
+ }
+ t.setTick(ut[0], this.name);
+ this._ticks.push(t);
+ }
+
+ else if ($.isPlainObject(ut)) {
+ $.extend(true, t, ut);
+ t.axis = this.name;
+ this._ticks.push(t);
+ }
+
+ else {
+ t.value = ut;
+ if (this.breakPoints) {
+ if (ut == this.breakPoints[0]) {
+ t.label = this.breakTickLabel;
+ t._breakTick = true;
+ t.showGridline = false;
+ t.showMark = false;
+ }
+ else if (ut > this.breakPoints[0] && ut <= this.breakPoints[1]) {
+ t.show = false;
+ t.showGridline = false;
+ }
+ }
+ t.setTick(ut, this.name);
+ this._ticks.push(t);
+ }
+ }
+ this.numberTicks = userTicks.length;
+ this.min = this._ticks[0].value;
+ this.max = this._ticks[this.numberTicks-1].value;
+ this.tickInterval = (this.max - this.min) / (this.numberTicks - 1);
+ }
+
+ // we don't have any ticks yet, let's make some!
+ else {
+ if (name == 'xaxis' || name == 'x2axis') {
+ dim = this._plotDimensions.width;
+ }
+ else {
+ dim = this._plotDimensions.height;
+ }
+
+ var _numberTicks = this.numberTicks;
+
+ // if aligning this axis, use number of ticks from previous axis.
+ // Do I need to reset somehow if alignTicks is changed and then graph is replotted??
+ if (this.alignTicks) {
+ if (this.name === 'x2axis' && plot.axes.xaxis.show) {
+ _numberTicks = plot.axes.xaxis.numberTicks;
+ }
+ else if (this.name.charAt(0) === 'y' && this.name !== 'yaxis' && this.name !== 'yMidAxis' && plot.axes.yaxis.show) {
+ _numberTicks = plot.axes.yaxis.numberTicks;
+ }
+ }
+
+ min = ((this.min != null) ? this.min : db.min);
+ max = ((this.max != null) ? this.max : db.max);
+
+ var range = max - min;
+ var rmin, rmax;
+ var temp;
+
+ if (this.tickOptions == null || !this.tickOptions.formatString) {
+ this._overrideFormatString = true;
+ }
+
+ // Doing complete autoscaling
+ if (this.min == null || this.max == null && this.tickInterval == null && !this.autoscale) {
+ // Check if user must have tick at 0 or 100 and ensure they are in range.
+ // The autoscaling algorithm will always place ticks at 0 and 100 if they are in range.
+ if (this.forceTickAt0) {
+ if (min > 0) {
+ min = 0;
+ }
+ if (max < 0) {
+ max = 0;
+ }
+ }
+
+ if (this.forceTickAt100) {
+ if (min > 100) {
+ min = 100;
+ }
+ if (max < 100) {
+ max = 100;
+ }
+ }
+
+ var keepMin = false,
+ keepMax = false;
+
+ if (this.min != null) {
+ keepMin = true;
+ }
+
+ else if (this.max != null) {
+ keepMax = true;
+ }
+
+ // var threshold = 30;
+ // var tdim = Math.max(dim, threshold+1);
+ // this._scalefact = (tdim-threshold)/300.0;
+ var ret = $.jqplot.LinearTickGenerator(min, max, this._scalefact, _numberTicks, keepMin, keepMax);
+ // calculate a padded max and min, points should be less than these
+ // so that they aren't too close to the edges of the plot.
+ // User can adjust how much padding is allowed with pad, padMin and PadMax options.
+ // If min or max is set, don't pad that end of axis.
+ var tumin = (this.min != null) ? min : min + range*(this.padMin - 1);
+ var tumax = (this.max != null) ? max : max - range*(this.padMax - 1);
+
+ // if they're equal, we shouldn't have to do anything, right?
+ // if (min <=tumin || max >= tumax) {
+ if (min <tumin || max > tumax) {
+ tumin = (this.min != null) ? min : min - range*(this.padMin - 1);
+ tumax = (this.max != null) ? max : max + range*(this.padMax - 1);
+ ret = $.jqplot.LinearTickGenerator(tumin, tumax, this._scalefact, _numberTicks, keepMin, keepMax);
+ }
+
+ this.min = ret[0];
+ this.max = ret[1];
+ // if numberTicks specified, it should return the same.
+ this.numberTicks = ret[2];
+ this._autoFormatString = ret[3];
+ this.tickInterval = ret[4];
+ }
+
+ // User has specified some axis scale related option, can use auto algorithm
+ else {
+
+ // if min and max are same, space them out a bit
+ if (min == max) {
+ var adj = 0.05;
+ if (min > 0) {
+ adj = Math.max(Math.log(min)/Math.LN10, 0.05);
+ }
+ min -= adj;
+ max += adj;
+ }
+
+ // autoscale. Can't autoscale if min or max is supplied.
+ // Will use numberTicks and tickInterval if supplied. Ticks
+ // across multiple axes may not line up depending on how
+ // bars are to be plotted.
+ if (this.autoscale && this.min == null && this.max == null) {
+ var rrange, ti, margin;
+ var forceMinZero = false;
+ var forceZeroLine = false;
+ var intervals = {min:null, max:null, average:null, stddev:null};
+ // if any series are bars, or if any are fill to zero, and if this
+ // is the axis to fill toward, check to see if we can start axis at zero.
+ for (var i=0; i<this._series.length; i++) {
+ var s = this._series[i];
+ var faname = (s.fillAxis == 'x') ? s._xaxis.name : s._yaxis.name;
+ // check to see if this is the fill axis
+ if (this.name == faname) {
+ var vals = s._plotValues[s.fillAxis];
+ var vmin = vals[0];
+ var vmax = vals[0];
+ for (var j=1; j<vals.length; j++) {
+ if (vals[j] < vmin) {
+ vmin = vals[j];
+ }
+ else if (vals[j] > vmax) {
+ vmax = vals[j];
+ }
+ }
+ var dp = (vmax - vmin) / vmax;
+ // is this sries a bar?
+ if (s.renderer.constructor == $.jqplot.BarRenderer) {
+ // if no negative values and could also check range.
+ if (vmin >= 0 && (s.fillToZero || dp > 0.1)) {
+ forceMinZero = true;
+ }
+ else {
+ forceMinZero = false;
+ if (s.fill && s.fillToZero && vmin < 0 && vmax > 0) {
+ forceZeroLine = true;
+ }
+ else {
+ forceZeroLine = false;
+ }
+ }
+ }
+
+ // if not a bar and filling, use appropriate method.
+ else if (s.fill) {
+ if (vmin >= 0 && (s.fillToZero || dp > 0.1)) {
+ forceMinZero = true;
+ }
+ else if (vmin < 0 && vmax > 0 && s.fillToZero) {
+ forceMinZero = false;
+ forceZeroLine = true;
+ }
+ else {
+ forceMinZero = false;
+ forceZeroLine = false;
+ }
+ }
+
+ // if not a bar and not filling, only change existing state
+ // if it doesn't make sense
+ else if (vmin < 0) {
+ forceMinZero = false;
+ }
+ }
+ }
+
+ // check if we need make axis min at 0.
+ if (forceMinZero) {
+ // compute number of ticks
+ this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
+ this.min = 0;
+ userMin = 0;
+ // what order is this range?
+ // what tick interval does that give us?
+ ti = max/(this.numberTicks-1);
+ temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10)));
+ if (ti/temp == parseInt(ti/temp, 10)) {
+ ti += temp;
+ }
+ this.tickInterval = Math.ceil(ti/temp) * temp;
+ this.max = this.tickInterval * (this.numberTicks - 1);
+ }
+
+ // check if we need to make sure there is a tick at 0.
+ else if (forceZeroLine) {
+ // compute number of ticks
+ this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
+ var ntmin = Math.ceil(Math.abs(min)/range*(this.numberTicks-1));
+ var ntmax = this.numberTicks - 1 - ntmin;
+ ti = Math.max(Math.abs(min/ntmin), Math.abs(max/ntmax));
+ temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10)));
+ this.tickInterval = Math.ceil(ti/temp) * temp;
+ this.max = this.tickInterval * ntmax;
+ this.min = -this.tickInterval * ntmin;
+ }
+
+ // if nothing else, do autoscaling which will try to line up ticks across axes.
+ else {
+ if (this.numberTicks == null){
+ if (this.tickInterval) {
+ this.numberTicks = 3 + Math.ceil(range / this.tickInterval);
+ }
+ else {
+ this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
+ }
+ }
+
+ if (this.tickInterval == null) {
+ // get a tick interval
+ ti = range/(this.numberTicks - 1);
+
+ if (ti < 1) {
+ temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10)));
+ }
+ else {
+ temp = 1;
+ }
+ this.tickInterval = Math.ceil(ti*temp*this.pad)/temp;
+ }
+ else {
+ temp = 1 / this.tickInterval;
+ }
+
+ // try to compute a nicer, more even tick interval
+ // temp = Math.pow(10, Math.floor(Math.log(ti)/Math.LN10));
+ // this.tickInterval = Math.ceil(ti/temp) * temp;
+ rrange = this.tickInterval * (this.numberTicks - 1);
+ margin = (rrange - range)/2;
+
+ if (this.min == null) {
+ this.min = Math.floor(temp*(min-margin))/temp;
+ }
+ if (this.max == null) {
+ this.max = this.min + rrange;
+ }
+ }
+
+ // Compute a somewhat decent format string if it is needed.
+ // get precision of interval and determine a format string.
+ var sf = $.jqplot.getSignificantFigures(this.tickInterval);
+
+ var fstr;
+
+ // if we have only a whole number, use integer formatting
+ if (sf.digitsLeft >= sf.significantDigits) {
+ fstr = '%d';
+ }
+
+ else {
+ var temp = Math.max(0, 5 - sf.digitsLeft);
+ temp = Math.min(temp, sf.digitsRight);
+ fstr = '%.'+ temp + 'f';
+ }
+
+ this._autoFormatString = fstr;
+ }
+
+ // Use the default algorithm which pads each axis to make the chart
+ // centered nicely on the grid.
+ else {
+
+ rmin = (this.min != null) ? this.min : min - range*(this.padMin - 1);
+ rmax = (this.max != null) ? this.max : max + range*(this.padMax - 1);
+ range = rmax - rmin;
+
+ if (this.numberTicks == null){
+ // if tickInterval is specified by user, we will ignore computed maximum.
+ // max will be equal or greater to fit even # of ticks.
+ if (this.tickInterval != null) {
+ this.numberTicks = Math.ceil((rmax - rmin)/this.tickInterval)+1;
+ }
+ else if (dim > 100) {
+ this.numberTicks = parseInt(3+(dim-100)/75, 10);
+ }
+ else {
+ this.numberTicks = 2;
+ }
+ }
+
+ if (this.tickInterval == null) {
+ this.tickInterval = range / (this.numberTicks-1);
+ }
+
+ if (this.max == null) {
+ rmax = rmin + this.tickInterval*(this.numberTicks - 1);
+ }
+ if (this.min == null) {
+ rmin = rmax - this.tickInterval*(this.numberTicks - 1);
+ }
+
+ // get precision of interval and determine a format string.
+ var sf = $.jqplot.getSignificantFigures(this.tickInterval);
+
+ var fstr;
+
+ // if we have only a whole number, use integer formatting
+ if (sf.digitsLeft >= sf.significantDigits) {
+ fstr = '%d';
+ }
+
+ else {
+ var temp = Math.max(0, 5 - sf.digitsLeft);
+ temp = Math.min(temp, sf.digitsRight);
+ fstr = '%.'+ temp + 'f';
+ }
+
+
+ this._autoFormatString = fstr;
+
+ this.min = rmin;
+ this.max = rmax;
+ }
+
+ if (this.renderer.constructor == $.jqplot.LinearAxisRenderer && this._autoFormatString == '') {
+ // fix for misleading tick display with small range and low precision.
+ range = this.max - this.min;
+ // figure out precision
+ var temptick = new this.tickRenderer(this.tickOptions);
+ // use the tick formatString or, the default.
+ var fs = temptick.formatString || $.jqplot.config.defaultTickFormatString;
+ var fs = fs.match($.jqplot.sprintf.regex)[0];
+ var precision = 0;
+ if (fs) {
+ if (fs.search(/[fFeEgGpP]/) > -1) {
+ var m = fs.match(/\%\.(\d{0,})?[eEfFgGpP]/);
+ if (m) {
+ precision = parseInt(m[1], 10);
+ }
+ else {
+ precision = 6;
+ }
+ }
+ else if (fs.search(/[di]/) > -1) {
+ precision = 0;
+ }
+ // fact will be <= 1;
+ var fact = Math.pow(10, -precision);
+ if (this.tickInterval < fact) {
+ // need to correct underrange
+ if (userNT == null && userTI == null) {
+ this.tickInterval = fact;
+ if (userMax == null && userMin == null) {
+ // this.min = Math.floor((this._dataBounds.min - this.tickInterval)/fact) * fact;
+ this.min = Math.floor(this._dataBounds.min/fact) * fact;
+ if (this.min == this._dataBounds.min) {
+ this.min = this._dataBounds.min - this.tickInterval;
+ }
+ // this.max = Math.ceil((this._dataBounds.max + this.tickInterval)/fact) * fact;
+ this.max = Math.ceil(this._dataBounds.max/fact) * fact;
+ if (this.max == this._dataBounds.max) {
+ this.max = this._dataBounds.max + this.tickInterval;
+ }
+ var n = (this.max - this.min)/this.tickInterval;
+ n = n.toFixed(11);
+ n = Math.ceil(n);
+ this.numberTicks = n + 1;
+ }
+ else if (userMax == null) {
+ // add one tick for top of range.
+ var n = (this._dataBounds.max - this.min) / this.tickInterval;
+ n = n.toFixed(11);
+ this.numberTicks = Math.ceil(n) + 2;
+ this.max = this.min + this.tickInterval * (this.numberTicks-1);
+ }
+ else if (userMin == null) {
+ // add one tick for bottom of range.
+ var n = (this.max - this._dataBounds.min) / this.tickInterval;
+ n = n.toFixed(11);
+ this.numberTicks = Math.ceil(n) + 2;
+ this.min = this.max - this.tickInterval * (this.numberTicks-1);
+ }
+ else {
+ // calculate a number of ticks so max is within axis scale
+ this.numberTicks = Math.ceil((userMax - userMin)/this.tickInterval) + 1;
+ // if user's min and max don't fit evenly in ticks, adjust.
+ // This takes care of cases such as user min set to 0, max set to 3.5 but tick
+ // format string set to %d (integer ticks)
+ this.min = Math.floor(userMin*Math.pow(10, precision))/Math.pow(10, precision);
+ this.max = Math.ceil(userMax*Math.pow(10, precision))/Math.pow(10, precision);
+ // this.max = this.min + this.tickInterval*(this.numberTicks-1);
+ this.numberTicks = Math.ceil((this.max - this.min)/this.tickInterval) + 1;
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ if (this._overrideFormatString && this._autoFormatString != '') {
+ this.tickOptions = this.tickOptions || {};
+ this.tickOptions.formatString = this._autoFormatString;
+ }
+
+ var t, to;
+ for (var i=0; i<this.numberTicks; i++){
+ tt = this.min + i * this.tickInterval;
+ t = new this.tickRenderer(this.tickOptions);
+ // var t = new $.jqplot.AxisTickRenderer(this.tickOptions);
+
+ t.setTick(tt, this.name);
+ this._ticks.push(t);
+
+ if (i < this.numberTicks - 1) {
+ for (var j=0; j<this.minorTicks; j++) {
+ tt += this.tickInterval/(this.minorTicks+1);
+ to = $.extend(true, {}, this.tickOptions, {name:this.name, value:tt, label:'', isMinorTick:true});
+ t = new this.tickRenderer(to);
+ this._ticks.push(t);
+ }
+ }
+ t = null;
+ }
+ }
+
+ if (this.tickInset) {
+ this.min = this.min - this.tickInset * this.tickInterval;
+ this.max = this.max + this.tickInset * this.tickInterval;
+ }
+
+ ticks = null;
+ };
+
+ // Used to reset just the values of the ticks and then repack, which will
+ // recalculate the positioning functions. It is assuemd that the
+ // number of ticks is the same and the values of the new array are at the
+ // proper interval.
+ // This method needs to be called with the scope of an axis object, like:
+ //
+ // > plot.axes.yaxis.renderer.resetTickValues.call(plot.axes.yaxis, yarr);
+ //
+ $.jqplot.LinearAxisRenderer.prototype.resetTickValues = function(opts) {
+ if ($.isArray(opts) && opts.length == this._ticks.length) {
+ var t;
+ for (var i=0; i<opts.length; i++) {
+ t = this._ticks[i];
+ t.value = opts[i];
+ t.label = t.formatter(t.formatString, opts[i]);
+ t.label = t.prefix + t.label;
+ t._elem.html(t.label);
+ }
+ t = null;
+ this.min = $.jqplot.arrayMin(opts);
+ this.max = $.jqplot.arrayMax(opts);
+ this.pack();
+ }
+ // Not implemented yet.
+ // else if ($.isPlainObject(opts)) {
+ //
+ // }
+ };
+
+ // called with scope of axis
+ $.jqplot.LinearAxisRenderer.prototype.pack = function(pos, offsets) {
+ // Add defaults for repacking from resetTickValues function.
+ pos = pos || {};
+ offsets = offsets || this._offsets;
+
+ var ticks = this._ticks;
+ var max = this.max;
+ var min = this.min;
+ var offmax = offsets.max;
+ var offmin = offsets.min;
+ var lshow = (this._label == null) ? false : this._label.show;
+
+ for (var p in pos) {
+ this._elem.css(p, pos[p]);
+ }
+
+ this._offsets = offsets;
+ // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
+ var pixellength = offmax - offmin;
+ var unitlength = max - min;
+
+ // point to unit and unit to point conversions references to Plot DOM element top left corner.
+ if (this.breakPoints) {
+ unitlength = unitlength - this.breakPoints[1] + this.breakPoints[0];
+
+ this.p2u = function(p){
+ return (p - offmin) * unitlength / pixellength + min;
+ };
+
+ this.u2p = function(u){
+ if (u > this.breakPoints[0] && u < this.breakPoints[1]){
+ u = this.breakPoints[0];
+ }
+ if (u <= this.breakPoints[0]) {
+ return (u - min) * pixellength / unitlength + offmin;
+ }
+ else {
+ return (u - this.breakPoints[1] + this.breakPoints[0] - min) * pixellength / unitlength + offmin;
+ }
+ };
+
+ if (this.name.charAt(0) == 'x'){
+ this.series_u2p = function(u){
+ if (u > this.breakPoints[0] && u < this.breakPoints[1]){
+ u = this.breakPoints[0];
+ }
+ if (u <= this.breakPoints[0]) {
+ return (u - min) * pixellength / unitlength;
+ }
+ else {
+ return (u - this.breakPoints[1] + this.breakPoints[0] - min) * pixellength / unitlength;
+ }
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+
+ else {
+ this.series_u2p = function(u){
+ if (u > this.breakPoints[0] && u < this.breakPoints[1]){
+ u = this.breakPoints[0];
+ }
+ if (u >= this.breakPoints[1]) {
+ return (u - max) * pixellength / unitlength;
+ }
+ else {
+ return (u + this.breakPoints[1] - this.breakPoints[0] - max) * pixellength / unitlength;
+ }
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + max;
+ };
+ }
+ }
+ else {
+ this.p2u = function(p){
+ return (p - offmin) * unitlength / pixellength + min;
+ };
+
+ this.u2p = function(u){
+ return (u - min) * pixellength / unitlength + offmin;
+ };
+
+ if (this.name == 'xaxis' || this.name == 'x2axis'){
+ this.series_u2p = function(u){
+ return (u - min) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + min;
+ };
+ }
+
+ else {
+ this.series_u2p = function(u){
+ return (u - max) * pixellength / unitlength;
+ };
+ this.series_p2u = function(p){
+ return p * unitlength / pixellength + max;
+ };
+ }
+ }
+
+ if (this.show) {
+ if (this.name == 'xaxis' || this.name == 'x2axis') {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'xaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ if (temp * t.angle < 0) {
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ }
+ // position at start
+ else {
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'end':
+ shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ case 'start':
+ shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ break;
+ case 'middle':
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ default:
+ shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getWidth()/2;
+ }
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('left', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var w = this._label._elem.outerWidth(true);
+ this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
+ if (this.name == 'xaxis') {
+ this._label._elem.css('bottom', '0px');
+ }
+ else {
+ this._label._elem.css('top', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ else {
+ for (var i=0; i<ticks.length; i++) {
+ var t = ticks[i];
+ if (t.show && t.showLabel) {
+ var shim;
+ if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
+ // will need to adjust auto positioning based on which axis this is.
+ var temp = (this.name == 'yaxis') ? 1 : -1;
+ switch (t.labelPosition) {
+ case 'auto':
+ // position at end
+ case 'end':
+ if (temp * t.angle < 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'start':
+ if (t.angle > 0) {
+ shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
+ }
+ else {
+ shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
+ }
+ break;
+ case 'middle':
+ // if (t.angle > 0) {
+ // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
+ // }
+ // else {
+ // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
+ // }
+ shim = -t.getHeight()/2;
+ break;
+ default:
+ shim = -t.getHeight()/2;
+ break;
+ }
+ }
+ else {
+ shim = -t.getHeight()/2;
+ }
+
+ var val = this.u2p(t.value) + shim + 'px';
+ t._elem.css('top', val);
+ t.pack();
+ }
+ }
+ if (lshow) {
+ var h = this._label._elem.outerHeight(true);
+ this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
+ if (this.name == 'yaxis') {
+ this._label._elem.css('left', '0px');
+ }
+ else {
+ this._label._elem.css('right', '0px');
+ }
+ this._label.pack();
+ }
+ }
+ }
+
+ ticks = null;
+ };
+
+
+ /**
+ * The following code was generaously given to me a while back by Scott Prahl.
+ * He did a good job at computing axes min, max and number of ticks for the
+ * case where the user has not set any scale related parameters (tickInterval,
+ * numberTicks, min or max). I had ignored this use case for a long time,
+ * focusing on the more difficult case where user has set some option controlling
+ * tick generation. Anyway, about time I got this into jqPlot.
+ * Thanks Scott!!
+ */
+
+ /**
+ * Copyright (c) 2010 Scott Prahl
+ * The next three routines are currently available for use in all personal
+ * or commercial projects under both the MIT and GPL version 2.0 licenses.
+ * This means that you can choose the license that best suits your project
+ * and use it accordingly.
+ */
+
+ // A good format string depends on the interval. If the interval is greater
+ // than 1 then there is no need to show any decimal digits. If it is < 1.0, then
+ // use the magnitude of the interval to determine the number of digits to show.
+ function bestFormatString (interval)
+ {
+ var fstr;
+ interval = Math.abs(interval);
+ if (interval >= 10) {
+ fstr = '%d';
+ }
+
+ else if (interval > 1) {
+ if (interval === parseInt(interval, 10)) {
+ fstr = '%d';
+ }
+ else {
+ fstr = '%.1f';
+ }
+ }
+
+ else {
+ var expv = -Math.floor(Math.log(interval)/Math.LN10);
+ fstr = '%.' + expv + 'f';
+ }
+
+ return fstr;
+ }
+
+ var _factors = [0.1, 0.2, 0.3, 0.4, 0.5, 0.8, 1, 2, 3, 4, 5];
+
+ var _getLowerFactor = function(f) {
+ var i = _factors.indexOf(f);
+ if (i > 0) {
+ return _factors[i-1];
+ }
+ else {
+ return _factors[_factors.length - 1] / 100;
+ }
+ };
+
+ var _getHigherFactor = function(f) {
+ var i = _factors.indexOf(f);
+ if (i < _factors.length-1) {
+ return _factors[i+1];
+ }
+ else {
+ return _factors[0] * 100;
+ }
+ };
+
+ // Given a fixed minimum and maximum and a target number ot ticks
+ // figure out the best interval and
+ // return min, max, number ticks, format string and tick interval
+ function bestConstrainedInterval(min, max, nttarget) {
+ // run through possible number to ticks and see which interval is best
+ var low = Math.floor(nttarget/2);
+ var hi = Math.ceil(nttarget*1.5);
+ var badness = Number.MAX_VALUE;
+ var r = (max - min);
+ var temp;
+ var sd;
+ var bestNT;
+ var gsf = $.jqplot.getSignificantFigures;
+ var fsd;
+ var fs;
+ var currentNT;
+ var bestPrec;
+
+ for (var i=0, l=hi-low+1; i<l; i++) {
+ currentNT = low + i;
+ temp = r/(currentNT-1);
+ sd = gsf(temp);
+
+ temp = Math.abs(nttarget - currentNT) + sd.digitsRight;
+ if (temp < badness) {
+ badness = temp;
+ bestNT = currentNT;
+ bestPrec = sd.digitsRight;
+ }
+ else if (temp === badness) {
+ // let nicer ticks trump number ot ticks
+ if (sd.digitsRight < bestPrec) {
+ bestNT = currentNT;
+ bestPrec = sd.digitsRight;
+ }
+ }
+
+ }
+
+ fsd = Math.max(bestPrec, Math.max(gsf(min).digitsRight, gsf(max).digitsRight));
+ if (fsd === 0) {
+ fs = '%d';
+ }
+ else {
+ fs = '%.' + fsd + 'f';
+ }
+ temp = r / (bestNT - 1);
+ // min, max, number ticks, format string, tick interval
+ return [min, max, bestNT, fs, temp];
+ }
+
+ // This will return an interval of form 2 * 10^n, 5 * 10^n or 10 * 10^n
+ // it is based soley on the range and number of ticks. So if user specifies
+ // number of ticks, use this.
+ function bestInterval(range, numberTicks) {
+ numberTicks = numberTicks || 7;
+ var minimum = range / (numberTicks - 1);
+ var magnitude = Math.pow(10, Math.floor(Math.log(minimum) / Math.LN10));
+ var residual = minimum / magnitude;
+ var interval;
+ // "nicest" ranges are 1, 2, 5 or powers of these.
+ // for magnitudes below 1, only allow these.
+ if (magnitude < 1) {
+ if (residual > 5) {
+ interval = 10 * magnitude;
+ }
+ else if (residual > 2) {
+ interval = 5 * magnitude;
+ }
+ else if (residual > 1) {
+ interval = 2 * magnitude;
+ }
+ else {
+ interval = magnitude;
+ }
+ }
+ // for large ranges (whole integers), allow intervals like 3, 4 or powers of these.
+ // this helps a lot with poor choices for number of ticks.
+ else {
+ if (residual > 5) {
+ interval = 10 * magnitude;
+ }
+ else if (residual > 4) {
+ interval = 5 * magnitude;
+ }
+ else if (residual > 3) {
+ interval = 4 * magnitude;
+ }
+ else if (residual > 2) {
+ interval = 3 * magnitude;
+ }
+ else if (residual > 1) {
+ interval = 2 * magnitude;
+ }
+ else {
+ interval = magnitude;
+ }
+ }
+
+ return interval;
+ }
+
+ // This will return an interval of form 2 * 10^n, 5 * 10^n or 10 * 10^n
+ // it is based soley on the range of data, number of ticks must be computed later.
+ function bestLinearInterval(range, scalefact) {
+ scalefact = scalefact || 1;
+ var expv = Math.floor(Math.log(range)/Math.LN10);
+ var magnitude = Math.pow(10, expv);
+ // 0 < f < 10
+ var f = range / magnitude;
+ var fact;
+ // for large plots, scalefact will decrease f and increase number of ticks.
+ // for small plots, scalefact will increase f and decrease number of ticks.
+ f = f/scalefact;
+
+ // for large plots, smaller interval, more ticks.
+ if (f<=0.38) {
+ fact = 0.1;
+ }
+ else if (f<=1.6) {
+ fact = 0.2;
+ }
+ else if (f<=4.0) {
+ fact = 0.5;
+ }
+ else if (f<=8.0) {
+ fact = 1.0;
+ }
+ // for very small plots, larger interval, less ticks in number ticks
+ else if (f<=16.0) {
+ fact = 2;
+ }
+ else {
+ fact = 5;
+ }
+
+ return fact*magnitude;
+ }
+
+ function bestLinearComponents(range, scalefact) {
+ var expv = Math.floor(Math.log(range)/Math.LN10);
+ var magnitude = Math.pow(10, expv);
+ // 0 < f < 10
+ var f = range / magnitude;
+ var interval;
+ var fact;
+ // for large plots, scalefact will decrease f and increase number of ticks.
+ // for small plots, scalefact will increase f and decrease number of ticks.
+ f = f/scalefact;
+
+ // for large plots, smaller interval, more ticks.
+ if (f<=0.38) {
+ fact = 0.1;
+ }
+ else if (f<=1.6) {
+ fact = 0.2;
+ }
+ else if (f<=4.0) {
+ fact = 0.5;
+ }
+ else if (f<=8.0) {
+ fact = 1.0;
+ }
+ // for very small plots, larger interval, less ticks in number ticks
+ else if (f<=16.0) {
+ fact = 2;
+ }
+ // else if (f<=20.0) {
+ // fact = 3;
+ // }
+ // else if (f<=24.0) {
+ // fact = 4;
+ // }
+ else {
+ fact = 5;
+ }
+
+ interval = fact * magnitude;
+
+ return [interval, fact, magnitude];
+ }
+
+ // Given the min and max for a dataset, return suitable endpoints
+ // for the graphing, a good number for the number of ticks, and a
+ // format string so that extraneous digits are not displayed.
+ // returned is an array containing [min, max, nTicks, format]
+ $.jqplot.LinearTickGenerator = function(axis_min, axis_max, scalefact, numberTicks, keepMin, keepMax) {
+ // Set to preserve EITHER min OR max.
+ // If min is preserved, max must be free.
+ keepMin = (keepMin === null) ? false : keepMin;
+ keepMax = (keepMax === null || keepMin) ? false : keepMax;
+ // if endpoints are equal try to include zero otherwise include one
+ if (axis_min === axis_max) {
+ axis_max = (axis_max) ? 0 : 1;
+ }
+
+ scalefact = scalefact || 1.0;
+
+ // make sure range is positive
+ if (axis_max < axis_min) {
+ var a = axis_max;
+ axis_max = axis_min;
+ axis_min = a;
+ }
+
+ var r = [];
+ var ss = bestLinearInterval(axis_max - axis_min, scalefact);
+
+ var gsf = $.jqplot.getSignificantFigures;
+
+ if (numberTicks == null) {
+
+ // Figure out the axis min, max and number of ticks
+ // the min and max will be some multiple of the tick interval,
+ // 1*10^n, 2*10^n or 5*10^n. This gaurantees that, if the
+ // axis min is negative, 0 will be a tick.
+ if (!keepMin && !keepMax) {
+ r[0] = Math.floor(axis_min / ss) * ss; // min
+ r[1] = Math.ceil(axis_max / ss) * ss; // max
+ r[2] = Math.round((r[1]-r[0])/ss+1.0); // number of ticks
+ r[3] = bestFormatString(ss); // format string
+ r[4] = ss; // tick Interval
+ }
+
+ else if (keepMin) {
+ r[0] = axis_min; // min
+ r[2] = Math.ceil((axis_max - axis_min) / ss + 1.0); // number of ticks
+ r[1] = axis_min + (r[2] - 1) * ss; // max
+ var digitsMin = gsf(axis_min).digitsRight;
+ var digitsSS = gsf(ss).digitsRight;
+ if (digitsMin < digitsSS) {
+ r[3] = bestFormatString(ss); // format string
+ }
+ else {
+ r[3] = '%.' + digitsMin + 'f';
+ }
+ r[4] = ss; // tick Interval
+ }
+
+ else if (keepMax) {
+ r[1] = axis_max; // max
+ r[2] = Math.ceil((axis_max - axis_min) / ss + 1.0); // number of ticks
+ r[0] = axis_max - (r[2] - 1) * ss; // min
+ var digitsMax = gsf(axis_max).digitsRight;
+ var digitsSS = gsf(ss).digitsRight;
+ if (digitsMax < digitsSS) {
+ r[3] = bestFormatString(ss); // format string
+ }
+ else {
+ r[3] = '%.' + digitsMax + 'f';
+ }
+ r[4] = ss; // tick Interval
+ }
+ }
+
+ else {
+ var tempr = [];
+
+ // Figure out the axis min, max and number of ticks
+ // the min and max will be some multiple of the tick interval,
+ // 1*10^n, 2*10^n or 5*10^n. This gaurantees that, if the
+ // axis min is negative, 0 will be a tick.
+ tempr[0] = Math.floor(axis_min / ss) * ss; // min
+ tempr[1] = Math.ceil(axis_max / ss) * ss; // max
+ tempr[2] = Math.round((tempr[1]-tempr[0])/ss+1.0); // number of ticks
+ tempr[3] = bestFormatString(ss); // format string
+ tempr[4] = ss; // tick Interval
+
+ // first, see if we happen to get the right number of ticks
+ if (tempr[2] === numberTicks) {
+ r = tempr;
+ }
+
+ else {
+
+ var newti = bestInterval(tempr[1] - tempr[0], numberTicks);
+
+ r[0] = tempr[0]; // min
+ r[2] = numberTicks; // number of ticks
+ r[4] = newti; // tick interval
+ r[3] = bestFormatString(newti); // format string
+ r[1] = r[0] + (r[2] - 1) * r[4]; // max
+ }
+ }
+
+ return r;
+ };
+
+ $.jqplot.LinearTickGenerator.bestLinearInterval = bestLinearInterval;
+ $.jqplot.LinearTickGenerator.bestInterval = bestInterval;
+ $.jqplot.LinearTickGenerator.bestLinearComponents = bestLinearComponents;
+ $.jqplot.LinearTickGenerator.bestConstrainedInterval = bestConstrainedInterval;
+
+
+ // class: $.jqplot.MarkerRenderer
+ // The default jqPlot marker renderer, rendering the points on the line.
+ $.jqplot.MarkerRenderer = function(options){
+ // Group: Properties
+
+ // prop: show
+ // wether or not to show the marker.
+ this.show = true;
+ // prop: style
+ // One of diamond, circle, square, x, plus, dash, filledDiamond, filledCircle, filledSquare
+ this.style = 'filledCircle';
+ // prop: lineWidth
+ // size of the line for non-filled markers.
+ this.lineWidth = 2;
+ // prop: size
+ // Size of the marker (diameter or circle, length of edge of square, etc.)
+ this.size = 9.0;
+ // prop: color
+ // color of marker. Will be set to color of series by default on init.
+ this.color = '#666666';
+ // prop: shadow
+ // wether or not to draw a shadow on the line
+ this.shadow = true;
+ // prop: shadowAngle
+ // Shadow angle in degrees
+ this.shadowAngle = 45;
+ // prop: shadowOffset
+ // Shadow offset from line in pixels
+ this.shadowOffset = 1;
+ // prop: shadowDepth
+ // Number of times shadow is stroked, each stroke offset shadowOffset from the last.
+ this.shadowDepth = 3;
+ // prop: shadowAlpha
+ // Alpha channel transparency of shadow. 0 = transparent.
+ this.shadowAlpha = '0.07';
+ // prop: shadowRenderer
+ // Renderer that will draws the shadows on the marker.
+ this.shadowRenderer = new $.jqplot.ShadowRenderer();
+ // prop: shapeRenderer
+ // Renderer that will draw the marker.
+ this.shapeRenderer = new $.jqplot.ShapeRenderer();
+
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ var sdopt = {angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, lineWidth:this.lineWidth, depth:this.shadowDepth, closePath:true};
+ if (this.style.indexOf('filled') != -1) {
+ sdopt.fill = true;
+ }
+ if (this.style.indexOf('ircle') != -1) {
+ sdopt.isarc = true;
+ sdopt.closePath = false;
+ }
+ this.shadowRenderer.init(sdopt);
+
+ var shopt = {fill:false, isarc:false, strokeStyle:this.color, fillStyle:this.color, lineWidth:this.lineWidth, closePath:true};
+ if (this.style.indexOf('filled') != -1) {
+ shopt.fill = true;
+ }
+ if (this.style.indexOf('ircle') != -1) {
+ shopt.isarc = true;
+ shopt.closePath = false;
+ }
+ this.shapeRenderer.init(shopt);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawDiamond = function(x, y, ctx, fill, options) {
+ var stretch = 1.2;
+ var dx = this.size/2/stretch;
+ var dy = this.size/2*stretch;
+ var points = [[x-dx, y], [x, y+dy], [x+dx, y], [x, y-dy]];
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points);
+ }
+ this.shapeRenderer.draw(ctx, points, options);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawPlus = function(x, y, ctx, fill, options) {
+ var stretch = 1.0;
+ var dx = this.size/2*stretch;
+ var dy = this.size/2*stretch;
+ var points1 = [[x, y-dy], [x, y+dy]];
+ var points2 = [[x+dx, y], [x-dx, y]];
+ var opts = $.extend(true, {}, this.options, {closePath:false});
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points1, {closePath:false});
+ this.shadowRenderer.draw(ctx, points2, {closePath:false});
+ }
+ this.shapeRenderer.draw(ctx, points1, opts);
+ this.shapeRenderer.draw(ctx, points2, opts);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawX = function(x, y, ctx, fill, options) {
+ var stretch = 1.0;
+ var dx = this.size/2*stretch;
+ var dy = this.size/2*stretch;
+ var opts = $.extend(true, {}, this.options, {closePath:false});
+ var points1 = [[x-dx, y-dy], [x+dx, y+dy]];
+ var points2 = [[x-dx, y+dy], [x+dx, y-dy]];
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points1, {closePath:false});
+ this.shadowRenderer.draw(ctx, points2, {closePath:false});
+ }
+ this.shapeRenderer.draw(ctx, points1, opts);
+ this.shapeRenderer.draw(ctx, points2, opts);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawDash = function(x, y, ctx, fill, options) {
+ var stretch = 1.0;
+ var dx = this.size/2*stretch;
+ var dy = this.size/2*stretch;
+ var points = [[x-dx, y], [x+dx, y]];
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points);
+ }
+ this.shapeRenderer.draw(ctx, points, options);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawLine = function(p1, p2, ctx, fill, options) {
+ var points = [p1, p2];
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points);
+ }
+ this.shapeRenderer.draw(ctx, points, options);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawSquare = function(x, y, ctx, fill, options) {
+ var stretch = 1.0;
+ var dx = this.size/2/stretch;
+ var dy = this.size/2*stretch;
+ var points = [[x-dx, y-dy], [x-dx, y+dy], [x+dx, y+dy], [x+dx, y-dy]];
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points);
+ }
+ this.shapeRenderer.draw(ctx, points, options);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.drawCircle = function(x, y, ctx, fill, options) {
+ var radius = this.size/2;
+ var end = 2*Math.PI;
+ var points = [x, y, radius, 0, end, true];
+ if (this.shadow) {
+ this.shadowRenderer.draw(ctx, points);
+ }
+ this.shapeRenderer.draw(ctx, points, options);
+ };
+
+ $.jqplot.MarkerRenderer.prototype.draw = function(x, y, ctx, options) {
+ options = options || {};
+ // hack here b/c shape renderer uses canvas based color style options
+ // and marker uses css style names.
+ if (options.show == null || options.show != false) {
+ if (options.color && !options.fillStyle) {
+ options.fillStyle = options.color;
+ }
+ if (options.color && !options.strokeStyle) {
+ options.strokeStyle = options.color;
+ }
+ switch (this.style) {
+ case 'diamond':
+ this.drawDiamond(x,y,ctx, false, options);
+ break;
+ case 'filledDiamond':
+ this.drawDiamond(x,y,ctx, true, options);
+ break;
+ case 'circle':
+ this.drawCircle(x,y,ctx, false, options);
+ break;
+ case 'filledCircle':
+ this.drawCircle(x,y,ctx, true, options);
+ break;
+ case 'square':
+ this.drawSquare(x,y,ctx, false, options);
+ break;
+ case 'filledSquare':
+ this.drawSquare(x,y,ctx, true, options);
+ break;
+ case 'x':
+ this.drawX(x,y,ctx, true, options);
+ break;
+ case 'plus':
+ this.drawPlus(x,y,ctx, true, options);
+ break;
+ case 'dash':
+ this.drawDash(x,y,ctx, true, options);
+ break;
+ case 'line':
+ this.drawLine(x, y, ctx, false, options);
+ break;
+ default:
+ this.drawDiamond(x,y,ctx, false, options);
+ break;
+ }
+ }
+ };
+
+ // class: $.jqplot.shadowRenderer
+ // The default jqPlot shadow renderer, rendering shadows behind shapes.
+ $.jqplot.ShadowRenderer = function(options){
+ // Group: Properties
+
+ // prop: angle
+ // Angle of the shadow in degrees. Measured counter-clockwise from the x axis.
+ this.angle = 45;
+ // prop: offset
+ // Pixel offset at the given shadow angle of each shadow stroke from the last stroke.
+ this.offset = 1;
+ // prop: alpha
+ // alpha transparency of shadow stroke.
+ this.alpha = 0.07;
+ // prop: lineWidth
+ // width of the shadow line stroke.
+ this.lineWidth = 1.5;
+ // prop: lineJoin
+ // How line segments of the shadow are joined.
+ this.lineJoin = 'miter';
+ // prop: lineCap
+ // how ends of the shadow line are rendered.
+ this.lineCap = 'round';
+ // prop; closePath
+ // whether line path segment is closed upon itself.
+ this.closePath = false;
+ // prop: fill
+ // whether to fill the shape.
+ this.fill = false;
+ // prop: depth
+ // how many times the shadow is stroked. Each stroke will be offset by offset at angle degrees.
+ this.depth = 3;
+ this.strokeStyle = 'rgba(0,0,0,0.1)';
+ // prop: isarc
+ // wether the shadow is an arc or not.
+ this.isarc = false;
+
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.ShadowRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ };
+
+ // function: draw
+ // draws an transparent black (i.e. gray) shadow.
+ //
+ // ctx - canvas drawing context
+ // points - array of points or [x, y, radius, start angle (rad), end angle (rad)]
+ $.jqplot.ShadowRenderer.prototype.draw = function(ctx, points, options) {
+ ctx.save();
+ var opts = (options != null) ? options : {};
+ var fill = (opts.fill != null) ? opts.fill : this.fill;
+ var fillRect = (opts.fillRect != null) ? opts.fillRect : this.fillRect;
+ var closePath = (opts.closePath != null) ? opts.closePath : this.closePath;
+ var offset = (opts.offset != null) ? opts.offset : this.offset;
+ var alpha = (opts.alpha != null) ? opts.alpha : this.alpha;
+ var depth = (opts.depth != null) ? opts.depth : this.depth;
+ var isarc = (opts.isarc != null) ? opts.isarc : this.isarc;
+ var linePattern = (opts.linePattern != null) ? opts.linePattern : this.linePattern;
+ ctx.lineWidth = (opts.lineWidth != null) ? opts.lineWidth : this.lineWidth;
+ ctx.lineJoin = (opts.lineJoin != null) ? opts.lineJoin : this.lineJoin;
+ ctx.lineCap = (opts.lineCap != null) ? opts.lineCap : this.lineCap;
+ ctx.strokeStyle = opts.strokeStyle || this.strokeStyle || 'rgba(0,0,0,'+alpha+')';
+ ctx.fillStyle = opts.fillStyle || this.fillStyle || 'rgba(0,0,0,'+alpha+')';
+ for (var j=0; j<depth; j++) {
+ var ctxPattern = $.jqplot.LinePattern(ctx, linePattern);
+ ctx.translate(Math.cos(this.angle*Math.PI/180)*offset, Math.sin(this.angle*Math.PI/180)*offset);
+ ctxPattern.beginPath();
+ if (isarc) {
+ ctx.arc(points[0], points[1], points[2], points[3], points[4], true);
+ }
+ else if (fillRect) {
+ if (fillRect) {
+ ctx.fillRect(points[0], points[1], points[2], points[3]);
+ }
+ }
+ else if (points && points.length){
+ var move = true;
+ for (var i=0; i<points.length; i++) {
+ // skip to the first non-null point and move to it.
+ if (points[i][0] != null && points[i][1] != null) {
+ if (move) {
+ ctxPattern.moveTo(points[i][0], points[i][1]);
+ move = false;
+ }
+ else {
+ ctxPattern.lineTo(points[i][0], points[i][1]);
+ }
+ }
+ else {
+ move = true;
+ }
+ }
+
+ }
+ if (closePath) {
+ ctxPattern.closePath();
+ }
+ if (fill) {
+ ctx.fill();
+ }
+ else {
+ ctx.stroke();
+ }
+ }
+ ctx.restore();
+ };
+
+ // class: $.jqplot.shapeRenderer
+ // The default jqPlot shape renderer. Given a set of points will
+ // plot them and either stroke a line (fill = false) or fill them (fill = true).
+ // If a filled shape is desired, closePath = true must also be set to close
+ // the shape.
+ $.jqplot.ShapeRenderer = function(options){
+
+ this.lineWidth = 1.5;
+ // prop: linePattern
+ // line pattern 'dashed', 'dotted', 'solid', some combination
+ // of '-' and '.' characters such as '.-.' or a numerical array like
+ // [draw, skip, draw, skip, ...] such as [1, 10] to draw a dotted line,
+ // [1, 10, 20, 10] to draw a dot-dash line, and so on.
+ this.linePattern = 'solid';
+ // prop: lineJoin
+ // How line segments of the shadow are joined.
+ this.lineJoin = 'miter';
+ // prop: lineCap
+ // how ends of the shadow line are rendered.
+ this.lineCap = 'round';
+ // prop; closePath
+ // whether line path segment is closed upon itself.
+ this.closePath = false;
+ // prop: fill
+ // whether to fill the shape.
+ this.fill = false;
+ // prop: isarc
+ // wether the shadow is an arc or not.
+ this.isarc = false;
+ // prop: fillRect
+ // true to draw shape as a filled rectangle.
+ this.fillRect = false;
+ // prop: strokeRect
+ // true to draw shape as a stroked rectangle.
+ this.strokeRect = false;
+ // prop: clearRect
+ // true to cear a rectangle.
+ this.clearRect = false;
+ // prop: strokeStyle
+ // css color spec for the stoke style
+ this.strokeStyle = '#999999';
+ // prop: fillStyle
+ // css color spec for the fill style.
+ this.fillStyle = '#999999';
+
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.ShapeRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ };
+
+ // function: draw
+ // draws the shape.
+ //
+ // ctx - canvas drawing context
+ // points - array of points for shapes or
+ // [x, y, width, height] for rectangles or
+ // [x, y, radius, start angle (rad), end angle (rad)] for circles and arcs.
+ $.jqplot.ShapeRenderer.prototype.draw = function(ctx, points, options) {
+ ctx.save();
+ var opts = (options != null) ? options : {};
+ var fill = (opts.fill != null) ? opts.fill : this.fill;
+ var closePath = (opts.closePath != null) ? opts.closePath : this.closePath;
+ var fillRect = (opts.fillRect != null) ? opts.fillRect : this.fillRect;
+ var strokeRect = (opts.strokeRect != null) ? opts.strokeRect : this.strokeRect;
+ var clearRect = (opts.clearRect != null) ? opts.clearRect : this.clearRect;
+ var isarc = (opts.isarc != null) ? opts.isarc : this.isarc;
+ var linePattern = (opts.linePattern != null) ? opts.linePattern : this.linePattern;
+ var ctxPattern = $.jqplot.LinePattern(ctx, linePattern);
+ ctx.lineWidth = opts.lineWidth || this.lineWidth;
+ ctx.lineJoin = opts.lineJoin || this.lineJoin;
+ ctx.lineCap = opts.lineCap || this.lineCap;
+ ctx.strokeStyle = (opts.strokeStyle || opts.color) || this.strokeStyle;
+ ctx.fillStyle = opts.fillStyle || this.fillStyle;
+ ctx.beginPath();
+ if (isarc) {
+ ctx.arc(points[0], points[1], points[2], points[3], points[4], true);
+ if (closePath) {
+ ctx.closePath();
+ }
+ if (fill) {
+ ctx.fill();
+ }
+ else {
+ ctx.stroke();
+ }
+ ctx.restore();
+ return;
+ }
+ else if (clearRect) {
+ ctx.clearRect(points[0], points[1], points[2], points[3]);
+ ctx.restore();
+ return;
+ }
+ else if (fillRect || strokeRect) {
+ if (fillRect) {
+ ctx.fillRect(points[0], points[1], points[2], points[3]);
+ }
+ if (strokeRect) {
+ ctx.strokeRect(points[0], points[1], points[2], points[3]);
+ ctx.restore();
+ return;
+ }
+ }
+ else if (points && points.length){
+ var move = true;
+ for (var i=0; i<points.length; i++) {
+ // skip to the first non-null point and move to it.
+ if (points[i][0] != null && points[i][1] != null) {
+ if (move) {
+ ctxPattern.moveTo(points[i][0], points[i][1]);
+ move = false;
+ }
+ else {
+ ctxPattern.lineTo(points[i][0], points[i][1]);
+ }
+ }
+ else {
+ move = true;
+ }
+ }
+ if (closePath) {
+ ctxPattern.closePath();
+ }
+ if (fill) {
+ ctx.fill();
+ }
+ else {
+ ctx.stroke();
+ }
+ }
+ ctx.restore();
+ };
+
+ // class $.jqplot.TableLegendRenderer
+ // The default legend renderer for jqPlot.
+ $.jqplot.TableLegendRenderer = function(){
+ //
+ };
+
+ $.jqplot.TableLegendRenderer.prototype.init = function(options) {
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.TableLegendRenderer.prototype.addrow = function (label, color, pad, reverse) {
+ var rs = (pad) ? this.rowSpacing+'px' : '0px';
+ var tr;
+ var td;
+ var elem;
+ var div0;
+ var div1;
+ elem = document.createElement('tr');
+ tr = $(elem);
+ tr.addClass('jqplot-table-legend');
+ elem = null;
+
+ if (reverse){
+ tr.prependTo(this._elem);
+ }
+
+ else{
+ tr.appendTo(this._elem);
+ }
+
+ if (this.showSwatches) {
+ td = $(document.createElement('td'));
+ td.addClass('jqplot-table-legend jqplot-table-legend-swatch');
+ td.css({textAlign: 'center', paddingTop: rs});
+
+ div0 = $(document.createElement('div'));
+ div0.addClass('jqplot-table-legend-swatch-outline');
+ div1 = $(document.createElement('div'));
+ div1.addClass('jqplot-table-legend-swatch');
+ div1.css({backgroundColor: color, borderColor: color});
+
+ tr.append(td.append(div0.append(div1)));
+
+ // $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
+ // '<div><div class="jqplot-table-legend-swatch" style="background-color:'+color+';border-color:'+color+';"></div>'+
+ // '</div></td>').appendTo(tr);
+ }
+ if (this.showLabels) {
+ td = $(document.createElement('td'));
+ td.addClass('jqplot-table-legend jqplot-table-legend-label');
+ td.css('paddingTop', rs);
+ tr.append(td);
+
+ // elem = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
+ // elem.appendTo(tr);
+ if (this.escapeHtml) {
+ td.text(label);
+ }
+ else {
+ td.html(label);
+ }
+ }
+ td = null;
+ div0 = null;
+ div1 = null;
+ tr = null;
+ elem = null;
+ };
+
+ // called with scope of legend
+ $.jqplot.TableLegendRenderer.prototype.draw = function() {
+ if (this._elem) {
+ this._elem.emptyForce();
+ this._elem = null;
+ }
+
+ if (this.show) {
+ var series = this._series;
+ // make a table. one line label per row.
+ var elem = document.createElement('table');
+ this._elem = $(elem);
+ this._elem.addClass('jqplot-table-legend');
+
+ var ss = {position:'absolute'};
+ if (this.background) {
+ ss['background'] = this.background;
+ }
+ if (this.border) {
+ ss['border'] = this.border;
+ }
+ if (this.fontSize) {
+ ss['fontSize'] = this.fontSize;
+ }
+ if (this.fontFamily) {
+ ss['fontFamily'] = this.fontFamily;
+ }
+ if (this.textColor) {
+ ss['textColor'] = this.textColor;
+ }
+ if (this.marginTop != null) {
+ ss['marginTop'] = this.marginTop;
+ }
+ if (this.marginBottom != null) {
+ ss['marginBottom'] = this.marginBottom;
+ }
+ if (this.marginLeft != null) {
+ ss['marginLeft'] = this.marginLeft;
+ }
+ if (this.marginRight != null) {
+ ss['marginRight'] = this.marginRight;
+ }
+
+
+ var pad = false,
+ reverse = false,
+ s;
+ for (var i = 0; i< series.length; i++) {
+ s = series[i];
+ if (s._stack || s.renderer.constructor == $.jqplot.BezierCurveRenderer){
+ reverse = true;
+ }
+ if (s.show && s.showLabel) {
+ var lt = this.labels[i] || s.label.toString();
+ if (lt) {
+ var color = s.color;
+ if (reverse && i < series.length - 1){
+ pad = true;
+ }
+ else if (reverse && i == series.length - 1){
+ pad = false;
+ }
+ this.renderer.addrow.call(this, lt, color, pad, reverse);
+ pad = true;
+ }
+ // let plugins add more rows to legend. Used by trend line plugin.
+ for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) {
+ var item = $.jqplot.addLegendRowHooks[j].call(this, s);
+ if (item) {
+ this.renderer.addrow.call(this, item.label, item.color, pad);
+ pad = true;
+ }
+ }
+ lt = null;
+ }
+ }
+ }
+ return this._elem;
+ };
+
+ $.jqplot.TableLegendRenderer.prototype.pack = function(offsets) {
+ if (this.show) {
+ if (this.placement == 'insideGrid') {
+ switch (this.location) {
+ case 'nw':
+ var a = offsets.left;
+ var b = offsets.top;
+ this._elem.css('left', a);
+ this._elem.css('top', b);
+ break;
+ case 'n':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = offsets.top;
+ this._elem.css('left', a);
+ this._elem.css('top', b);
+ break;
+ case 'ne':
+ var a = offsets.right;
+ var b = offsets.top;
+ this._elem.css({right:a, top:b});
+ break;
+ case 'e':
+ var a = offsets.right;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({right:a, top:b});
+ break;
+ case 'se':
+ var a = offsets.right;
+ var b = offsets.bottom;
+ this._elem.css({right:a, bottom:b});
+ break;
+ case 's':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = offsets.bottom;
+ this._elem.css({left:a, bottom:b});
+ break;
+ case 'sw':
+ var a = offsets.left;
+ var b = offsets.bottom;
+ this._elem.css({left:a, bottom:b});
+ break;
+ case 'w':
+ var a = offsets.left;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({left:a, top:b});
+ break;
+ default: // same as 'se'
+ var a = offsets.right;
+ var b = offsets.bottom;
+ this._elem.css({right:a, bottom:b});
+ break;
+ }
+
+ }
+ else if (this.placement == 'outside'){
+ switch (this.location) {
+ case 'nw':
+ var a = this._plotDimensions.width - offsets.left;
+ var b = offsets.top;
+ this._elem.css('right', a);
+ this._elem.css('top', b);
+ break;
+ case 'n':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = this._plotDimensions.height - offsets.top;
+ this._elem.css('left', a);
+ this._elem.css('bottom', b);
+ break;
+ case 'ne':
+ var a = this._plotDimensions.width - offsets.right;
+ var b = offsets.top;
+ this._elem.css({left:a, top:b});
+ break;
+ case 'e':
+ var a = this._plotDimensions.width - offsets.right;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({left:a, top:b});
+ break;
+ case 'se':
+ var a = this._plotDimensions.width - offsets.right;
+ var b = offsets.bottom;
+ this._elem.css({left:a, bottom:b});
+ break;
+ case 's':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ var b = this._plotDimensions.height - offsets.bottom;
+ this._elem.css({left:a, top:b});
+ break;
+ case 'sw':
+ var a = this._plotDimensions.width - offsets.left;
+ var b = offsets.bottom;
+ this._elem.css({right:a, bottom:b});
+ break;
+ case 'w':
+ var a = this._plotDimensions.width - offsets.left;
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({right:a, top:b});
+ break;
+ default: // same as 'se'
+ var a = offsets.right;
+ var b = offsets.bottom;
+ this._elem.css({right:a, bottom:b});
+ break;
+ }
+ }
+ else {
+ switch (this.location) {
+ case 'nw':
+ this._elem.css({left:0, top:offsets.top});
+ break;
+ case 'n':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ this._elem.css({left: a, top:offsets.top});
+ break;
+ case 'ne':
+ this._elem.css({right:0, top:offsets.top});
+ break;
+ case 'e':
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({right:offsets.right, top:b});
+ break;
+ case 'se':
+ this._elem.css({right:offsets.right, bottom:offsets.bottom});
+ break;
+ case 's':
+ var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+ this._elem.css({left: a, bottom:offsets.bottom});
+ break;
+ case 'sw':
+ this._elem.css({left:offsets.left, bottom:offsets.bottom});
+ break;
+ case 'w':
+ var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+ this._elem.css({left:offsets.left, top:b});
+ break;
+ default: // same as 'se'
+ this._elem.css({right:offsets.right, bottom:offsets.bottom});
+ break;
+ }
+ }
+ }
+ };
+
+ /**
+ * Class: $.jqplot.ThemeEngine
+ * Theme Engine provides a programatic way to change some of the more
+ * common jqplot styling options such as fonts, colors and grid options.
+ * A theme engine instance is created with each plot. The theme engine
+ * manages a collection of themes which can be modified, added to, or
+ * applied to the plot.
+ *
+ * The themeEngine class is not instantiated directly.
+ * When a plot is initialized, the current plot options are scanned
+ * an a default theme named "Default" is created. This theme is
+ * used as the basis for other themes added to the theme engine and
+ * is always available.
+ *
+ * A theme is a simple javascript object with styling parameters for
+ * various entities of the plot. A theme has the form:
+ *
+ *
+ * > {
+ * > _name:f "Default",
+ * > target: {
+ * > backgroundColor: "transparent"
+ * > },
+ * > legend: {
+ * > textColor: null,
+ * > fontFamily: null,
+ * > fontSize: null,
+ * > border: null,
+ * > background: null
+ * > },
+ * > title: {
+ * > textColor: "rgb(102, 102, 102)",
+ * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif",
+ * > fontSize: "19.2px",
+ * > textAlign: "center"
+ * > },
+ * > seriesStyles: {},
+ * > series: [{
+ * > color: "#4bb2c5",
+ * > lineWidth: 2.5,
+ * > linePattern: "solid",
+ * > shadow: true,
+ * > fillColor: "#4bb2c5",
+ * > showMarker: true,
+ * > markerOptions: {
+ * > color: "#4bb2c5",
+ * > show: true,
+ * > style: 'filledCircle',
+ * > lineWidth: 1.5,
+ * > size: 4,
+ * > shadow: true
+ * > }
+ * > }],
+ * > grid: {
+ * > drawGridlines: true,
+ * > gridLineColor: "#cccccc",
+ * > gridLineWidth: 1,
+ * > backgroundColor: "#fffdf6",
+ * > borderColor: "#999999",
+ * > borderWidth: 2,
+ * > shadow: true
+ * > },
+ * > axesStyles: {
+ * > label: {},
+ * > ticks: {}
+ * > },
+ * > axes: {
+ * > xaxis: {
+ * > borderColor: "#999999",
+ * > borderWidth: 2,
+ * > ticks: {
+ * > show: true,
+ * > showGridline: true,
+ * > showLabel: true,
+ * > showMark: true,
+ * > size: 4,
+ * > textColor: "",
+ * > whiteSpace: "nowrap",
+ * > fontSize: "12px",
+ * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif"
+ * > },
+ * > label: {
+ * > textColor: "rgb(102, 102, 102)",
+ * > whiteSpace: "normal",
+ * > fontSize: "14.6667px",
+ * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif",
+ * > fontWeight: "400"
+ * > }
+ * > },
+ * > yaxis: {
+ * > borderColor: "#999999",
+ * > borderWidth: 2,
+ * > ticks: {
+ * > show: true,
+ * > showGridline: true,
+ * > showLabel: true,
+ * > showMark: true,
+ * > size: 4,
+ * > textColor: "",
+ * > whiteSpace: "nowrap",
+ * > fontSize: "12px",
+ * > fontFamily: "'Trebuchet MS',Arial,Helvetica,sans-serif"
+ * > },
+ * > label: {
+ * > textColor: null,
+ * > whiteSpace: null,
+ * > fontSize: null,
+ * > fontFamily: null,
+ * > fontWeight: null
+ * > }
+ * > },
+ * > x2axis: {...
+ * > },
+ * > ...
+ * > y9axis: {...
+ * > }
+ * > }
+ * > }
+ *
+ * "seriesStyles" is a style object that will be applied to all series in the plot.
+ * It will forcibly override any styles applied on the individual series. "axesStyles" is
+ * a style object that will be applied to all axes in the plot. It will also forcibly
+ * override any styles on the individual axes.
+ *
+ * The example shown above has series options for a line series. Options for other
+ * series types are shown below:
+ *
+ * Bar Series:
+ *
+ * > {
+ * > color: "#4bb2c5",
+ * > seriesColors: ["#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"],
+ * > lineWidth: 2.5,
+ * > shadow: true,
+ * > barPadding: 2,
+ * > barMargin: 10,
+ * > barWidth: 15.09375,
+ * > highlightColors: ["rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)", "rgb(129,201,214)"]
+ * > }
+ *
+ * Pie Series:
+ *
+ * > {
+ * > seriesColors: ["#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"],
+ * > padding: 20,
+ * > sliceMargin: 0,
+ * > fill: true,
+ * > shadow: true,
+ * > startAngle: 0,
+ * > lineWidth: 2.5,
+ * > highlightColors: ["rgb(129,201,214)", "rgb(240,189,104)", "rgb(214,202,165)", "rgb(137,180,158)", "rgb(168,180,137)", "rgb(180,174,89)", "rgb(180,113,161)", "rgb(129,141,236)", "rgb(227,205,120)", "rgb(255,138,76)", "rgb(76,169,219)", "rgb(215,126,190)", "rgb(220,232,135)", "rgb(200,167,96)", "rgb(103,202,235)", "rgb(208,154,215)"]
+ * > }
+ *
+ * Funnel Series:
+ *
+ * > {
+ * > color: "#4bb2c5",
+ * > lineWidth: 2,
+ * > shadow: true,
+ * > padding: {
+ * > top: 20,
+ * > right: 20,
+ * > bottom: 20,
+ * > left: 20
+ * > },
+ * > sectionMargin: 6,
+ * > seriesColors: ["#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"],
+ * > highlightColors: ["rgb(147,208,220)", "rgb(242,199,126)", "rgb(220,210,178)", "rgb(154,191,172)", "rgb(180,191,154)", "rgb(191,186,112)", "rgb(191,133,174)", "rgb(147,157,238)", "rgb(231,212,139)", "rgb(255,154,102)", "rgb(102,181,224)", "rgb(221,144,199)", "rgb(225,235,152)", "rgb(200,167,96)", "rgb(124,210,238)", "rgb(215,169,221)"]
+ * > }
+ *
+ */
+ $.jqplot.ThemeEngine = function(){
+ // Group: Properties
+ //
+ // prop: themes
+ // hash of themes managed by the theme engine.
+ // Indexed by theme name.
+ this.themes = {};
+ // prop: activeTheme
+ // Pointer to currently active theme
+ this.activeTheme=null;
+
+ };
+
+ // called with scope of plot
+ $.jqplot.ThemeEngine.prototype.init = function() {
+ // get the Default theme from the current plot settings.
+ var th = new $.jqplot.Theme({_name:'Default'});
+ var n, i, nn;
+
+ for (n in th.target) {
+ if (n == "textColor") {
+ th.target[n] = this.target.css('color');
+ }
+ else {
+ th.target[n] = this.target.css(n);
+ }
+ }
+
+ if (this.title.show && this.title._elem) {
+ for (n in th.title) {
+ if (n == "textColor") {
+ th.title[n] = this.title._elem.css('color');
+ }
+ else {
+ th.title[n] = this.title._elem.css(n);
+ }
+ }
+ }
+
+ for (n in th.grid) {
+ th.grid[n] = this.grid[n];
+ }
+ if (th.grid.backgroundColor == null && this.grid.background != null) {
+ th.grid.backgroundColor = this.grid.background;
+ }
+ if (this.legend.show && this.legend._elem) {
+ for (n in th.legend) {
+ if (n == 'textColor') {
+ th.legend[n] = this.legend._elem.css('color');
+ }
+ else {
+ th.legend[n] = this.legend._elem.css(n);
+ }
+ }
+ }
+ var s;
+
+ for (i=0; i<this.series.length; i++) {
+ s = this.series[i];
+ if (s.renderer.constructor == $.jqplot.LineRenderer) {
+ th.series.push(new LineSeriesProperties());
+ }
+ else if (s.renderer.constructor == $.jqplot.BarRenderer) {
+ th.series.push(new BarSeriesProperties());
+ }
+ else if (s.renderer.constructor == $.jqplot.PieRenderer) {
+ th.series.push(new PieSeriesProperties());
+ }
+ else if (s.renderer.constructor == $.jqplot.DonutRenderer) {
+ th.series.push(new DonutSeriesProperties());
+ }
+ else if (s.renderer.constructor == $.jqplot.FunnelRenderer) {
+ th.series.push(new FunnelSeriesProperties());
+ }
+ else if (s.renderer.constructor == $.jqplot.MeterGaugeRenderer) {
+ th.series.push(new MeterSeriesProperties());
+ }
+ else {
+ th.series.push({});
+ }
+ for (n in th.series[i]) {
+ th.series[i][n] = s[n];
+ }
+ }
+ var a, ax;
+ for (n in this.axes) {
+ ax = this.axes[n];
+ a = th.axes[n] = new AxisProperties();
+ a.borderColor = ax.borderColor;
+ a.borderWidth = ax.borderWidth;
+ if (ax._ticks && ax._ticks[0]) {
+ for (nn in a.ticks) {
+ if (ax._ticks[0].hasOwnProperty(nn)) {
+ a.ticks[nn] = ax._ticks[0][nn];
+ }
+ else if (ax._ticks[0]._elem){
+ a.ticks[nn] = ax._ticks[0]._elem.css(nn);
+ }
+ }
+ }
+ if (ax._label && ax._label.show) {
+ for (nn in a.label) {
+ // a.label[nn] = ax._label._elem.css(nn);
+ if (ax._label[nn]) {
+ a.label[nn] = ax._label[nn];
+ }
+ else if (ax._label._elem){
+ if (nn == 'textColor') {
+ a.label[nn] = ax._label._elem.css('color');
+ }
+ else {
+ a.label[nn] = ax._label._elem.css(nn);
+ }
+ }
+ }
+ }
+ }
+ this.themeEngine._add(th);
+ this.themeEngine.activeTheme = this.themeEngine.themes[th._name];
+ };
+ /**
+ * Group: methods
+ *
+ * method: get
+ *
+ * Get and return the named theme or the active theme if no name given.
+ *
+ * parameter:
+ *
+ * name - name of theme to get.
+ *
+ * returns:
+ *
+ * Theme instance of given name.
+ */
+ $.jqplot.ThemeEngine.prototype.get = function(name) {
+ if (!name) {
+ // return the active theme
+ return this.activeTheme;
+ }
+ else {
+ return this.themes[name];
+ }
+ };
+
+ function numericalOrder(a,b) { return a-b; }
+
+ /**
+ * method: getThemeNames
+ *
+ * Return the list of theme names in this manager in alpha-numerical order.
+ *
+ * parameter:
+ *
+ * None
+ *
+ * returns:
+ *
+ * A the list of theme names in this manager in alpha-numerical order.
+ */
+ $.jqplot.ThemeEngine.prototype.getThemeNames = function() {
+ var tn = [];
+ for (var n in this.themes) {
+ tn.push(n);
+ }
+ return tn.sort(numericalOrder);
+ };
+
+ /**
+ * method: getThemes
+ *
+ * Return a list of themes in alpha-numerical order by name.
+ *
+ * parameter:
+ *
+ * None
+ *
+ * returns:
+ *
+ * A list of themes in alpha-numerical order by name.
+ */
+ $.jqplot.ThemeEngine.prototype.getThemes = function() {
+ var tn = [];
+ var themes = [];
+ for (var n in this.themes) {
+ tn.push(n);
+ }
+ tn.sort(numericalOrder);
+ for (var i=0; i<tn.length; i++) {
+ themes.push(this.themes[tn[i]]);
+ }
+ return themes;
+ };
+
+ $.jqplot.ThemeEngine.prototype.activate = function(plot, name) {
+ // sometimes need to redraw whole plot.
+ var redrawPlot = false;
+ if (!name && this.activeTheme && this.activeTheme._name) {
+ name = this.activeTheme._name;
+ }
+ if (!this.themes.hasOwnProperty(name)) {
+ throw new Error("No theme of that name");
+ }
+ else {
+ var th = this.themes[name];
+ this.activeTheme = th;
+ var val, checkBorderColor = false, checkBorderWidth = false;
+ var arr = ['xaxis', 'x2axis', 'yaxis', 'y2axis'];
+
+ for (i=0; i<arr.length; i++) {
+ var ax = arr[i];
+ if (th.axesStyles.borderColor != null) {
+ plot.axes[ax].borderColor = th.axesStyles.borderColor;
+ }
+ if (th.axesStyles.borderWidth != null) {
+ plot.axes[ax].borderWidth = th.axesStyles.borderWidth;
+ }
+ }
+
+ for (var axname in plot.axes) {
+ var axis = plot.axes[axname];
+ if (axis.show) {
+ var thaxis = th.axes[axname] || {};
+ var thaxstyle = th.axesStyles;
+ var thax = $.jqplot.extend(true, {}, thaxis, thaxstyle);
+ val = (th.axesStyles.borderColor != null) ? th.axesStyles.borderColor : thax.borderColor;
+ if (thax.borderColor != null) {
+ axis.borderColor = thax.borderColor;
+ redrawPlot = true;
+ }
+ val = (th.axesStyles.borderWidth != null) ? th.axesStyles.borderWidth : thax.borderWidth;
+ if (thax.borderWidth != null) {
+ axis.borderWidth = thax.borderWidth;
+ redrawPlot = true;
+ }
+ if (axis._ticks && axis._ticks[0]) {
+ for (var nn in thax.ticks) {
+ // val = null;
+ // if (th.axesStyles.ticks && th.axesStyles.ticks[nn] != null) {
+ // val = th.axesStyles.ticks[nn];
+ // }
+ // else if (thax.ticks[nn] != null){
+ // val = thax.ticks[nn]
+ // }
+ val = thax.ticks[nn];
+ if (val != null) {
+ axis.tickOptions[nn] = val;
+ axis._ticks = [];
+ redrawPlot = true;
+ }
+ }
+ }
+ if (axis._label && axis._label.show) {
+ for (var nn in thax.label) {
+ // val = null;
+ // if (th.axesStyles.label && th.axesStyles.label[nn] != null) {
+ // val = th.axesStyles.label[nn];
+ // }
+ // else if (thax.label && thax.label[nn] != null){
+ // val = thax.label[nn]
+ // }
+ val = thax.label[nn];
+ if (val != null) {
+ axis.labelOptions[nn] = val;
+ redrawPlot = true;
+ }
+ }
+ }
+
+ }
+ }
+
+ for (var n in th.grid) {
+ if (th.grid[n] != null) {
+ plot.grid[n] = th.grid[n];
+ }
+ }
+ if (!redrawPlot) {
+ plot.grid.draw();
+ }
+
+ if (plot.legend.show) {
+ for (n in th.legend) {
+ if (th.legend[n] != null) {
+ plot.legend[n] = th.legend[n];
+ }
+ }
+ }
+ if (plot.title.show) {
+ for (n in th.title) {
+ if (th.title[n] != null) {
+ plot.title[n] = th.title[n];
+ }
+ }
+ }
+
+ var i;
+ for (i=0; i<th.series.length; i++) {
+ var opts = {};
+ var redrawSeries = false;
+ for (n in th.series[i]) {
+ val = (th.seriesStyles[n] != null) ? th.seriesStyles[n] : th.series[i][n];
+ if (val != null) {
+ opts[n] = val;
+ if (n == 'color') {
+ plot.series[i].renderer.shapeRenderer.fillStyle = val;
+ plot.series[i].renderer.shapeRenderer.strokeStyle = val;
+ plot.series[i][n] = val;
+ }
+ else if ((n == 'lineWidth') || (n == 'linePattern')) {
+ plot.series[i].renderer.shapeRenderer[n] = val;
+ plot.series[i][n] = val;
+ }
+ else if (n == 'markerOptions') {
+ merge (plot.series[i].markerOptions, val);
+ merge (plot.series[i].markerRenderer, val);
+ }
+ else {
+ plot.series[i][n] = val;
+ }
+ redrawPlot = true;
+ }
+ }
+ }
+
+ if (redrawPlot) {
+ plot.target.empty();
+ plot.draw();
+ }
+
+ for (n in th.target) {
+ if (th.target[n] != null) {
+ plot.target.css(n, th.target[n]);
+ }
+ }
+ }
+
+ };
+
+ $.jqplot.ThemeEngine.prototype._add = function(theme, name) {
+ if (name) {
+ theme._name = name;
+ }
+ if (!theme._name) {
+ theme._name = Date.parse(new Date());
+ }
+ if (!this.themes.hasOwnProperty(theme._name)) {
+ this.themes[theme._name] = theme;
+ }
+ else {
+ throw new Error("jqplot.ThemeEngine Error: Theme already in use");
+ }
+ };
+
+ // method remove
+ // Delete the named theme, return true on success, false on failure.
+
+
+ /**
+ * method: remove
+ *
+ * Remove the given theme from the themeEngine.
+ *
+ * parameters:
+ *
+ * name - name of the theme to remove.
+ *
+ * returns:
+ *
+ * true on success, false on failure.
+ */
+ $.jqplot.ThemeEngine.prototype.remove = function(name) {
+ if (name == 'Default') {
+ return false;
+ }
+ return delete this.themes[name];
+ };
+
+ /**
+ * method: newTheme
+ *
+ * Create a new theme based on the default theme, adding it the themeEngine.
+ *
+ * parameters:
+ *
+ * name - name of the new theme.
+ * obj - optional object of styles to be applied to this new theme.
+ *
+ * returns:
+ *
+ * new Theme object.
+ */
+ $.jqplot.ThemeEngine.prototype.newTheme = function(name, obj) {
+ if (typeof(name) == 'object') {
+ obj = obj || name;
+ name = null;
+ }
+ if (obj && obj._name) {
+ name = obj._name;
+ }
+ else {
+ name = name || Date.parse(new Date());
+ }
+ // var th = new $.jqplot.Theme(name);
+ var th = this.copy(this.themes['Default']._name, name);
+ $.jqplot.extend(th, obj);
+ return th;
+ };
+
+ // function clone(obj) {
+ // return eval(obj.toSource());
+ // }
+
+ function clone(obj){
+ if(obj == null || typeof(obj) != 'object'){
+ return obj;
+ }
+
+ var temp = new obj.constructor();
+ for(var key in obj){
+ temp[key] = clone(obj[key]);
+ }
+ return temp;
+ }
+
+ $.jqplot.clone = clone;
+
+ function merge(obj1, obj2) {
+ if (obj2 == null || typeof(obj2) != 'object') {
+ return;
+ }
+ for (var key in obj2) {
+ if (key == 'highlightColors') {
+ obj1[key] = clone(obj2[key]);
+ }
+ if (obj2[key] != null && typeof(obj2[key]) == 'object') {
+ if (!obj1.hasOwnProperty(key)) {
+ obj1[key] = {};
+ }
+ merge(obj1[key], obj2[key]);
+ }
+ else {
+ obj1[key] = obj2[key];
+ }
+ }
+ }
+
+ $.jqplot.merge = merge;
+
+ // Use the jQuery 1.3.2 extend function since behaviour in jQuery 1.4 seems problematic
+ $.jqplot.extend = function() {
+ // copy reference to target object
+ var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !toString.call(target) === "[object Function]" ) {
+ target = {};
+ }
+
+ for ( ; i < length; i++ ){
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( var name in options ) {
+ var src = target[ name ], copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging object values
+ if ( deep && copy && typeof copy === "object" && !copy.nodeType ) {
+ target[ name ] = $.jqplot.extend( deep,
+ // Never move original objects, clone them
+ src || ( copy.length != null ? [ ] : { } )
+ , copy );
+ }
+ // Don't bring in undefined values
+ else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+ // Return the modified object
+ return target;
+ };
+
+ /**
+ * method: rename
+ *
+ * Rename a theme.
+ *
+ * parameters:
+ *
+ * oldName - current name of the theme.
+ * newName - desired name of the theme.
+ *
+ * returns:
+ *
+ * new Theme object.
+ */
+ $.jqplot.ThemeEngine.prototype.rename = function (oldName, newName) {
+ if (oldName == 'Default' || newName == 'Default') {
+ throw new Error ("jqplot.ThemeEngine Error: Cannot rename from/to Default");
+ }
+ if (this.themes.hasOwnProperty(newName)) {
+ throw new Error ("jqplot.ThemeEngine Error: New name already in use.");
+ }
+ else if (this.themes.hasOwnProperty(oldName)) {
+ var th = this.copy (oldName, newName);
+ this.remove(oldName);
+ return th;
+ }
+ throw new Error("jqplot.ThemeEngine Error: Old name or new name invalid");
+ };
+
+ /**
+ * method: copy
+ *
+ * Create a copy of an existing theme in the themeEngine, adding it the themeEngine.
+ *
+ * parameters:
+ *
+ * sourceName - name of the existing theme.
+ * targetName - name of the copy.
+ * obj - optional object of style parameter to apply to the new theme.
+ *
+ * returns:
+ *
+ * new Theme object.
+ */
+ $.jqplot.ThemeEngine.prototype.copy = function (sourceName, targetName, obj) {
+ if (targetName == 'Default') {
+ throw new Error ("jqplot.ThemeEngine Error: Cannot copy over Default theme");
+ }
+ if (!this.themes.hasOwnProperty(sourceName)) {
+ var s = "jqplot.ThemeEngine Error: Source name invalid";
+ throw new Error(s);
+ }
+ if (this.themes.hasOwnProperty(targetName)) {
+ var s = "jqplot.ThemeEngine Error: Target name invalid";
+ throw new Error(s);
+ }
+ else {
+ var th = clone(this.themes[sourceName]);
+ th._name = targetName;
+ $.jqplot.extend(true, th, obj);
+ this._add(th);
+ return th;
+ }
+ };
+
+
+ $.jqplot.Theme = function(name, obj) {
+ if (typeof(name) == 'object') {
+ obj = obj || name;
+ name = null;
+ }
+ name = name || Date.parse(new Date());
+ this._name = name;
+ this.target = {
+ backgroundColor: null
+ };
+ this.legend = {
+ textColor: null,
+ fontFamily: null,
+ fontSize: null,
+ border: null,
+ background: null
+ };
+ this.title = {
+ textColor: null,
+ fontFamily: null,
+ fontSize: null,
+ textAlign: null
+ };
+ this.seriesStyles = {};
+ this.series = [];
+ this.grid = {
+ drawGridlines: null,
+ gridLineColor: null,
+ gridLineWidth: null,
+ backgroundColor: null,
+ borderColor: null,
+ borderWidth: null,
+ shadow: null
+ };
+ this.axesStyles = {label:{}, ticks:{}};
+ this.axes = {};
+ if (typeof(obj) == 'string') {
+ this._name = obj;
+ }
+ else if(typeof(obj) == 'object') {
+ $.jqplot.extend(true, this, obj);
+ }
+ };
+
+ var AxisProperties = function() {
+ this.borderColor = null;
+ this.borderWidth = null;
+ this.ticks = new AxisTicks();
+ this.label = new AxisLabel();
+ };
+
+ var AxisTicks = function() {
+ this.show = null;
+ this.showGridline = null;
+ this.showLabel = null;
+ this.showMark = null;
+ this.size = null;
+ this.textColor = null;
+ this.whiteSpace = null;
+ this.fontSize = null;
+ this.fontFamily = null;
+ };
+
+ var AxisLabel = function() {
+ this.textColor = null;
+ this.whiteSpace = null;
+ this.fontSize = null;
+ this.fontFamily = null;
+ this.fontWeight = null;
+ };
+
+ var LineSeriesProperties = function() {
+ this.color=null;
+ this.lineWidth=null;
+ this.linePattern=null;
+ this.shadow=null;
+ this.fillColor=null;
+ this.showMarker=null;
+ this.markerOptions = new MarkerOptions();
+ };
+
+ var MarkerOptions = function() {
+ this.show = null;
+ this.style = null;
+ this.lineWidth = null;
+ this.size = null;
+ this.color = null;
+ this.shadow = null;
+ };
+
+ var BarSeriesProperties = function() {
+ this.color=null;
+ this.seriesColors=null;
+ this.lineWidth=null;
+ this.shadow=null;
+ this.barPadding=null;
+ this.barMargin=null;
+ this.barWidth=null;
+ this.highlightColors=null;
+ };
+
+ var PieSeriesProperties = function() {
+ this.seriesColors=null;
+ this.padding=null;
+ this.sliceMargin=null;
+ this.fill=null;
+ this.shadow=null;
+ this.startAngle=null;
+ this.lineWidth=null;
+ this.highlightColors=null;
+ };
+
+ var DonutSeriesProperties = function() {
+ this.seriesColors=null;
+ this.padding=null;
+ this.sliceMargin=null;
+ this.fill=null;
+ this.shadow=null;
+ this.startAngle=null;
+ this.lineWidth=null;
+ this.innerDiameter=null;
+ this.thickness=null;
+ this.ringMargin=null;
+ this.highlightColors=null;
+ };
+
+ var FunnelSeriesProperties = function() {
+ this.color=null;
+ this.lineWidth=null;
+ this.shadow=null;
+ this.padding=null;
+ this.sectionMargin=null;
+ this.seriesColors=null;
+ this.highlightColors=null;
+ };
+
+ var MeterSeriesProperties = function() {
+ this.padding=null;
+ this.backgroundColor=null;
+ this.ringColor=null;
+ this.tickColor=null;
+ this.ringWidth=null;
+ this.intervalColors=null;
+ this.intervalInnerRadius=null;
+ this.intervalOuterRadius=null;
+ this.hubRadius=null;
+ this.needleThickness=null;
+ this.needlePad=null;
+ };
+
+
+
+
+ $.fn.jqplotChildText = function() {
+ return $(this).contents().filter(function() {
+ return this.nodeType == 3; // Node.TEXT_NODE not defined in I7
+ }).text();
+ };
+
+ // Returns font style as abbreviation for "font" property.
+ $.fn.jqplotGetComputedFontStyle = function() {
+ var css = window.getComputedStyle ? window.getComputedStyle(this[0], "") : this[0].currentStyle;
+ var attrs = css['font-style'] ? ['font-style', 'font-weight', 'font-size', 'font-family'] : ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily'];
+ var style = [];
+
+ for (var i=0 ; i < attrs.length; ++i) {
+ var attr = String(css[attrs[i]]);
+
+ if (attr && attr != 'normal') {
+ style.push(attr);
+ }
+ }
+ return style.join(' ');
+ };
+
+ /**
+ * Namespace: $.fn
+ * jQuery namespace to attach functions to jQuery elements.
+ *
+ */
+
+ $.fn.jqplotToImageCanvas = function(options) {
+
+ options = options || {};
+ var x_offset = (options.x_offset == null) ? 0 : options.x_offset;
+ var y_offset = (options.y_offset == null) ? 0 : options.y_offset;
+ var backgroundColor = (options.backgroundColor == null) ? 'rgb(255,255,255)' : options.backgroundColor;
+
+ if ($(this).width() == 0 || $(this).height() == 0) {
+ return null;
+ }
+
+ // excanvas and hence IE < 9 do not support toDataURL and cannot export images.
+ if ($.jqplot.use_excanvas) {
+ return null;
+ }
+
+ var newCanvas = document.createElement("canvas");
+ var h = $(this).outerHeight(true);
+ var w = $(this).outerWidth(true);
+ var offs = $(this).offset();
+ var plotleft = offs.left;
+ var plottop = offs.top;
+ var transx = 0, transy = 0;
+
+ // have to check if any elements are hanging outside of plot area before rendering,
+ // since changing width of canvas will erase canvas.
+
+ var clses = ['jqplot-table-legend', 'jqplot-xaxis-tick', 'jqplot-x2axis-tick', 'jqplot-yaxis-tick', 'jqplot-y2axis-tick', 'jqplot-y3axis-tick',
+ 'jqplot-y4axis-tick', 'jqplot-y5axis-tick', 'jqplot-y6axis-tick', 'jqplot-y7axis-tick', 'jqplot-y8axis-tick', 'jqplot-y9axis-tick',
+ 'jqplot-xaxis-label', 'jqplot-x2axis-label', 'jqplot-yaxis-label', 'jqplot-y2axis-label', 'jqplot-y3axis-label', 'jqplot-y4axis-label',
+ 'jqplot-y5axis-label', 'jqplot-y6axis-label', 'jqplot-y7axis-label', 'jqplot-y8axis-label', 'jqplot-y9axis-label' ];
+
+ var temptop, templeft, tempbottom, tempright;
+
+ for (var i = 0; i < clses.length; i++) {
+ $(this).find('.'+clses[i]).each(function() {
+ temptop = $(this).offset().top - plottop;
+ templeft = $(this).offset().left - plotleft;
+ tempright = templeft + $(this).outerWidth(true) + transx;
+ tempbottom = temptop + $(this).outerHeight(true) + transy;
+ if (templeft < -transx) {
+ w = w - transx - templeft;
+ transx = -templeft;
+ }
+ if (temptop < -transy) {
+ h = h - transy - temptop;
+ transy = - temptop;
+ }
+ if (tempright > w) {
+ w = tempright;
+ }
+ if (tempbottom > h) {
+ h = tempbottom;
+ }
+ });
+ }
+
+ newCanvas.width = w + Number(x_offset);
+ newCanvas.height = h + Number(y_offset);
+
+ var newContext = newCanvas.getContext("2d");
+
+ newContext.save();
+ newContext.fillStyle = backgroundColor;
+ newContext.fillRect(0,0, newCanvas.width, newCanvas.height);
+ newContext.restore();
+
+ newContext.translate(transx, transy);
+ newContext.textAlign = 'left';
+ newContext.textBaseline = 'top';
+
+ function getLineheight(el) {
+ var lineheight = parseInt($(el).css('line-height'), 10);
+
+ if (isNaN(lineheight)) {
+ lineheight = parseInt($(el).css('font-size'), 10) * 1.2;
+ }
+ return lineheight;
+ }
+
+ function writeWrappedText (el, context, text, left, top, canvasWidth) {
+ var lineheight = getLineheight(el);
+ var tagwidth = $(el).innerWidth();
+ var tagheight = $(el).innerHeight();
+ var words = text.split(/\s+/);
+ var wl = words.length;
+ var w = '';
+ var breaks = [];
+ var temptop = top;
+ var templeft = left;
+
+ for (var i=0; i<wl; i++) {
+ w += words[i];
+ if (context.measureText(w).width > tagwidth) {
+ breaks.push(i);
+ w = '';
+ i--;
+ }
+ }
+ if (breaks.length === 0) {
+ // center text if necessary
+ if ($(el).css('textAlign') === 'center') {
+ templeft = left + (canvasWidth - context.measureText(w).width)/2 - transx;
+ }
+ context.fillText(text, templeft, top);
+ }
+ else {
+ w = words.slice(0, breaks[0]).join(' ');
+ // center text if necessary
+ if ($(el).css('textAlign') === 'center') {
+ templeft = left + (canvasWidth - context.measureText(w).width)/2 - transx;
+ }
+ context.fillText(w, templeft, temptop);
+ temptop += lineheight;
+ for (var i=1, l=breaks.length; i<l; i++) {
+ w = words.slice(breaks[i-1], breaks[i]).join(' ');
+ // center text if necessary
+ if ($(el).css('textAlign') === 'center') {
+ templeft = left + (canvasWidth - context.measureText(w).width)/2 - transx;
+ }
+ context.fillText(w, templeft, temptop);
+ temptop += lineheight;
+ }
+ w = words.slice(breaks[i-1], words.length).join(' ');
+ // center text if necessary
+ if ($(el).css('textAlign') === 'center') {
+ templeft = left + (canvasWidth - context.measureText(w).width)/2 - transx;
+ }
+ context.fillText(w, templeft, temptop);
+ }
+
+ }
+
+ function _jqpToImage(el, x_offset, y_offset) {
+ var tagname = el.tagName.toLowerCase();
+ var p = $(el).position();
+ var css = window.getComputedStyle ? window.getComputedStyle(el, "") : el.currentStyle; // for IE < 9
+ var left = x_offset + p.left + parseInt(css.marginLeft, 10) + parseInt(css.borderLeftWidth, 10) + parseInt(css.paddingLeft, 10);
+ var top = y_offset + p.top + parseInt(css.marginTop, 10) + parseInt(css.borderTopWidth, 10)+ parseInt(css.paddingTop, 10);
+ var w = newCanvas.width;
+ // var left = x_offset + p.left + $(el).css('marginLeft') + $(el).css('borderLeftWidth')
+
+ // somehow in here, for divs within divs, the width of the inner div should be used instead of the canvas.
+
+ if ((tagname == 'div' || tagname == 'span') && !$(el).hasClass('jqplot-highlighter-tooltip')) {
+ $(el).children().each(function() {
+ _jqpToImage(this, left, top);
+ });
+ var text = $(el).jqplotChildText();
+
+ if (text) {
+ newContext.font = $(el).jqplotGetComputedFontStyle();
+ newContext.fillStyle = $(el).css('color');
+
+ writeWrappedText(el, newContext, text, left, top, w);
+ }
+ }
+
+ // handle the standard table legend
+
+ else if (tagname === 'table' && $(el).hasClass('jqplot-table-legend')) {
+ newContext.strokeStyle = $(el).css('border-top-color');
+ newContext.fillStyle = $(el).css('background-color');
+ newContext.fillRect(left, top, $(el).innerWidth(), $(el).innerHeight());
+ if (parseInt($(el).css('border-top-width'), 10) > 0) {
+ newContext.strokeRect(left, top, $(el).innerWidth(), $(el).innerHeight());
+ }
+
+ // find all the swatches
+ $(el).find('div.jqplot-table-legend-swatch-outline').each(function() {
+ // get the first div and stroke it
+ var elem = $(this);
+ newContext.strokeStyle = elem.css('border-top-color');
+ var l = left + elem.position().left;
+ var t = top + elem.position().top;
+ newContext.strokeRect(l, t, elem.innerWidth(), elem.innerHeight());
+
+ // now fill the swatch
+
+ l += parseInt(elem.css('padding-left'), 10);
+ t += parseInt(elem.css('padding-top'), 10);
+ var h = elem.innerHeight() - 2 * parseInt(elem.css('padding-top'), 10);
+ var w = elem.innerWidth() - 2 * parseInt(elem.css('padding-left'), 10);
+
+ var swatch = elem.children('div.jqplot-table-legend-swatch');
+ newContext.fillStyle = swatch.css('background-color');
+ newContext.fillRect(l, t, w, h);
+ });
+
+ // now add text
+
+ $(el).find('td.jqplot-table-legend-label').each(function(){
+ var elem = $(this);
+ var l = left + elem.position().left;
+ var t = top + elem.position().top + parseInt(elem.css('padding-top'), 10);
+ newContext.font = elem.jqplotGetComputedFontStyle();
+ newContext.fillStyle = elem.css('color');
+ writeWrappedText(elem, newContext, elem.text(), l, t, w);
+ });
+
+ var elem = null;
+ }
+
+ else if (tagname == 'canvas') {
+ newContext.drawImage(el, left, top);
+ }
+ }
+ $(this).children().each(function() {
+ _jqpToImage(this, x_offset, y_offset);
+ });
+ return newCanvas;
+ };
+
+ // return the raw image data string.
+ // Should work on canvas supporting browsers.
+ $.fn.jqplotToImageStr = function(options) {
+ var imgCanvas = $(this).jqplotToImageCanvas(options);
+ if (imgCanvas) {
+ return imgCanvas.toDataURL("image/png");
+ }
+ else {
+ return null;
+ }
+ };
+
+ // return a DOM <img> element and return it.
+ // Should work on canvas supporting browsers.
+ $.fn.jqplotToImageElem = function(options) {
+ var elem = document.createElement("img");
+ var str = $(this).jqplotToImageStr(options);
+ elem.src = str;
+ return elem;
+ };
+
+ // return a string for an <img> element and return it.
+ // Should work on canvas supporting browsers.
+ $.fn.jqplotToImageElemStr = function(options) {
+ var str = '<img src='+$(this).jqplotToImageStr(options)+' />';
+ return str;
+ };
+
+ // Not gauranteed to work, even on canvas supporting browsers due to
+ // limitations with location.href and browser support.
+ $.fn.jqplotSaveImage = function() {
+ var imgData = $(this).jqplotToImageStr({});
+ if (imgData) {
+ window.location.href = imgData.replace("image/png", "image/octet-stream");
+ }
+
+ };
+
+ // Not gauranteed to work, even on canvas supporting browsers due to
+ // limitations with window.open and arbitrary data.
+ $.fn.jqplotViewImage = function() {
+ var imgStr = $(this).jqplotToImageElemStr({});
+ var imgData = $(this).jqplotToImageStr({});
+ if (imgStr) {
+ var w = window.open('');
+ w.document.open("image/png");
+ w.document.write(imgStr);
+ w.document.close();
+ w = null;
+ }
+ };
+
+
+
+
+ /**
+ * @description
+ * <p>Object with extended date parsing and formatting capabilities.
+ * This library borrows many concepts and ideas from the Date Instance
+ * Methods by Ken Snyder along with some parts of Ken's actual code.</p>
+ *
+ * <p>jsDate takes a different approach by not extending the built-in
+ * Date Object, improving date parsing, allowing for multiple formatting
+ * syntaxes and multiple and more easily expandable localization.</p>
+ *
+ * @author Chris Leonello
+ * @date #date#
+ * @version #VERSION#
+ * @copyright (c) 2010 Chris Leonello
+ * jsDate is currently available for use in all personal or commercial projects
+ * under both the MIT and GPL version 2.0 licenses. This means that you can
+ * choose the license that best suits your project and use it accordingly.
+ *
+ * <p>Ken's origianl Date Instance Methods and copyright notice:</p>
+ * <pre>
+ * Ken Snyder (ken d snyder at gmail dot com)
+ * 2008-09-10
+ * version 2.0.2 (http://kendsnyder.com/sandbox/date/)
+ * Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
+ * </pre>
+ *
+ * @class
+ * @name jsDate
+ * @param {String | Number | Array | Date&nbsp;Object | Options&nbsp;Object} arguments Optional arguments, either a parsable date/time string,
+ * a JavaScript timestamp, an array of numbers of form [year, month, day, hours, minutes, seconds, milliseconds],
+ * a Date object, or an options object of form {syntax: "perl", date:some Date} where all options are optional.
+ */
+
+ var jsDate = function () {
+
+ this.syntax = jsDate.config.syntax;
+ this._type = "jsDate";
+ this.proxy = new Date();
+ this.options = {};
+ this.locale = jsDate.regional.getLocale();
+ this.formatString = '';
+ this.defaultCentury = jsDate.config.defaultCentury;
+
+ switch ( arguments.length ) {
+ case 0:
+ break;
+ case 1:
+ // other objects either won't have a _type property or,
+ // if they do, it shouldn't be set to "jsDate", so
+ // assume it is an options argument.
+ if (get_type(arguments[0]) == "[object Object]" && arguments[0]._type != "jsDate") {
+ var opts = this.options = arguments[0];
+ this.syntax = opts.syntax || this.syntax;
+ this.defaultCentury = opts.defaultCentury || this.defaultCentury;
+ this.proxy = jsDate.createDate(opts.date);
+ }
+ else {
+ this.proxy = jsDate.createDate(arguments[0]);
+ }
+ break;
+ default:
+ var a = [];
+ for ( var i=0; i<arguments.length; i++ ) {
+ a.push(arguments[i]);
+ }
+ // this should be the current date/time?
+ this.proxy = new Date();
+ this.proxy.setFullYear.apply( this.proxy, a.slice(0,3) );
+ if ( a.slice(3).length ) {
+ this.proxy.setHours.apply( this.proxy, a.slice(3) );
+ }
+ break;
+ }
+ };
+
+ /**
+ * @namespace Configuration options that will be used as defaults for all instances on the page.
+ * @property {String} defaultLocale The default locale to use [en].
+ * @property {String} syntax The default syntax to use [perl].
+ * @property {Number} defaultCentury The default centry for 2 digit dates.
+ */
+ jsDate.config = {
+ defaultLocale: 'en',
+ syntax: 'perl',
+ defaultCentury: 1900
+ };
+
+ /**
+ * Add an arbitrary amount to the currently stored date
+ *
+ * @param {Number} number
+ * @param {String} unit
+ * @returns {jsDate}
+ */
+
+ jsDate.prototype.add = function(number, unit) {
+ var factor = multipliers[unit] || multipliers.day;
+ if (typeof factor == 'number') {
+ this.proxy.setTime(this.proxy.getTime() + (factor * number));
+ } else {
+ factor.add(this, number);
+ }
+ return this;
+ };
+
+ /**
+ * Create a new jqplot.date object with the same date
+ *
+ * @returns {jsDate}
+ */
+
+ jsDate.prototype.clone = function() {
+ return new jsDate(this.proxy.getTime());
+ };
+
+ /**
+ * Get the UTC TimeZone Offset of this date in milliseconds.
+ *
+ * @returns {Number}
+ */
+
+ jsDate.prototype.getUtcOffset = function() {
+ return this.proxy.getTimezoneOffset() * 60000;
+ };
+
+ /**
+ * Find the difference between this jsDate and another date.
+ *
+ * @param {String| Number| Array| jsDate&nbsp;Object| Date&nbsp;Object} dateObj
+ * @param {String} unit
+ * @param {Boolean} allowDecimal
+ * @returns {Number} Number of units difference between dates.
+ */
+
+ jsDate.prototype.diff = function(dateObj, unit, allowDecimal) {
+ // ensure we have a Date object
+ dateObj = new jsDate(dateObj);
+ if (dateObj === null) {
+ return null;
+ }
+ // get the multiplying factor integer or factor function
+ var factor = multipliers[unit] || multipliers.day;
+ if (typeof factor == 'number') {
+ // multiply
+ var unitDiff = (this.proxy.getTime() - dateObj.proxy.getTime()) / factor;
+ } else {
+ // run function
+ var unitDiff = factor.diff(this.proxy, dateObj.proxy);
+ }
+ // if decimals are not allowed, round toward zero
+ return (allowDecimal ? unitDiff : Math[unitDiff > 0 ? 'floor' : 'ceil'](unitDiff));
+ };
+
+ /**
+ * Get the abbreviated name of the current week day
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getAbbrDayName = function() {
+ return jsDate.regional[this.locale]["dayNamesShort"][this.proxy.getDay()];
+ };
+
+ /**
+ * Get the abbreviated name of the current month
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getAbbrMonthName = function() {
+ return jsDate.regional[this.locale]["monthNamesShort"][this.proxy.getMonth()];
+ };
+
+ /**
+ * Get UPPER CASE AM or PM for the current time
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getAMPM = function() {
+ return this.proxy.getHours() >= 12 ? 'PM' : 'AM';
+ };
+
+ /**
+ * Get lower case am or pm for the current time
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getAmPm = function() {
+ return this.proxy.getHours() >= 12 ? 'pm' : 'am';
+ };
+
+ /**
+ * Get the century (19 for 20th Century)
+ *
+ * @returns {Integer} Century (19 for 20th century).
+ */
+ jsDate.prototype.getCentury = function() {
+ return parseInt(this.proxy.getFullYear()/100, 10);
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getDate = function() {
+ return this.proxy.getDate();
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getDay = function() {
+ return this.proxy.getDay();
+ };
+
+ /**
+ * Get the Day of week 1 (Monday) thru 7 (Sunday)
+ *
+ * @returns {Integer} Day of week 1 (Monday) thru 7 (Sunday)
+ */
+ jsDate.prototype.getDayOfWeek = function() {
+ var dow = this.proxy.getDay();
+ return dow===0?7:dow;
+ };
+
+ /**
+ * Get the day of the year
+ *
+ * @returns {Integer} 1 - 366, day of the year
+ */
+ jsDate.prototype.getDayOfYear = function() {
+ var d = this.proxy;
+ var ms = d - new Date('' + d.getFullYear() + '/1/1 GMT');
+ ms += d.getTimezoneOffset()*60000;
+ d = null;
+ return parseInt(ms/60000/60/24, 10)+1;
+ };
+
+ /**
+ * Get the name of the current week day
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getDayName = function() {
+ return jsDate.regional[this.locale]["dayNames"][this.proxy.getDay()];
+ };
+
+ /**
+ * Get the week number of the given year, starting with the first Sunday as the first week
+ * @returns {Integer} Week number (13 for the 13th full week of the year).
+ */
+ jsDate.prototype.getFullWeekOfYear = function() {
+ var d = this.proxy;
+ var doy = this.getDayOfYear();
+ var rdow = 6-d.getDay();
+ var woy = parseInt((doy+rdow)/7, 10);
+ return woy;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getFullYear = function() {
+ return this.proxy.getFullYear();
+ };
+
+ /**
+ * Get the GMT offset in hours and minutes (e.g. +06:30)
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getGmtOffset = function() {
+ // divide the minutes offset by 60
+ var hours = this.proxy.getTimezoneOffset() / 60;
+ // decide if we are ahead of or behind GMT
+ var prefix = hours < 0 ? '+' : '-';
+ // remove the negative sign if any
+ hours = Math.abs(hours);
+ // add the +/- to the padded number of hours to : to the padded minutes
+ return prefix + addZeros(Math.floor(hours), 2) + ':' + addZeros((hours % 1) * 60, 2);
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getHours = function() {
+ return this.proxy.getHours();
+ };
+
+ /**
+ * Get the current hour on a 12-hour scheme
+ *
+ * @returns {Integer}
+ */
+
+ jsDate.prototype.getHours12 = function() {
+ var hours = this.proxy.getHours();
+ return hours > 12 ? hours - 12 : (hours == 0 ? 12 : hours);
+ };
+
+
+ jsDate.prototype.getIsoWeek = function() {
+ var d = this.proxy;
+ var woy = d.getWeekOfYear();
+ var dow1_1 = (new Date('' + d.getFullYear() + '/1/1')).getDay();
+ // First week is 01 and not 00 as in the case of %U and %W,
+ // so we add 1 to the final result except if day 1 of the year
+ // is a Monday (then %W returns 01).
+ // We also need to subtract 1 if the day 1 of the year is
+ // Friday-Sunday, so the resulting equation becomes:
+ var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1);
+ if(idow == 53 && (new Date('' + d.getFullYear() + '/12/31')).getDay() < 4)
+ {
+ idow = 1;
+ }
+ else if(idow === 0)
+ {
+ d = new jsDate(new Date('' + (d.getFullYear()-1) + '/12/31'));
+ idow = d.getIsoWeek();
+ }
+ d = null;
+ return idow;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getMilliseconds = function() {
+ return this.proxy.getMilliseconds();
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getMinutes = function() {
+ return this.proxy.getMinutes();
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getMonth = function() {
+ return this.proxy.getMonth();
+ };
+
+ /**
+ * Get the name of the current month
+ *
+ * @returns {String}
+ */
+
+ jsDate.prototype.getMonthName = function() {
+ return jsDate.regional[this.locale]["monthNames"][this.proxy.getMonth()];
+ };
+
+ /**
+ * Get the number of the current month, 1-12
+ *
+ * @returns {Integer}
+ */
+
+ jsDate.prototype.getMonthNumber = function() {
+ return this.proxy.getMonth() + 1;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getSeconds = function() {
+ return this.proxy.getSeconds();
+ };
+
+ /**
+ * Return a proper two-digit year integer
+ *
+ * @returns {Integer}
+ */
+
+ jsDate.prototype.getShortYear = function() {
+ return this.proxy.getYear() % 100;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getTime = function() {
+ return this.proxy.getTime();
+ };
+
+ /**
+ * Get the timezone abbreviation
+ *
+ * @returns {String} Abbreviation for the timezone
+ */
+ jsDate.prototype.getTimezoneAbbr = function() {
+ return this.proxy.toString().replace(/^.*\(([^)]+)\)$/, '$1');
+ };
+
+ /**
+ * Get the browser-reported name for the current timezone (e.g. MDT, Mountain Daylight Time)
+ *
+ * @returns {String}
+ */
+ jsDate.prototype.getTimezoneName = function() {
+ var match = /(?:\((.+)\)$| ([A-Z]{3}) )/.exec(this.toString());
+ return match[1] || match[2] || 'GMT' + this.getGmtOffset();
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getTimezoneOffset = function() {
+ return this.proxy.getTimezoneOffset();
+ };
+
+
+ /**
+ * Get the week number of the given year, starting with the first Monday as the first week
+ * @returns {Integer} Week number (13 for the 13th week of the year).
+ */
+ jsDate.prototype.getWeekOfYear = function() {
+ var doy = this.getDayOfYear();
+ var rdow = 7 - this.getDayOfWeek();
+ var woy = parseInt((doy+rdow)/7, 10);
+ return woy;
+ };
+
+ /**
+ * Get the current date as a Unix timestamp
+ *
+ * @returns {Integer}
+ */
+
+ jsDate.prototype.getUnix = function() {
+ return Math.round(this.proxy.getTime() / 1000, 0);
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.getYear = function() {
+ return this.proxy.getYear();
+ };
+
+ /**
+ * Return a date one day ahead (or any other unit)
+ *
+ * @param {String} unit Optional, year | month | day | week | hour | minute | second | millisecond
+ * @returns {jsDate}
+ */
+
+ jsDate.prototype.next = function(unit) {
+ unit = unit || 'day';
+ return this.clone().add(1, unit);
+ };
+
+ /**
+ * Set the jsDate instance to a new date.
+ *
+ * @param {String | Number | Array | Date Object | jsDate Object | Options Object} arguments Optional arguments,
+ * either a parsable date/time string,
+ * a JavaScript timestamp, an array of numbers of form [year, month, day, hours, minutes, seconds, milliseconds],
+ * a Date object, jsDate Object or an options object of form {syntax: "perl", date:some Date} where all options are optional.
+ */
+ jsDate.prototype.set = function() {
+ switch ( arguments.length ) {
+ case 0:
+ this.proxy = new Date();
+ break;
+ case 1:
+ // other objects either won't have a _type property or,
+ // if they do, it shouldn't be set to "jsDate", so
+ // assume it is an options argument.
+ if (get_type(arguments[0]) == "[object Object]" && arguments[0]._type != "jsDate") {
+ var opts = this.options = arguments[0];
+ this.syntax = opts.syntax || this.syntax;
+ this.defaultCentury = opts.defaultCentury || this.defaultCentury;
+ this.proxy = jsDate.createDate(opts.date);
+ }
+ else {
+ this.proxy = jsDate.createDate(arguments[0]);
+ }
+ break;
+ default:
+ var a = [];
+ for ( var i=0; i<arguments.length; i++ ) {
+ a.push(arguments[i]);
+ }
+ // this should be the current date/time
+ this.proxy = new Date();
+ this.proxy.setFullYear.apply( this.proxy, a.slice(0,3) );
+ if ( a.slice(3).length ) {
+ this.proxy.setHours.apply( this.proxy, a.slice(3) );
+ }
+ break;
+ }
+ return this;
+ };
+
+ /**
+ * Sets the day of the month for a specified date according to local time.
+ * @param {Integer} dayValue An integer from 1 to 31, representing the day of the month.
+ */
+ jsDate.prototype.setDate = function(n) {
+ this.proxy.setDate(n);
+ return this;
+ };
+
+ /**
+ * Sets the full year for a specified date according to local time.
+ * @param {Integer} yearValue The numeric value of the year, for example, 1995.
+ * @param {Integer} monthValue Optional, between 0 and 11 representing the months January through December.
+ * @param {Integer} dayValue Optional, between 1 and 31 representing the day of the month. If you specify the dayValue parameter, you must also specify the monthValue.
+ */
+ jsDate.prototype.setFullYear = function() {
+ this.proxy.setFullYear.apply(this.proxy, arguments);
+ return this;
+ };
+
+ /**
+ * Sets the hours for a specified date according to local time.
+ *
+ * @param {Integer} hoursValue An integer between 0 and 23, representing the hour.
+ * @param {Integer} minutesValue Optional, An integer between 0 and 59, representing the minutes.
+ * @param {Integer} secondsValue Optional, An integer between 0 and 59, representing the seconds.
+ * If you specify the secondsValue parameter, you must also specify the minutesValue.
+ * @param {Integer} msValue Optional, A number between 0 and 999, representing the milliseconds.
+ * If you specify the msValue parameter, you must also specify the minutesValue and secondsValue.
+ */
+ jsDate.prototype.setHours = function() {
+ this.proxy.setHours.apply(this.proxy, arguments);
+ return this;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.setMilliseconds = function(n) {
+ this.proxy.setMilliseconds(n);
+ return this;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.setMinutes = function() {
+ this.proxy.setMinutes.apply(this.proxy, arguments);
+ return this;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.setMonth = function() {
+ this.proxy.setMonth.apply(this.proxy, arguments);
+ return this;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.setSeconds = function() {
+ this.proxy.setSeconds.apply(this.proxy, arguments);
+ return this;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.setTime = function(n) {
+ this.proxy.setTime(n);
+ return this;
+ };
+
+ /**
+ * Implements Date functionality
+ */
+ jsDate.prototype.setYear = function() {
+ this.proxy.setYear.apply(this.proxy, arguments);
+ return this;
+ };
+
+ /**
+ * Provide a formatted string representation of this date.
+ *
+ * @param {String} formatString A format string.
+ * See: {@link jsDate.formats}.
+ * @returns {String} Date String.
+ */
+
+ jsDate.prototype.strftime = function(formatString) {
+ formatString = formatString || this.formatString || jsDate.regional[this.locale]['formatString'];
+ return jsDate.strftime(this, formatString, this.syntax);
+ };
+
+ /**
+ * Return a String representation of this jsDate object.
+ * @returns {String} Date string.
+ */
+
+ jsDate.prototype.toString = function() {
+ return this.proxy.toString();
+ };
+
+ /**
+ * Convert the current date to an 8-digit integer (%Y%m%d)
+ *
+ * @returns {Integer}
+ */
+
+ jsDate.prototype.toYmdInt = function() {
+ return (this.proxy.getFullYear() * 10000) + (this.getMonthNumber() * 100) + this.proxy.getDate();
+ };
+
+ /**
+ * @namespace Holds localizations for month/day names.
+ * <p>jsDate attempts to detect locale when loaded and defaults to 'en'.
+ * If a localization is detected which is not available, jsDate defaults to 'en'.
+ * Additional localizations can be added after jsDate loads. After adding a localization,
+ * call the jsDate.regional.getLocale() method. Currently, en, fr and de are defined.</p>
+ *
+ * <p>Localizations must be an object and have the following properties defined: monthNames, monthNamesShort, dayNames, dayNamesShort and Localizations are added like:</p>
+ * <pre class="code">
+ * jsDate.regional['en'] = {
+ * monthNames : 'January February March April May June July August September October November December'.split(' '),
+ * monthNamesShort : 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' '),
+ * dayNames : 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday'.split(' '),
+ * dayNamesShort : 'Sun Mon Tue Wed Thu Fri Sat'.split(' ')
+ * };
+ * </pre>
+ * <p>After adding localizations, call <code>jsDate.regional.getLocale();</code> to update the locale setting with the
+ * new localizations.</p>
+ */
+
+ jsDate.regional = {
+ 'en': {
+ monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
+ monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun','Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
+ dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
+ dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'fr': {
+ monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'],
+ monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun','Jul','Aoû','Sep','Oct','Nov','Déc'],
+ dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'],
+ dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'de': {
+ monthNames: ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'],
+ monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'],
+ dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
+ dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'es': {
+ monthNames: ['Enero','Febrero','Marzo','Abril','Mayo','Junio', 'Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'],
+ monthNamesShort: ['Ene','Feb','Mar','Abr','May','Jun', 'Jul','Ago','Sep','Oct','Nov','Dic'],
+ dayNames: ['Domingo','Lunes','Martes','Mi&eacute;rcoles','Jueves','Viernes','S&aacute;bado'],
+ dayNamesShort: ['Dom','Lun','Mar','Mi&eacute;','Juv','Vie','S&aacute;b'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'ru': {
+ monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'],
+ monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн','Июл','Авг','Сен','Окт','Ноя','Дек'],
+ dayNames: ['воскресенье','понедельник','вторник','среда','четверг','пятница','суббота'],
+ dayNamesShort: ['вск','пнд','втр','срд','чтв','птн','сбт'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'ar': {
+ monthNames: ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'آذار', 'حزيران','تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],
+ monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'],
+ dayNames: ['السبت', 'الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة'],
+ dayNamesShort: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'pt': {
+ monthNames: ['Janeiro','Fevereiro','Mar&ccedil;o','Abril','Maio','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'],
+ monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez'],
+ dayNames: ['Domingo','Segunda-feira','Ter&ccedil;a-feira','Quarta-feira','Quinta-feira','Sexta-feira','S&aacute;bado'],
+ dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','S&aacute;b'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ },
+
+ 'pt-BR': {
+ monthNames: ['Janeiro','Fevereiro','Mar&ccedil;o','Abril','Maio','Junho', 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'],
+ monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez'],
+ dayNames: ['Domingo','Segunda-feira','Ter&ccedil;a-feira','Quarta-feira','Quinta-feira','Sexta-feira','S&aacute;bado'],
+ dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','S&aacute;b'],
+ formatString: '%Y-%m-%d %H:%M:%S'
+ }
+
+
+ };
+
+ // Set english variants to 'en'
+ jsDate.regional['en-US'] = jsDate.regional['en-GB'] = jsDate.regional['en'];
+
+ /**
+ * Try to determine the users locale based on the lang attribute of the html page. Defaults to 'en'
+ * if it cannot figure out a locale of if the locale does not have a localization defined.
+ * @returns {String} locale
+ */
+
+ jsDate.regional.getLocale = function () {
+ var l = jsDate.config.defaultLocale;
+
+ if ( document && document.getElementsByTagName('html') && document.getElementsByTagName('html')[0].lang ) {
+ l = document.getElementsByTagName('html')[0].lang;
+ if (!jsDate.regional.hasOwnProperty(l)) {
+ l = jsDate.config.defaultLocale;
+ }
+ }
+
+ return l;
+ };
+
+ // ms in day
+ var day = 24 * 60 * 60 * 1000;
+
+ // padd a number with zeros
+ var addZeros = function(num, digits) {
+ num = String(num);
+ var i = digits - num.length;
+ var s = String(Math.pow(10, i)).slice(1);
+ return s.concat(num);
+ };
+
+ // representations used for calculating differences between dates.
+ // This borrows heavily from Ken Snyder's work.
+ var multipliers = {
+ millisecond: 1,
+ second: 1000,
+ minute: 60 * 1000,
+ hour: 60 * 60 * 1000,
+ day: day,
+ week: 7 * day,
+ month: {
+ // add a number of months
+ add: function(d, number) {
+ // add any years needed (increments of 12)
+ multipliers.year.add(d, Math[number > 0 ? 'floor' : 'ceil'](number / 12));
+ // ensure that we properly wrap betwen December and January
+ // 11 % 12 = 11
+ // 12 % 12 = 0
+ var prevMonth = d.getMonth() + (number % 12);
+ if (prevMonth == 12) {
+ prevMonth = 0;
+ d.setYear(d.getFullYear() + 1);
+ } else if (prevMonth == -1) {
+ prevMonth = 11;
+ d.setYear(d.getFullYear() - 1);
+ }
+ d.setMonth(prevMonth);
+ },
+ // get the number of months between two Date objects (decimal to the nearest day)
+ diff: function(d1, d2) {
+ // get the number of years
+ var diffYears = d1.getFullYear() - d2.getFullYear();
+ // get the number of remaining months
+ var diffMonths = d1.getMonth() - d2.getMonth() + (diffYears * 12);
+ // get the number of remaining days
+ var diffDays = d1.getDate() - d2.getDate();
+ // return the month difference with the days difference as a decimal
+ return diffMonths + (diffDays / 30);
+ }
+ },
+ year: {
+ // add a number of years
+ add: function(d, number) {
+ d.setYear(d.getFullYear() + Math[number > 0 ? 'floor' : 'ceil'](number));
+ },
+ // get the number of years between two Date objects (decimal to the nearest day)
+ diff: function(d1, d2) {
+ return multipliers.month.diff(d1, d2) / 12;
+ }
+ }
+ };
+ //
+ // Alias each multiplier with an 's' to allow 'year' and 'years' for example.
+ // This comes from Ken Snyders work.
+ //
+ for (var unit in multipliers) {
+ if (unit.substring(unit.length - 1) != 's') { // IE will iterate newly added properties :|
+ multipliers[unit + 's'] = multipliers[unit];
+ }
+ }
+
+ //
+ // take a jsDate instance and a format code and return the formatted value.
+ // This is a somewhat modified version of Ken Snyder's method.
+ //
+ var format = function(d, code, syntax) {
+ // if shorcut codes are used, recursively expand those.
+ if (jsDate.formats[syntax]["shortcuts"][code]) {
+ return jsDate.strftime(d, jsDate.formats[syntax]["shortcuts"][code], syntax);
+ } else {
+ // get the format code function and addZeros() argument
+ var getter = (jsDate.formats[syntax]["codes"][code] || '').split('.');
+ var nbr = d['get' + getter[0]] ? d['get' + getter[0]]() : '';
+ if (getter[1]) {
+ nbr = addZeros(nbr, getter[1]);
+ }
+ return nbr;
+ }
+ };
+
+ /**
+ * @static
+ * Static function for convert a date to a string according to a given format. Also acts as namespace for strftime format codes.
+ * <p>strftime formatting can be accomplished without creating a jsDate object by calling jsDate.strftime():</p>
+ * <pre class="code">
+ * var formattedDate = jsDate.strftime('Feb 8, 2006 8:48:32', '%Y-%m-%d %H:%M:%S');
+ * </pre>
+ * @param {String | Number | Array | jsDate&nbsp;Object | Date&nbsp;Object} date A parsable date string, JavaScript time stamp, Array of form [year, month, day, hours, minutes, seconds, milliseconds], jsDate Object or Date object.
+ * @param {String} formatString String with embedded date formatting codes.
+ * See: {@link jsDate.formats}.
+ * @param {String} syntax Optional syntax to use [default perl].
+ * @param {String} locale Optional locale to use.
+ * @returns {String} Formatted representation of the date.
+ */
+ //
+ // Logic as implemented here is very similar to Ken Snyder's Date Instance Methods.
+ //
+ jsDate.strftime = function(d, formatString, syntax, locale) {
+ var syn = 'perl';
+ var loc = jsDate.regional.getLocale();
+
+ // check if syntax and locale are available or reversed
+ if (syntax && jsDate.formats.hasOwnProperty(syntax)) {
+ syn = syntax;
+ }
+ else if (syntax && jsDate.regional.hasOwnProperty(syntax)) {
+ loc = syntax;
+ }
+
+ if (locale && jsDate.formats.hasOwnProperty(locale)) {
+ syn = locale;
+ }
+ else if (locale && jsDate.regional.hasOwnProperty(locale)) {
+ loc = locale;
+ }
+
+ if (get_type(d) != "[object Object]" || d._type != "jsDate") {
+ d = new jsDate(d);
+ d.locale = loc;
+ }
+ if (!formatString) {
+ formatString = d.formatString || jsDate.regional[loc]['formatString'];
+ }
+ // default the format string to year-month-day
+ var source = formatString || '%Y-%m-%d',
+ result = '',
+ match;
+ // replace each format code
+ while (source.length > 0) {
+ if (match = source.match(jsDate.formats[syn].codes.matcher)) {
+ result += source.slice(0, match.index);
+ result += (match[1] || '') + format(d, match[2], syn);
+ source = source.slice(match.index + match[0].length);
+ } else {
+ result += source;
+ source = '';
+ }
+ }
+ return result;
+ };
+
+ /**
+ * @namespace
+ * Namespace to hold format codes and format shortcuts. "perl" and "php" format codes
+ * and shortcuts are defined by default. Additional codes and shortcuts can be
+ * added like:
+ *
+ * <pre class="code">
+ * jsDate.formats["perl"] = {
+ * "codes": {
+ * matcher: /someregex/,
+ * Y: "fullYear", // name of "get" method without the "get",
+ * ..., // more codes
+ * },
+ * "shortcuts": {
+ * F: '%Y-%m-%d',
+ * ..., // more shortcuts
+ * }
+ * };
+ * </pre>
+ *
+ * <p>Additionally, ISO and SQL shortcuts are defined and can be accesses via:
+ * <code>jsDate.formats.ISO</code> and <code>jsDate.formats.SQL</code>
+ */
+
+ jsDate.formats = {
+ ISO:'%Y-%m-%dT%H:%M:%S.%N%G',
+ SQL:'%Y-%m-%d %H:%M:%S'
+ };
+
+ /**
+ * Perl format codes and shortcuts for strftime.
+ *
+ * A hash (object) of codes where each code must be an array where the first member is
+ * the name of a Date.prototype or jsDate.prototype function to call
+ * and optionally a second member indicating the number to pass to addZeros()
+ *
+ * <p>The following format codes are defined:</p>
+ *
+ * <pre class="code">
+ * Code Result Description
+ * == Years ==
+ * %Y 2008 Four-digit year
+ * %y 08 Two-digit year
+ *
+ * == Months ==
+ * %m 09 Two-digit month
+ * %#m 9 One or two-digit month
+ * %B September Full month name
+ * %b Sep Abbreviated month name
+ *
+ * == Days ==
+ * %d 05 Two-digit day of month
+ * %#d 5 One or two-digit day of month
+ * %e 5 One or two-digit day of month
+ * %A Sunday Full name of the day of the week
+ * %a Sun Abbreviated name of the day of the week
+ * %w 0 Number of the day of the week (0 = Sunday, 6 = Saturday)
+ *
+ * == Hours ==
+ * %H 23 Hours in 24-hour format (two digits)
+ * %#H 3 Hours in 24-hour integer format (one or two digits)
+ * %I 11 Hours in 12-hour format (two digits)
+ * %#I 3 Hours in 12-hour integer format (one or two digits)
+ * %p PM AM or PM
+ *
+ * == Minutes ==
+ * %M 09 Minutes (two digits)
+ * %#M 9 Minutes (one or two digits)
+ *
+ * == Seconds ==
+ * %S 02 Seconds (two digits)
+ * %#S 2 Seconds (one or two digits)
+ * %s 1206567625723 Unix timestamp (Seconds past 1970-01-01 00:00:00)
+ *
+ * == Milliseconds ==
+ * %N 008 Milliseconds (three digits)
+ * %#N 8 Milliseconds (one to three digits)
+ *
+ * == Timezone ==
+ * %O 360 difference in minutes between local time and GMT
+ * %Z Mountain Standard Time Name of timezone as reported by browser
+ * %G 06:00 Hours and minutes between GMT
+ *
+ * == Shortcuts ==
+ * %F 2008-03-26 %Y-%m-%d
+ * %T 05:06:30 %H:%M:%S
+ * %X 05:06:30 %H:%M:%S
+ * %x 03/26/08 %m/%d/%y
+ * %D 03/26/08 %m/%d/%y
+ * %#c Wed Mar 26 15:31:00 2008 %a %b %e %H:%M:%S %Y
+ * %v 3-Sep-2008 %e-%b-%Y
+ * %R 15:31 %H:%M
+ * %r 03:31:00 PM %I:%M:%S %p
+ *
+ * == Characters ==
+ * %n \n Newline
+ * %t \t Tab
+ * %% % Percent Symbol
+ * </pre>
+ *
+ * <p>Formatting shortcuts that will be translated into their longer version.
+ * Be sure that format shortcuts do not refer to themselves: this will cause an infinite loop.</p>
+ *
+ * <p>Format codes and format shortcuts can be redefined after the jsDate
+ * module is imported.</p>
+ *
+ * <p>Note that if you redefine the whole hash (object), you must supply a "matcher"
+ * regex for the parser. The default matcher is:</p>
+ *
+ * <code>/()%(#?(%|[a-z]))/i</code>
+ *
+ * <p>which corresponds to the Perl syntax used by default.</p>
+ *
+ * <p>By customizing the matcher and format codes, nearly any strftime functionality is possible.</p>
+ */
+
+ jsDate.formats.perl = {
+ codes: {
+ //
+ // 2-part regex matcher for format codes
+ //
+ // first match must be the character before the code (to account for escaping)
+ // second match must be the format code character(s)
+ //
+ matcher: /()%(#?(%|[a-z]))/i,
+ // year
+ Y: 'FullYear',
+ y: 'ShortYear.2',
+ // month
+ m: 'MonthNumber.2',
+ '#m': 'MonthNumber',
+ B: 'MonthName',
+ b: 'AbbrMonthName',
+ // day
+ d: 'Date.2',
+ '#d': 'Date',
+ e: 'Date',
+ A: 'DayName',
+ a: 'AbbrDayName',
+ w: 'Day',
+ // hours
+ H: 'Hours.2',
+ '#H': 'Hours',
+ I: 'Hours12.2',
+ '#I': 'Hours12',
+ p: 'AMPM',
+ // minutes
+ M: 'Minutes.2',
+ '#M': 'Minutes',
+ // seconds
+ S: 'Seconds.2',
+ '#S': 'Seconds',
+ s: 'Unix',
+ // milliseconds
+ N: 'Milliseconds.3',
+ '#N': 'Milliseconds',
+ // timezone
+ O: 'TimezoneOffset',
+ Z: 'TimezoneName',
+ G: 'GmtOffset'
+ },
+
+ shortcuts: {
+ // date
+ F: '%Y-%m-%d',
+ // time
+ T: '%H:%M:%S',
+ X: '%H:%M:%S',
+ // local format date
+ x: '%m/%d/%y',
+ D: '%m/%d/%y',
+ // local format extended
+ '#c': '%a %b %e %H:%M:%S %Y',
+ // local format short
+ v: '%e-%b-%Y',
+ R: '%H:%M',
+ r: '%I:%M:%S %p',
+ // tab and newline
+ t: '\t',
+ n: '\n',
+ '%': '%'
+ }
+ };
+
+ /**
+ * PHP format codes and shortcuts for strftime.
+ *
+ * A hash (object) of codes where each code must be an array where the first member is
+ * the name of a Date.prototype or jsDate.prototype function to call
+ * and optionally a second member indicating the number to pass to addZeros()
+ *
+ * <p>The following format codes are defined:</p>
+ *
+ * <pre class="code">
+ * Code Result Description
+ * === Days ===
+ * %a Sun through Sat An abbreviated textual representation of the day
+ * %A Sunday - Saturday A full textual representation of the day
+ * %d 01 to 31 Two-digit day of the month (with leading zeros)
+ * %e 1 to 31 Day of the month, with a space preceding single digits.
+ * %j 001 to 366 Day of the year, 3 digits with leading zeros
+ * %u 1 - 7 (Mon - Sun) ISO-8601 numeric representation of the day of the week
+ * %w 0 - 6 (Sun - Sat) Numeric representation of the day of the week
+ *
+ * === Week ===
+ * %U 13 Full Week number, starting with the first Sunday as the first week
+ * %V 01 through 53 ISO-8601:1988 week number, starting with the first week of the year
+ * with at least 4 weekdays, with Monday being the start of the week
+ * %W 46 A numeric representation of the week of the year,
+ * starting with the first Monday as the first week
+ * === Month ===
+ * %b Jan through Dec Abbreviated month name, based on the locale
+ * %B January - December Full month name, based on the locale
+ * %h Jan through Dec Abbreviated month name, based on the locale (an alias of %b)
+ * %m 01 - 12 (Jan - Dec) Two digit representation of the month
+ *
+ * === Year ===
+ * %C 19 Two digit century (year/100, truncated to an integer)
+ * %y 09 for 2009 Two digit year
+ * %Y 2038 Four digit year
+ *
+ * === Time ===
+ * %H 00 through 23 Two digit representation of the hour in 24-hour format
+ * %I 01 through 12 Two digit representation of the hour in 12-hour format
+ * %l 1 through 12 Hour in 12-hour format, with a space preceeding single digits
+ * %M 00 through 59 Two digit representation of the minute
+ * %p AM/PM UPPER-CASE 'AM' or 'PM' based on the given time
+ * %P am/pm lower-case 'am' or 'pm' based on the given time
+ * %r 09:34:17 PM Same as %I:%M:%S %p
+ * %R 00:35 Same as %H:%M
+ * %S 00 through 59 Two digit representation of the second
+ * %T 21:34:17 Same as %H:%M:%S
+ * %X 03:59:16 Preferred time representation based on locale, without the date
+ * %z -0500 or EST Either the time zone offset from UTC or the abbreviation
+ * %Z -0500 or EST The time zone offset/abbreviation option NOT given by %z
+ *
+ * === Time and Date ===
+ * %D 02/05/09 Same as %m/%d/%y
+ * %F 2009-02-05 Same as %Y-%m-%d (commonly used in database datestamps)
+ * %s 305815200 Unix Epoch Time timestamp (same as the time() function)
+ * %x 02/05/09 Preferred date representation, without the time
+ *
+ * === Miscellaneous ===
+ * %n --- A newline character (\n)
+ * %t --- A Tab character (\t)
+ * %% --- A literal percentage character (%)
+ * </pre>
+ */
+
+ jsDate.formats.php = {
+ codes: {
+ //
+ // 2-part regex matcher for format codes
+ //
+ // first match must be the character before the code (to account for escaping)
+ // second match must be the format code character(s)
+ //
+ matcher: /()%((%|[a-z]))/i,
+ // day
+ a: 'AbbrDayName',
+ A: 'DayName',
+ d: 'Date.2',
+ e: 'Date',
+ j: 'DayOfYear.3',
+ u: 'DayOfWeek',
+ w: 'Day',
+ // week
+ U: 'FullWeekOfYear.2',
+ V: 'IsoWeek.2',
+ W: 'WeekOfYear.2',
+ // month
+ b: 'AbbrMonthName',
+ B: 'MonthName',
+ m: 'MonthNumber.2',
+ h: 'AbbrMonthName',
+ // year
+ C: 'Century.2',
+ y: 'ShortYear.2',
+ Y: 'FullYear',
+ // time
+ H: 'Hours.2',
+ I: 'Hours12.2',
+ l: 'Hours12',
+ p: 'AMPM',
+ P: 'AmPm',
+ M: 'Minutes.2',
+ S: 'Seconds.2',
+ s: 'Unix',
+ O: 'TimezoneOffset',
+ z: 'GmtOffset',
+ Z: 'TimezoneAbbr'
+ },
+
+ shortcuts: {
+ D: '%m/%d/%y',
+ F: '%Y-%m-%d',
+ T: '%H:%M:%S',
+ X: '%H:%M:%S',
+ x: '%m/%d/%y',
+ R: '%H:%M',
+ r: '%I:%M:%S %p',
+ t: '\t',
+ n: '\n',
+ '%': '%'
+ }
+ };
+ //
+ // Conceptually, the logic implemented here is similar to Ken Snyder's Date Instance Methods.
+ // I use his idea of a set of parsers which can be regular expressions or functions,
+ // iterating through those, and then seeing if Date.parse() will create a date.
+ // The parser expressions and functions are a little different and some bugs have been
+ // worked out. Also, a lot of "pre-parsing" is done to fix implementation
+ // variations of Date.parse() between browsers.
+ //
+ jsDate.createDate = function(date) {
+ // if passing in multiple arguments, try Date constructor
+ if (date == null) {
+ return new Date();
+ }
+ // If the passed value is already a date object, return it
+ if (date instanceof Date) {
+ return date;
+ }
+ // if (typeof date == 'number') return new Date(date * 1000);
+ // If the passed value is an integer, interpret it as a javascript timestamp
+ if (typeof date == 'number') {
+ return new Date(date);
+ }
+
+ // Before passing strings into Date.parse(), have to normalize them for certain conditions.
+ // If strings are not formatted staccording to the EcmaScript spec, results from Date parse will be implementation dependent.
+ //
+ // For example:
+ // * FF and Opera assume 2 digit dates are pre y2k, Chome assumes <50 is pre y2k, 50+ is 21st century.
+ // * Chrome will correctly parse '1984-1-25' into localtime, FF and Opera will not parse.
+ // * Both FF, Chrome and Opera will parse '1984/1/25' into localtime.
+
+ // remove leading and trailing spaces
+ var parsable = String(date).replace(/^\s*(.+)\s*$/g, '$1');
+
+ // replace dahses (-) with slashes (/) in dates like n[nnn]/n[n]/n[nnn]
+ parsable = parsable.replace(/^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,4})/, "$1/$2/$3");
+
+ /////////
+ // Need to check for '15-Dec-09' also.
+ // FF will not parse, but Chrome will.
+ // Chrome will set date to 2009 as well.
+ /////////
+
+ // first check for 'dd-mmm-yyyy' or 'dd/mmm/yyyy' like '15-Dec-2010'
+ parsable = parsable.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{4})/i, "$1 $2 $3");
+
+ // Now check for 'dd-mmm-yy' or 'dd/mmm/yy' and normalize years to default century.
+ var match = parsable.match(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i);
+ if (match && match.length > 3) {
+ var m3 = parseFloat(match[3]);
+ var ny = jsDate.config.defaultCentury + m3;
+ ny = String(ny);
+
+ // now replace 2 digit year with 4 digit year
+ parsable = parsable.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i, match[1] +' '+ match[2] +' '+ ny);
+
+ }
+
+ // Check for '1/19/70 8:14PM'
+ // where starts with mm/dd/yy or yy/mm/dd and have something after
+ // Check if 1st postiion is greater than 31, assume it is year.
+ // Assme all 2 digit years are 1900's.
+ // Finally, change them into US style mm/dd/yyyy representations.
+ match = parsable.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})[^0-9]/);
+
+ function h1(parsable, match) {
+ var m1 = parseFloat(match[1]);
+ var m2 = parseFloat(match[2]);
+ var m3 = parseFloat(match[3]);
+ var cent = jsDate.config.defaultCentury;
+ var ny, nd, nm, str;
+
+ if (m1 > 31) { // first number is a year
+ nd = m3;
+ nm = m2;
+ ny = cent + m1;
+ }
+
+ else { // last number is the year
+ nd = m2;
+ nm = m1;
+ ny = cent + m3;
+ }
+
+ str = nm+'/'+nd+'/'+ny;
+
+ // now replace 2 digit year with 4 digit year
+ return parsable.replace(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})/, str);
+
+ }
+
+ if (match && match.length > 3) {
+ parsable = h1(parsable, match);
+ }
+
+ // Now check for '1/19/70' with nothing after and do as above
+ var match = parsable.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})$/);
+
+ if (match && match.length > 3) {
+ parsable = h1(parsable, match);
+ }
+
+
+ var i = 0;
+ var length = jsDate.matchers.length;
+ var pattern,
+ ms,
+ current = parsable,
+ obj;
+ while (i < length) {
+ ms = Date.parse(current);
+ if (!isNaN(ms)) {
+ return new Date(ms);
+ }
+ pattern = jsDate.matchers[i];
+ if (typeof pattern == 'function') {
+ obj = pattern.call(jsDate, current);
+ if (obj instanceof Date) {
+ return obj;
+ }
+ } else {
+ current = parsable.replace(pattern[0], pattern[1]);
+ }
+ i++;
+ }
+ return NaN;
+ };
+
+
+ /**
+ * @static
+ * Handy static utility function to return the number of days in a given month.
+ * @param {Integer} year Year
+ * @param {Integer} month Month (1-12)
+ * @returns {Integer} Number of days in the month.
+ */
+ //
+ // handy utility method Borrowed right from Ken Snyder's Date Instance Mehtods.
+ //
+ jsDate.daysInMonth = function(year, month) {
+ if (month == 2) {
+ return new Date(year, 1, 29).getDate() == 29 ? 29 : 28;
+ }
+ return [undefined,31,undefined,31,30,31,30,31,31,30,31,30,31][month];
+ };
+
+
+ //
+ // An Array of regular expressions or functions that will attempt to match the date string.
+ // Functions are called with scope of a jsDate instance.
+ //
+ jsDate.matchers = [
+ // convert dd.mmm.yyyy to mm/dd/yyyy (world date to US date).
+ [/(3[01]|[0-2]\d)\s*\.\s*(1[0-2]|0\d)\s*\.\s*([1-9]\d{3})/, '$2/$1/$3'],
+ // convert yyyy-mm-dd to mm/dd/yyyy (ISO date to US date).
+ [/([1-9]\d{3})\s*-\s*(1[0-2]|0\d)\s*-\s*(3[01]|[0-2]\d)/, '$2/$3/$1'],
+ // Handle 12 hour or 24 hour time with milliseconds am/pm and optional date part.
+ function(str) {
+ var match = str.match(/^(?:(.+)\s+)?([012]?\d)(?:\s*\:\s*(\d\d))?(?:\s*\:\s*(\d\d(\.\d*)?))?\s*(am|pm)?\s*$/i);
+ // opt. date hour opt. minute opt. second opt. msec opt. am or pm
+ if (match) {
+ if (match[1]) {
+ var d = this.createDate(match[1]);
+ if (isNaN(d)) {
+ return;
+ }
+ } else {
+ var d = new Date();
+ d.setMilliseconds(0);
+ }
+ var hour = parseFloat(match[2]);
+ if (match[6]) {
+ hour = match[6].toLowerCase() == 'am' ? (hour == 12 ? 0 : hour) : (hour == 12 ? 12 : hour + 12);
+ }
+ d.setHours(hour, parseInt(match[3] || 0, 10), parseInt(match[4] || 0, 10), ((parseFloat(match[5] || 0)) || 0)*1000);
+ return d;
+ }
+ else {
+ return str;
+ }
+ },
+ // Handle ISO timestamp with time zone.
+ function(str) {
+ var match = str.match(/^(?:(.+))[T|\s+]([012]\d)(?:\:(\d\d))(?:\:(\d\d))(?:\.\d+)([\+\-]\d\d\:\d\d)$/i);
+ if (match) {
+ if (match[1]) {
+ var d = this.createDate(match[1]);
+ if (isNaN(d)) {
+ return;
+ }
+ } else {
+ var d = new Date();
+ d.setMilliseconds(0);
+ }
+ var hour = parseFloat(match[2]);
+ d.setHours(hour, parseInt(match[3], 10), parseInt(match[4], 10), parseFloat(match[5])*1000);
+ return d;
+ }
+ else {
+ return str;
+ }
+ },
+ // Try to match ambiguous strings like 12/8/22.
+ // Use FF date assumption that 2 digit years are 20th century (i.e. 1900's).
+ // This may be redundant with pre processing of date already performed.
+ function(str) {
+ var match = str.match(/^([0-3]?\d)\s*[-\/.\s]{1}\s*([a-zA-Z]{3,9})\s*[-\/.\s]{1}\s*([0-3]?\d)$/);
+ if (match) {
+ var d = new Date();
+ var cent = jsDate.config.defaultCentury;
+ var m1 = parseFloat(match[1]);
+ var m3 = parseFloat(match[3]);
+ var ny, nd, nm;
+ if (m1 > 31) { // first number is a year
+ nd = m3;
+ ny = cent + m1;
+ }
+
+ else { // last number is the year
+ nd = m1;
+ ny = cent + m3;
+ }
+
+ var nm = inArray(match[2], jsDate.regional[jsDate.regional.getLocale()]["monthNamesShort"]);
+
+ if (nm == -1) {
+ nm = inArray(match[2], jsDate.regional[jsDate.regional.getLocale()]["monthNames"]);
+ }
+
+ d.setFullYear(ny, nm, nd);
+ d.setHours(0,0,0,0);
+ return d;
+ }
+
+ else {
+ return str;
+ }
+ }
+ ];
+
+ //
+ // I think John Reisig published this method on his blog, ejohn.
+ //
+ function inArray( elem, array ) {
+ if ( array.indexOf ) {
+ return array.indexOf( elem );
+ }
+
+ for ( var i = 0, length = array.length; i < length; i++ ) {
+ if ( array[ i ] === elem ) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ //
+ // Thanks to Kangax, Christian Sciberras and Stack Overflow for this method.
+ //
+ function get_type(thing){
+ if(thing===null) return "[object Null]"; // special case
+ return Object.prototype.toString.call(thing);
+ }
+
+ $.jsDate = jsDate;
+
+
+ /**
+ * JavaScript printf/sprintf functions.
+ *
+ * This code has been adapted from the publicly available sprintf methods
+ * by Ash Searle. His original header follows:
+ *
+ * This code is unrestricted: you are free to use it however you like.
+ *
+ * The functions should work as expected, performing left or right alignment,
+ * truncating strings, outputting numbers with a required precision etc.
+ *
+ * For complex cases, these functions follow the Perl implementations of
+ * (s)printf, allowing arguments to be passed out-of-order, and to set the
+ * precision or length of the output based on arguments instead of fixed
+ * numbers.
+ *
+ * See http://perldoc.perl.org/functions/sprintf.html for more information.
+ *
+ * Implemented:
+ * - zero and space-padding
+ * - right and left-alignment,
+ * - base X prefix (binary, octal and hex)
+ * - positive number prefix
+ * - (minimum) width
+ * - precision / truncation / maximum width
+ * - out of order arguments
+ *
+ * Not implemented (yet):
+ * - vector flag
+ * - size (bytes, words, long-words etc.)
+ *
+ * Will not implement:
+ * - %n or %p (no pass-by-reference in JavaScript)
+ *
+ * @version 2007.04.27
+ * @author Ash Searle
+ *
+ * You can see the original work and comments on his blog:
+ * http://hexmen.com/blog/2007/03/printf-sprintf/
+ * http://hexmen.com/js/sprintf.js
+ */
+
+ /**
+ * @Modifications 2009.05.26
+ * @author Chris Leonello
+ *
+ * Added %p %P specifier
+ * Acts like %g or %G but will not add more significant digits to the output than present in the input.
+ * Example:
+ * Format: '%.3p', Input: 0.012, Output: 0.012
+ * Format: '%.3g', Input: 0.012, Output: 0.0120
+ * Format: '%.4p', Input: 12.0, Output: 12.0
+ * Format: '%.4g', Input: 12.0, Output: 12.00
+ * Format: '%.4p', Input: 4.321e-5, Output: 4.321e-5
+ * Format: '%.4g', Input: 4.321e-5, Output: 4.3210e-5
+ *
+ * Example:
+ * >>> $.jqplot.sprintf('%.2f, %d', 23.3452, 43.23)
+ * "23.35, 43"
+ * >>> $.jqplot.sprintf("no value: %n, decimal with thousands separator: %'d", 23.3452, 433524)
+ * "no value: , decimal with thousands separator: 433,524"
+ */
+ $.jqplot.sprintf = function() {
+ function pad(str, len, chr, leftJustify) {
+ var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);
+ return leftJustify ? str + padding : padding + str;
+
+ }
+
+ function thousand_separate(value) {
+ var value_str = new String(value);
+ for (var i=10; i>0; i--) {
+ if (value_str == (value_str = value_str.replace(/^(\d+)(\d{3})/, "$1"+$.jqplot.sprintf.thousandsSeparator+"$2"))) break;
+ }
+ return value_str;
+ }
+
+ function justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace) {
+ var diff = minWidth - value.length;
+ if (diff > 0) {
+ var spchar = ' ';
+ if (htmlSpace) { spchar = '&nbsp;'; }
+ if (leftJustify || !zeroPad) {
+ value = pad(value, minWidth, spchar, leftJustify);
+ } else {
+ value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
+ }
+ }
+ return value;
+ }
+
+ function formatBaseX(value, base, prefix, leftJustify, minWidth, precision, zeroPad, htmlSpace) {
+ // Note: casts negative numbers to positive ones
+ var number = value >>> 0;
+ prefix = prefix && number && {'2': '0b', '8': '0', '16': '0x'}[base] || '';
+ value = prefix + pad(number.toString(base), precision || 0, '0', false);
+ return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace);
+ }
+
+ function formatString(value, leftJustify, minWidth, precision, zeroPad, htmlSpace) {
+ if (precision != null) {
+ value = value.slice(0, precision);
+ }
+ return justify(value, '', leftJustify, minWidth, zeroPad, htmlSpace);
+ }
+
+ var a = arguments, i = 0, format = a[i++];
+
+ return format.replace($.jqplot.sprintf.regex, function(substring, valueIndex, flags, minWidth, _, precision, type) {
+ if (substring == '%%') { return '%'; }
+
+ // parse flags
+ var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false, htmlSpace = false, thousandSeparation = false;
+ for (var j = 0; flags && j < flags.length; j++) switch (flags.charAt(j)) {
+ case ' ': positivePrefix = ' '; break;
+ case '+': positivePrefix = '+'; break;
+ case '-': leftJustify = true; break;
+ case '0': zeroPad = true; break;
+ case '#': prefixBaseX = true; break;
+ case '&': htmlSpace = true; break;
+ case '\'': thousandSeparation = true; break;
+ }
+
+ // parameters may be null, undefined, empty-string or real valued
+ // we want to ignore null, undefined and empty-string values
+
+ if (!minWidth) {
+ minWidth = 0;
+ }
+ else if (minWidth == '*') {
+ minWidth = +a[i++];
+ }
+ else if (minWidth.charAt(0) == '*') {
+ minWidth = +a[minWidth.slice(1, -1)];
+ }
+ else {
+ minWidth = +minWidth;
+ }
+
+ // Note: undocumented perl feature:
+ if (minWidth < 0) {
+ minWidth = -minWidth;
+ leftJustify = true;
+ }
+
+ if (!isFinite(minWidth)) {
+ throw new Error('$.jqplot.sprintf: (minimum-)width must be finite');
+ }
+
+ if (!precision) {
+ precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : void(0);
+ }
+ else if (precision == '*') {
+ precision = +a[i++];
+ }
+ else if (precision.charAt(0) == '*') {
+ precision = +a[precision.slice(1, -1)];
+ }
+ else {
+ precision = +precision;
+ }
+
+ // grab value using valueIndex if required?
+ var value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];
+
+ switch (type) {
+ case 's': {
+ if (value == null) {
+ return '';
+ }
+ return formatString(String(value), leftJustify, minWidth, precision, zeroPad, htmlSpace);
+ }
+ case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad, htmlSpace);
+ case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad,htmlSpace);
+ case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace);
+ case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace);
+ case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace).toUpperCase();
+ case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace);
+ case 'i': {
+ var number = parseInt(+value, 10);
+ if (isNaN(number)) {
+ return '';
+ }
+ var prefix = number < 0 ? '-' : positivePrefix;
+ var number_str = thousandSeparation ? thousand_separate(String(Math.abs(number))): String(Math.abs(number));
+ value = prefix + pad(number_str, precision, '0', false);
+ //value = prefix + pad(String(Math.abs(number)), precision, '0', false);
+ return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace);
+ }
+ case 'd': {
+ var number = Math.round(+value);
+ if (isNaN(number)) {
+ return '';
+ }
+ var prefix = number < 0 ? '-' : positivePrefix;
+ var number_str = thousandSeparation ? thousand_separate(String(Math.abs(number))): String(Math.abs(number));
+ value = prefix + pad(number_str, precision, '0', false);
+ return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace);
+ }
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ {
+ var number = +value;
+ if (isNaN(number)) {
+ return '';
+ }
+ var prefix = number < 0 ? '-' : positivePrefix;
+ var method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
+ var textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
+ var number_str = Math.abs(number)[method](precision);
+ number_str = thousandSeparation ? thousand_separate(number_str): number_str;
+ value = prefix + number_str;
+ var justified = justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform]();
+
+ if ($.jqplot.sprintf.decimalMark !== '.' && $.jqplot.sprintf.decimalMark !== $.jqplot.sprintf.thousandsSeparator) {
+ return justified.replace(/\./, $.jqplot.sprintf.decimalMark);
+ } else {
+ return justified;
+ }
+ }
+ case 'p':
+ case 'P':
+ {
+ // make sure number is a number
+ var number = +value;
+ if (isNaN(number)) {
+ return '';
+ }
+ var prefix = number < 0 ? '-' : positivePrefix;
+
+ var parts = String(Number(Math.abs(number)).toExponential()).split(/e|E/);
+ var sd = (parts[0].indexOf('.') != -1) ? parts[0].length - 1 : parts[0].length;
+ var zeros = (parts[1] < 0) ? -parts[1] - 1 : 0;
+
+ if (Math.abs(number) < 1) {
+ if (sd + zeros <= precision) {
+ value = prefix + Math.abs(number).toPrecision(sd);
+ }
+ else {
+ if (sd <= precision - 1) {
+ value = prefix + Math.abs(number).toExponential(sd-1);
+ }
+ else {
+ value = prefix + Math.abs(number).toExponential(precision-1);
+ }
+ }
+ }
+ else {
+ var prec = (sd <= precision) ? sd : precision;
+ value = prefix + Math.abs(number).toPrecision(prec);
+ }
+ var textTransform = ['toString', 'toUpperCase']['pP'.indexOf(type) % 2];
+ return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform]();
+ }
+ case 'n': return '';
+ default: return substring;
+ }
+ });
+ };
+
+ $.jqplot.sprintf.thousandsSeparator = ',';
+ // Specifies the decimal mark for floating point values. By default a period '.'
+ // is used. If you change this value to for example a comma be sure to also
+ // change the thousands separator or else this won't work since a simple String
+ // replace is used (replacing all periods with the mark specified here).
+ $.jqplot.sprintf.decimalMark = '.';
+
+ $.jqplot.sprintf.regex = /%%|%(\d+\$)?([-+#0&\' ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([nAscboxXuidfegpEGP])/g;
+
+ $.jqplot.getSignificantFigures = function(number) {
+ var parts = String(Number(Math.abs(number)).toExponential()).split(/e|E/);
+ // total significant digits
+ var sd = (parts[0].indexOf('.') != -1) ? parts[0].length - 1 : parts[0].length;
+ var zeros = (parts[1] < 0) ? -parts[1] - 1 : 0;
+ // exponent
+ var expn = parseInt(parts[1], 10);
+ // digits to the left of the decimal place
+ var dleft = (expn + 1 > 0) ? expn + 1 : 0;
+ // digits to the right of the decimal place
+ var dright = (sd <= dleft) ? 0 : sd - expn - 1;
+ return {significantDigits: sd, digitsLeft: dleft, digitsRight: dright, zeros: zeros, exponent: expn} ;
+ };
+
+ $.jqplot.getPrecision = function(number) {
+ return $.jqplot.getSignificantFigures(number).digitsRight;
+ };
+
+})(jQuery);
+
+
+ var backCompat = $.uiBackCompat !== false;
+
+ $.jqplot.effects = {
+ effect: {}
+ };
+
+ // prefix used for storing data on .data()
+ var dataSpace = "jqplot.storage.";
+
+ /******************************************************************************/
+ /*********************************** EFFECTS **********************************/
+ /******************************************************************************/
+
+ $.extend( $.jqplot.effects, {
+ version: "1.9pre",
+
+ // Saves a set of properties in a data storage
+ save: function( element, set ) {
+ for( var i=0; i < set.length; i++ ) {
+ if ( set[ i ] !== null ) {
+ element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
+ }
+ }
+ },
+
+ // Restores a set of previously saved properties from a data storage
+ restore: function( element, set ) {
+ for( var i=0; i < set.length; i++ ) {
+ if ( set[ i ] !== null ) {
+ element.css( set[ i ], element.data( dataSpace + set[ i ] ) );
+ }
+ }
+ },
+
+ setMode: function( el, mode ) {
+ if (mode === "toggle") {
+ mode = el.is( ":hidden" ) ? "show" : "hide";
+ }
+ return mode;
+ },
+
+ // Wraps the element around a wrapper that copies position properties
+ createWrapper: function( element ) {
+
+ // if the element is already wrapped, return it
+ if ( element.parent().is( ".ui-effects-wrapper" )) {
+ return element.parent();
+ }
+
+ // wrap the element
+ var props = {
+ width: element.outerWidth(true),
+ height: element.outerHeight(true),
+ "float": element.css( "float" )
+ },
+ wrapper = $( "<div></div>" )
+ .addClass( "ui-effects-wrapper" )
+ .css({
+ fontSize: "100%",
+ background: "transparent",
+ border: "none",
+ margin: 0,
+ padding: 0
+ }),
+ // Store the size in case width/height are defined in % - Fixes #5245
+ size = {
+ width: element.width(),
+ height: element.height()
+ },
+ active = document.activeElement;
+
+ element.wrap( wrapper );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+
+ wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually loose the reference to the wrapped element
+
+ // transfer positioning properties to the wrapper
+ if ( element.css( "position" ) === "static" ) {
+ wrapper.css({ position: "relative" });
+ element.css({ position: "relative" });
+ } else {
+ $.extend( props, {
+ position: element.css( "position" ),
+ zIndex: element.css( "z-index" )
+ });
+ $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
+ props[ pos ] = element.css( pos );
+ if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
+ props[ pos ] = "auto";
+ }
+ });
+ element.css({
+ position: "relative",
+ top: 0,
+ left: 0,
+ right: "auto",
+ bottom: "auto"
+ });
+ }
+ element.css(size);
+
+ return wrapper.css( props ).show();
+ },
+
+ removeWrapper: function( element ) {
+ var active = document.activeElement;
+
+ if ( element.parent().is( ".ui-effects-wrapper" ) ) {
+ element.parent().replaceWith( element );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+ }
+
+
+ return element;
+ }
+ });
+
+ // return an effect options object for the given parameters:
+ function _normalizeArguments( effect, options, speed, callback ) {
+
+ // short path for passing an effect options object:
+ if ( $.isPlainObject( effect ) ) {
+ return effect;
+ }
+
+ // convert to an object
+ effect = { effect: effect };
+
+ // catch (effect)
+ if ( options === undefined ) {
+ options = {};
+ }
+
+ // catch (effect, callback)
+ if ( $.isFunction( options ) ) {
+ callback = options;
+ speed = null;
+ options = {};
+ }
+
+ // catch (effect, speed, ?)
+ if ( $.type( options ) === "number" || $.fx.speeds[ options ]) {
+ callback = speed;
+ speed = options;
+ options = {};
+ }
+
+ // catch (effect, options, callback)
+ if ( $.isFunction( speed ) ) {
+ callback = speed;
+ speed = null;
+ }
+
+ // add options to effect
+ if ( options ) {
+ $.extend( effect, options );
+ }
+
+ speed = speed || options.duration;
+ effect.duration = $.fx.off ? 0 : typeof speed === "number"
+ ? speed : speed in $.fx.speeds ? $.fx.speeds[ speed ] : $.fx.speeds._default;
+
+ effect.complete = callback || options.complete;
+
+ return effect;
+ }
+
+ function standardSpeed( speed ) {
+ // valid standard speeds
+ if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) {
+ return true;
+ }
+
+ // invalid strings - treat as "normal" speed
+ if ( typeof speed === "string" && !$.jqplot.effects.effect[ speed ] ) {
+ // TODO: remove in 2.0 (#7115)
+ if ( backCompat && $.jqplot.effects[ speed ] ) {
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ $.fn.extend({
+ jqplotEffect: function( effect, options, speed, callback ) {
+ var args = _normalizeArguments.apply( this, arguments ),
+ mode = args.mode,
+ queue = args.queue,
+ effectMethod = $.jqplot.effects.effect[ args.effect ],
+
+ // DEPRECATED: remove in 2.0 (#7115)
+ oldEffectMethod = !effectMethod && backCompat && $.jqplot.effects[ args.effect ];
+
+ if ( $.fx.off || !( effectMethod || oldEffectMethod ) ) {
+ // delegate to the original method (e.g., .show()) if possible
+ if ( mode ) {
+ return this[ mode ]( args.duration, args.complete );
+ } else {
+ return this.each( function() {
+ if ( args.complete ) {
+ args.complete.call( this );
+ }
+ });
+ }
+ }
+
+ function run( next ) {
+ var elem = $( this ),
+ complete = args.complete,
+ mode = args.mode;
+
+ function done() {
+ if ( $.isFunction( complete ) ) {
+ complete.call( elem[0] );
+ }
+ if ( $.isFunction( next ) ) {
+ next();
+ }
+ }
+
+ // if the element is hiddden and mode is hide,
+ // or element is visible and mode is show
+ if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
+ done();
+ } else {
+ effectMethod.call( elem[0], args, done );
+ }
+ }
+
+ // TODO: remove this check in 2.0, effectMethod will always be true
+ if ( effectMethod ) {
+ return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
+ } else {
+ // DEPRECATED: remove in 2.0 (#7115)
+ return oldEffectMethod.call(this, {
+ options: args,
+ duration: args.duration,
+ callback: args.complete,
+ mode: args.mode
+ });
+ }
+ }
+ });
+
+
+
+
+ var rvertical = /up|down|vertical/,
+ rpositivemotion = /up|left|vertical|horizontal/;
+
+ $.jqplot.effects.effect.blind = function( o, done ) {
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.jqplot.effects.setMode( el, o.mode || "hide" ),
+ direction = o.direction || "up",
+ vertical = rvertical.test( direction ),
+ ref = vertical ? "height" : "width",
+ ref2 = vertical ? "top" : "left",
+ motion = rpositivemotion.test( direction ),
+ animation = {},
+ show = mode === "show",
+ wrapper, distance, top;
+
+ // // if already wrapped, the wrapper's properties are my property. #6245
+ if ( el.parent().is( ".ui-effects-wrapper" ) ) {
+ $.jqplot.effects.save( el.parent(), props );
+ } else {
+ $.jqplot.effects.save( el, props );
+ }
+ el.show();
+ top = parseInt(el.css('top'), 10);
+ wrapper = $.jqplot.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+
+ distance = vertical ? wrapper[ ref ]() + top : wrapper[ ref ]();
+
+ animation[ ref ] = show ? String(distance) : '0';
+ if ( !motion ) {
+ el
+ .css( vertical ? "bottom" : "right", 0 )
+ .css( vertical ? "top" : "left", "" )
+ .css({ position: "absolute" });
+ animation[ ref2 ] = show ? '0' : String(distance);
+ }
+
+ // // start at 0 if we are showing
+ if ( show ) {
+ wrapper.css( ref, 0 );
+ if ( ! motion ) {
+ wrapper.css( ref2, distance );
+ }
+ }
+
+ // // Animate
+ wrapper.animate( animation, {
+ duration: o.duration,
+ easing: o.easing,
+ queue: false,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.jqplot.effects.restore( el, props );
+ $.jqplot.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+ };
+
+
diff --git a/SemanticResultFormats/resources/jquery/jquery.blockUI.js b/SemanticResultFormats/resources/jquery/jquery.blockUI.js
new file mode 100644
index 00000000..ccef3f03
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jquery.blockUI.js
@@ -0,0 +1,619 @@
+/*!
+ * jQuery blockUI plugin
+ * Version 2.66.0-2013.10.09
+ * Requires jQuery v1.7 or later
+ *
+ * Examples at: http://malsup.com/jquery/block/
+ * Copyright (c) 2007-2013 M. Alsup
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Thanks to Amir-Hossein Sobhi for some excellent contributions!
+ */
+
+;(function() {
+/*jshint eqeqeq:false curly:false latedef:false */
+"use strict";
+
+ function setup($) {
+ $.fn._fadeIn = $.fn.fadeIn;
+
+ var noOp = $.noop || function() {};
+
+ // this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
+ // confusing userAgent strings on Vista)
+ var msie = /MSIE/.test(navigator.userAgent);
+ var ie6 = /MSIE 6.0/.test(navigator.userAgent) && ! /MSIE 8.0/.test(navigator.userAgent);
+ var mode = document.documentMode || 0;
+ var setExpr = $.isFunction( document.createElement('div').style.setExpression );
+
+ // global $ methods for blocking/unblocking the entire page
+ $.blockUI = function(opts) { install(window, opts); };
+ $.unblockUI = function(opts) { remove(window, opts); };
+
+ // convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
+ $.growlUI = function(title, message, timeout, onClose) {
+ var $m = $('<div class="growlUI"></div>');
+ if (title) $m.append('<h1>'+title+'</h1>');
+ if (message) $m.append('<h2>'+message+'</h2>');
+ if (timeout === undefined) timeout = 3000;
+
+ // Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications
+ var callBlock = function(opts) {
+ opts = opts || {};
+
+ $.blockUI({
+ message: $m,
+ fadeIn : typeof opts.fadeIn !== 'undefined' ? opts.fadeIn : 700,
+ fadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000,
+ timeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout,
+ centerY: false,
+ showOverlay: false,
+ onUnblock: onClose,
+ css: $.blockUI.defaults.growlCSS
+ });
+ };
+
+ callBlock();
+ var nonmousedOpacity = $m.css('opacity');
+ $m.mouseover(function() {
+ callBlock({
+ fadeIn: 0,
+ timeout: 30000
+ });
+
+ var displayBlock = $('.blockMsg');
+ displayBlock.stop(); // cancel fadeout if it has started
+ displayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency
+ }).mouseout(function() {
+ $('.blockMsg').fadeOut(1000);
+ });
+ // End konapun additions
+ };
+
+ // plugin method for blocking element content
+ $.fn.block = function(opts) {
+ if ( this[0] === window ) {
+ $.blockUI( opts );
+ return this;
+ }
+ var fullOpts = $.extend({}, $.blockUI.defaults, opts || {});
+ this.each(function() {
+ var $el = $(this);
+ if (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked'))
+ return;
+ $el.unblock({ fadeOut: 0 });
+ });
+
+ return this.each(function() {
+ if ($.css(this,'position') == 'static') {
+ this.style.position = 'relative';
+ $(this).data('blockUI.static', true);
+ }
+ this.style.zoom = 1; // force 'hasLayout' in ie
+ install(this, opts);
+ });
+ };
+
+ // plugin method for unblocking element content
+ $.fn.unblock = function(opts) {
+ if ( this[0] === window ) {
+ $.unblockUI( opts );
+ return this;
+ }
+ return this.each(function() {
+ remove(this, opts);
+ });
+ };
+
+ $.blockUI.version = 2.66; // 2nd generation blocking at no extra cost!
+
+ // override these in your code to change the default behavior and style
+ $.blockUI.defaults = {
+ // message displayed when blocking (use null for no message)
+ message: '<h1>Please wait...</h1>',
+
+ title: null, // title string; only used when theme == true
+ draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
+
+ theme: false, // set to true to use with jQuery UI themes
+
+ // styles for the message when blocking; if you wish to disable
+ // these and use an external stylesheet then do this in your code:
+ // $.blockUI.defaults.css = {};
+ css: {
+ padding: 0,
+ margin: 0,
+ width: '30%',
+ top: '40%',
+ left: '35%',
+ textAlign: 'center',
+ color: '#000',
+ border: '3px solid #aaa',
+ backgroundColor:'#fff',
+ cursor: 'wait'
+ },
+
+ // minimal style set used when themes are used
+ themedCSS: {
+ width: '30%',
+ top: '40%',
+ left: '35%'
+ },
+
+ // styles for the overlay
+ overlayCSS: {
+ backgroundColor: '#000',
+ opacity: 0.6,
+ cursor: 'wait'
+ },
+
+ // style to replace wait cursor before unblocking to correct issue
+ // of lingering wait cursor
+ cursorReset: 'default',
+
+ // styles applied when using $.growlUI
+ growlCSS: {
+ width: '350px',
+ top: '10px',
+ left: '',
+ right: '10px',
+ border: 'none',
+ padding: '5px',
+ opacity: 0.6,
+ cursor: 'default',
+ color: '#fff',
+ backgroundColor: '#000',
+ '-webkit-border-radius':'10px',
+ '-moz-border-radius': '10px',
+ 'border-radius': '10px'
+ },
+
+ // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
+ // (hat tip to Jorge H. N. de Vasconcelos)
+ /*jshint scripturl:true */
+ iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
+
+ // force usage of iframe in non-IE browsers (handy for blocking applets)
+ forceIframe: false,
+
+ // z-index for the blocking overlay
+ baseZ: 1000,
+
+ // set these to true to have the message automatically centered
+ centerX: true, // <-- only effects element blocking (page block controlled via css above)
+ centerY: true,
+
+ // allow body element to be stetched in ie6; this makes blocking look better
+ // on "short" pages. disable if you wish to prevent changes to the body height
+ allowBodyStretch: true,
+
+ // enable if you want key and mouse events to be disabled for content that is blocked
+ bindEvents: true,
+
+ // be default blockUI will supress tab navigation from leaving blocking content
+ // (if bindEvents is true)
+ constrainTabKey: true,
+
+ // fadeIn time in millis; set to 0 to disable fadeIn on block
+ fadeIn: 200,
+
+ // fadeOut time in millis; set to 0 to disable fadeOut on unblock
+ fadeOut: 400,
+
+ // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
+ timeout: 0,
+
+ // disable if you don't want to show the overlay
+ showOverlay: true,
+
+ // if true, focus will be placed in the first available input field when
+ // page blocking
+ focusInput: true,
+
+ // elements that can receive focus
+ focusableElements: ':input:enabled:visible',
+
+ // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
+ // no longer needed in 2012
+ // applyPlatformOpacityRules: true,
+
+ // callback method invoked when fadeIn has completed and blocking message is visible
+ onBlock: null,
+
+ // callback method invoked when unblocking has completed; the callback is
+ // passed the element that has been unblocked (which is the window object for page
+ // blocks) and the options that were passed to the unblock call:
+ // onUnblock(element, options)
+ onUnblock: null,
+
+ // callback method invoked when the overlay area is clicked.
+ // setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used.
+ onOverlayClick: null,
+
+ // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
+ quirksmodeOffsetHack: 4,
+
+ // class name of the message block
+ blockMsgClass: 'blockMsg',
+
+ // if it is already blocked, then ignore it (don't unblock and reblock)
+ ignoreIfBlocked: false
+ };
+
+ // private data and functions follow...
+
+ var pageBlock = null;
+ var pageBlockEls = [];
+
+ function install(el, opts) {
+ var css, themedCSS;
+ var full = (el == window);
+ var msg = (opts && opts.message !== undefined ? opts.message : undefined);
+ opts = $.extend({}, $.blockUI.defaults, opts || {});
+
+ if (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked'))
+ return;
+
+ opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
+ css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
+ if (opts.onOverlayClick)
+ opts.overlayCSS.cursor = 'pointer';
+
+ themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
+ msg = msg === undefined ? opts.message : msg;
+
+ // remove the current block (if there is one)
+ if (full && pageBlock)
+ remove(window, {fadeOut:0});
+
+ // if an existing element is being used as the blocking content then we capture
+ // its current place in the DOM (and current display style) so we can restore
+ // it when we unblock
+ if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
+ var node = msg.jquery ? msg[0] : msg;
+ var data = {};
+ $(el).data('blockUI.history', data);
+ data.el = node;
+ data.parent = node.parentNode;
+ data.display = node.style.display;
+ data.position = node.style.position;
+ if (data.parent)
+ data.parent.removeChild(node);
+ }
+
+ $(el).data('blockUI.onUnblock', opts.onUnblock);
+ var z = opts.baseZ;
+
+ // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
+ // layer1 is the iframe layer which is used to supress bleed through of underlying content
+ // layer2 is the overlay layer which has opacity and a wait cursor (by default)
+ // layer3 is the message content that is displayed while blocking
+ var lyr1, lyr2, lyr3, s;
+ if (msie || opts.forceIframe)
+ lyr1 = $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>');
+ else
+ lyr1 = $('<div class="blockUI" style="display:none"></div>');
+
+ if (opts.theme)
+ lyr2 = $('<div class="blockUI blockOverlay ui-widget-overlay" style="z-index:'+ (z++) +';display:none"></div>');
+ else
+ lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
+
+ if (opts.theme && full) {
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:fixed">';
+ if ( opts.title ) {
+ s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
+ }
+ s += '<div class="ui-widget-content ui-dialog-content"></div>';
+ s += '</div>';
+ }
+ else if (opts.theme) {
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:absolute">';
+ if ( opts.title ) {
+ s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
+ }
+ s += '<div class="ui-widget-content ui-dialog-content"></div>';
+ s += '</div>';
+ }
+ else if (full) {
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:'+(z+10)+';display:none;position:fixed"></div>';
+ }
+ else {
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
+ }
+ lyr3 = $(s);
+
+ // if we have a message, style it
+ if (msg) {
+ if (opts.theme) {
+ lyr3.css(themedCSS);
+ lyr3.addClass('ui-widget-content');
+ }
+ else
+ lyr3.css(css);
+ }
+
+ // style the overlay
+ if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/)
+ lyr2.css(opts.overlayCSS);
+ lyr2.css('position', full ? 'fixed' : 'absolute');
+
+ // make iframe layer transparent in IE
+ if (msie || opts.forceIframe)
+ lyr1.css('opacity',0.0);
+
+ //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
+ var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
+ $.each(layers, function() {
+ this.appendTo($par);
+ });
+
+ if (opts.theme && opts.draggable && $.fn.draggable) {
+ lyr3.draggable({
+ handle: '.ui-dialog-titlebar',
+ cancel: 'li'
+ });
+ }
+
+ // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
+ var expr = setExpr && (!$.support.boxModel || $('object,embed', full ? null : el).length > 0);
+ if (ie6 || expr) {
+ // give body 100% height
+ if (full && opts.allowBodyStretch && $.support.boxModel)
+ $('html,body').css('height','100%');
+
+ // fix ie6 issue when blocked element has a border width
+ if ((ie6 || !$.support.boxModel) && !full) {
+ var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
+ var fixT = t ? '(0 - '+t+')' : 0;
+ var fixL = l ? '(0 - '+l+')' : 0;
+ }
+
+ // simulate fixed position
+ $.each(layers, function(i,o) {
+ var s = o[0].style;
+ s.position = 'absolute';
+ if (i < 2) {
+ if (full)
+ s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"');
+ else
+ s.setExpression('height','this.parentNode.offsetHeight + "px"');
+ if (full)
+ s.setExpression('width','jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"');
+ else
+ s.setExpression('width','this.parentNode.offsetWidth + "px"');
+ if (fixL) s.setExpression('left', fixL);
+ if (fixT) s.setExpression('top', fixT);
+ }
+ else if (opts.centerY) {
+ if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
+ s.marginTop = 0;
+ }
+ else if (!opts.centerY && full) {
+ var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0;
+ var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
+ s.setExpression('top',expression);
+ }
+ });
+ }
+
+ // show the message
+ if (msg) {
+ if (opts.theme)
+ lyr3.find('.ui-widget-content').append(msg);
+ else
+ lyr3.append(msg);
+ if (msg.jquery || msg.nodeType)
+ $(msg).show();
+ }
+
+ if ((msie || opts.forceIframe) && opts.showOverlay)
+ lyr1.show(); // opacity is zero
+ if (opts.fadeIn) {
+ var cb = opts.onBlock ? opts.onBlock : noOp;
+ var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
+ var cb2 = msg ? cb : noOp;
+ if (opts.showOverlay)
+ lyr2._fadeIn(opts.fadeIn, cb1);
+ if (msg)
+ lyr3._fadeIn(opts.fadeIn, cb2);
+ }
+ else {
+ if (opts.showOverlay)
+ lyr2.show();
+ if (msg)
+ lyr3.show();
+ if (opts.onBlock)
+ opts.onBlock();
+ }
+
+ // bind key and mouse events
+ bind(1, el, opts);
+
+ if (full) {
+ pageBlock = lyr3[0];
+ pageBlockEls = $(opts.focusableElements,pageBlock);
+ if (opts.focusInput)
+ setTimeout(focus, 20);
+ }
+ else
+ center(lyr3[0], opts.centerX, opts.centerY);
+
+ if (opts.timeout) {
+ // auto-unblock
+ var to = setTimeout(function() {
+ if (full)
+ $.unblockUI(opts);
+ else
+ $(el).unblock(opts);
+ }, opts.timeout);
+ $(el).data('blockUI.timeout', to);
+ }
+ }
+
+ // remove the block
+ function remove(el, opts) {
+ var count;
+ var full = (el == window);
+ var $el = $(el);
+ var data = $el.data('blockUI.history');
+ var to = $el.data('blockUI.timeout');
+ if (to) {
+ clearTimeout(to);
+ $el.removeData('blockUI.timeout');
+ }
+ opts = $.extend({}, $.blockUI.defaults, opts || {});
+ bind(0, el, opts); // unbind events
+
+ if (opts.onUnblock === null) {
+ opts.onUnblock = $el.data('blockUI.onUnblock');
+ $el.removeData('blockUI.onUnblock');
+ }
+
+ var els;
+ if (full) // crazy selector to handle odd field errors in ie6/7
+ els = $('body').children().filter('.blockUI').add('body > .blockUI');
+ else
+ els = $el.find('>.blockUI');
+
+ // fix cursor issue
+ if ( opts.cursorReset ) {
+ if ( els.length > 1 )
+ els[1].style.cursor = opts.cursorReset;
+ if ( els.length > 2 )
+ els[2].style.cursor = opts.cursorReset;
+ }
+
+ if (full)
+ pageBlock = pageBlockEls = null;
+
+ if (opts.fadeOut) {
+ count = els.length;
+ els.stop().fadeOut(opts.fadeOut, function() {
+ if ( --count === 0)
+ reset(els,data,opts,el);
+ });
+ }
+ else
+ reset(els, data, opts, el);
+ }
+
+ // move blocking element back into the DOM where it started
+ function reset(els,data,opts,el) {
+ var $el = $(el);
+ if ( $el.data('blockUI.isBlocked') )
+ return;
+
+ els.each(function(i,o) {
+ // remove via DOM calls so we don't lose event handlers
+ if (this.parentNode)
+ this.parentNode.removeChild(this);
+ });
+
+ if (data && data.el) {
+ data.el.style.display = data.display;
+ data.el.style.position = data.position;
+ if (data.parent)
+ data.parent.appendChild(data.el);
+ $el.removeData('blockUI.history');
+ }
+
+ if ($el.data('blockUI.static')) {
+ $el.css('position', 'static'); // #22
+ }
+
+ if (typeof opts.onUnblock == 'function')
+ opts.onUnblock(el,opts);
+
+ // fix issue in Safari 6 where block artifacts remain until reflow
+ var body = $(document.body), w = body.width(), cssW = body[0].style.width;
+ body.width(w-1).width(w);
+ body[0].style.width = cssW;
+ }
+
+ // bind/unbind the handler
+ function bind(b, el, opts) {
+ var full = el == window, $el = $(el);
+
+ // don't bother unbinding if there is nothing to unbind
+ if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
+ return;
+
+ $el.data('blockUI.isBlocked', b);
+
+ // don't bind events when overlay is not in use or if bindEvents is false
+ if (!full || !opts.bindEvents || (b && !opts.showOverlay))
+ return;
+
+ // bind anchors and inputs for mouse and key events
+ var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove';
+ if (b)
+ $(document).bind(events, opts, handler);
+ else
+ $(document).unbind(events, handler);
+
+ // former impl...
+ // var $e = $('a,:input');
+ // b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
+ }
+
+ // event handler to suppress keyboard/mouse events when blocking
+ function handler(e) {
+ // allow tab navigation (conditionally)
+ if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) {
+ if (pageBlock && e.data.constrainTabKey) {
+ var els = pageBlockEls;
+ var fwd = !e.shiftKey && e.target === els[els.length-1];
+ var back = e.shiftKey && e.target === els[0];
+ if (fwd || back) {
+ setTimeout(function(){focus(back);},10);
+ return false;
+ }
+ }
+ }
+ var opts = e.data;
+ var target = $(e.target);
+ if (target.hasClass('blockOverlay') && opts.onOverlayClick)
+ opts.onOverlayClick(e);
+
+ // allow events within the message content
+ if (target.parents('div.' + opts.blockMsgClass).length > 0)
+ return true;
+
+ // allow events for content that is not being blocked
+ return target.parents().children().filter('div.blockUI').length === 0;
+ }
+
+ function focus(back) {
+ if (!pageBlockEls)
+ return;
+ var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
+ if (e)
+ e.focus();
+ }
+
+ function center(el, x, y) {
+ var p = el.parentNode, s = el.style;
+ var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
+ var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
+ if (x) s.left = l > 0 ? (l+'px') : '0';
+ if (y) s.top = t > 0 ? (t+'px') : '0';
+ }
+
+ function sz(el, p) {
+ return parseInt($.css(el,p),10)||0;
+ }
+
+ }
+
+
+ /*global define:true */
+ if (typeof define === 'function' && define.amd && define.amd.jQuery) {
+ define(['jquery'], setup);
+ } else {
+ setup(jQuery);
+ }
+
+})(); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jquery.dynamiccarousel.js b/SemanticResultFormats/resources/jquery/jquery.dynamiccarousel.js
new file mode 100644
index 00000000..456ec536
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jquery.dynamiccarousel.js
@@ -0,0 +1,526 @@
+/*! (c) Mat Marquis (@wilto). MIT License. http://wil.to/3a */
+
+(function( $, undefined ) {
+ var inst = 0;
+
+ $.fn.getPercentage = function() {
+ var oPercent = this.attr('style').match(/margin\-left:(.*[0-9])/i) && parseInt(RegExp.$1);
+
+ return oPercent;
+ };
+
+ $.fn.adjRounding = function(slide) {
+ var $el = $(this),
+ $slides = $el.find( slide ),
+ diff = $el.parent().width() - $($slides[0]).width();
+
+ if (diff !== 0) {
+ $($slides).css( "position", "relative" );
+
+ for (var i = 0; i < $slides.length; i++) {
+ $($slides[i]).css( "left", (diff * i) + "px" );
+ }
+ }
+
+ return this;
+ };
+
+ $.fn.carousel = function(config) {
+
+ // Prevent re-init:
+ if( this.data( "carousel-initialized" ) ) { return; }
+
+ // Carousel is being initialized:
+ this.data( "carousel-initialized", true );
+
+ var defaults = {
+ slider : '.slider',
+ slide : '.slide',
+ prevSlide : null,
+ nextSlide : null,
+ slideHed : null,
+ addPagination : false,
+ addNav : ( config != undefined && ( config.prevSlide || config.nextSlide ) ) ? false : true,
+ namespace : 'carousel',
+ speed : 300
+ },
+ opt = $.extend(defaults, config),
+ $slidewrap = this,
+ dStyle = document.body.style,
+ transitionSupport = dStyle.webkitTransition !== undefined ||
+ dStyle.mozTransition !== undefined ||
+ dStyle.msTransition !== undefined ||
+ dStyle.OTransition !== undefined ||
+ dStyle.transition !== undefined,
+ carousel = {
+ init : function() {
+ inst++;
+
+ $slidewrap.each(function(carInt) {
+ var $wrap = $(this),
+ $slider = $wrap.find(opt.slider),
+ $slide = $wrap.find(opt.slide),
+ slidenum = $slide.length,
+ transition = "margin-left " + ( opt.speed / 1000 ) + "s ease",
+ tmp = 'carousel-' + inst + '-' + carInt;
+
+ if( $slide.length <= 1 ) {
+ return; /* No sense running all this code if the carousel functionality is unnecessary. */
+ }
+
+ $wrap
+ .css({
+ overflow : "hidden",
+ width : "100%"
+ })
+ .attr('role' , 'application');
+
+ $slider
+ .attr( 'id', ( $slider[0].id || 'carousel-' + inst + '-' + carInt ) )
+ .css({
+ "marginLeft" : "0px",
+ "float" : "left",
+ "width" : 100 * slidenum + "%",
+ "-webkit-transition" : transition,
+ "-moz-transition" : transition,
+ "-ms-transition" : transition,
+ "-o-transition" : transition,
+ "transition" : transition
+ })
+ .bind( 'carouselmove' , carousel.move )
+ .bind( 'nextprev' , carousel.nextPrev )
+ .bind( 'navstate' , carousel.navState );
+
+ $slide
+ .css({
+ "float": "left",
+ width: (100 / slidenum) + "%"
+ })
+ .each(function(i) {
+ var $el = $(this);
+
+ $el.attr({
+ role : "tabpanel document",
+ id : tmp + '-slide' + i
+ });
+
+ if( opt.addPagination ) {
+ $el.attr('aria-labelledby', tmp + '-tab' + i);
+ }
+ });
+
+ // Build and insert navigation/pagination, if specified in the options:
+ opt.addPagination && carousel.addPagination();
+ opt.addNav && carousel.addNav();
+
+ $slider.trigger( "navstate", { current: 0 });
+ });
+ },
+ addNav : function() {
+ $slidewrap.each(function(i) {
+ var $oEl = $(this),
+ $slider = $oEl.find(opt.slider),
+ currentSlider = $slider[0].id,
+ navMarkup = [
+ '<ul class="slidecontrols" role="navigation">',
+ ' <li role="presentation"><a href="#' + currentSlider + '" class="' + opt.namespace + '-next">Next</a></li>',
+ ' <li role="presentation"><a href="#' + currentSlider + '" class="' + opt.namespace + '-prev">Prev</a></li>',
+ '</ul>'
+ ].join(''),
+ nextprev = {
+ nextSlide : '.' + opt.namespace + '-next',
+ prevSlide : '.' + opt.namespace + '-prev'
+ };
+
+ opt = $.extend(opt, nextprev);
+
+ $oEl.prepend(navMarkup);
+ });
+ },
+ addPagination : function() {
+ $slidewrap.each(function(i) {
+ var $oEl = $(this),
+ $pagination = $('<ol class="' + opt.namespace + '-tabs" role="tablist navigation" />'),
+ $slider = $oEl.find(opt.slider),
+ $slides = $oEl.find(opt.slide)
+ slideNum = $slides.length,
+ associated = 'carousel-' + inst + '-' + i;
+
+ while( slideNum-- ) {
+ var hed = $( $slides[ slideNum ] ).find( opt.slideHed ).text() || 'Page ' + ( slideNum + 1 ),
+ tabMarkup = [
+ '<li role="presentation">',
+ '<a href="#' + associated + '-slide' + slideNum +'"',
+ ' aria-controls="' + associated + '-slide' + slideNum +'"',
+ ' id="' + associated + '-tab' + slideNum + '" role="tab">' + hed + '</a>',
+ '</li>'
+ ].join('');
+
+ $pagination.prepend(tabMarkup);
+ };
+
+ $pagination
+ .appendTo( $oEl )
+ .find('li').keydown( function(e) {
+ var $el = $(this),
+ $prevTab = $el.prev().find('a'),
+ $nextTab = $el.next().find('a');
+
+ switch( e.which ) {
+ case 37:
+ case 38:
+ $prevTab.length && $prevTab.trigger('click').focus();
+ e.preventDefault();
+ break;
+ case 39:
+ case 40:
+ $nextTab.length && $nextTab.trigger('click').focus();
+ e.preventDefault();
+ break;
+ }
+ })
+ .find('a').click( function(e) {
+ var $el = $(this);
+
+ if( $el.attr('aria-selected') == 'true' ) {
+ var current = $el.parent().index(),
+ move = -( 100 * ( current ) ),
+ $slider = $oEl.find( opt.slider );
+
+ $slider.trigger( 'carouselmove', { moveTo: move });
+ }
+ e.preventDefault();
+ });
+ });
+ },
+ roundDown : function(oVal) {
+ var val = parseInt(oVal, 10);
+
+ return Math.ceil( (val - (val % 100 ) ) / 100) * 100;
+ },
+ navState : function(e, ui) {
+ var $el = $(this),
+ $slides = $el.find(opt.slide),
+ ind = -(ui.current / 100),
+ $activeSlide = $($slides[ind]);
+
+ $el.attr('aria-activedescendant', $activeSlide[0].id);
+
+ // Update state of active tabpanel:
+ $activeSlide
+ .addClass( opt.namespace + "-active-slide" )
+ .attr( 'aria-hidden', false )
+ .siblings()
+ .removeClass( opt.namespace + "-active-slide" )
+ .attr( 'aria-hidden', true );
+
+ // Update state of next/prev navigation:
+ if( ( !!opt.prevSlide || !!opt.nextSlide ) ) {
+ var $target = $('[href*="#' + this.id + '"]');
+
+ $target.removeClass( opt.namespace + '-disabled' );
+
+ if( ind == 0 ) {
+ $target.filter(opt.prevSlide).addClass( opt.namespace + '-disabled' );
+ } else if( ind == $slides.length - 1 ) {
+ $target.filter(opt.nextSlide).addClass( opt.namespace + '-disabled' );
+ }
+ }
+
+ // Update state of pagination tabs:
+ if( !!opt.addPagination ) {
+ var tabId = $activeSlide.attr('aria-labelledby'),
+ $tab = $('#' + tabId );
+
+ $tab
+ .parent()
+ .addClass(opt.namespace + '-active-tab')
+ .siblings()
+ .removeClass(opt.namespace + '-active-tab')
+ .find('a')
+ .attr({
+ 'aria-selected' : false,
+ 'tabindex' : -1
+ });
+
+ $tab.attr({
+ 'aria-selected' : true,
+ 'tabindex' : 0
+ });
+ }
+ },
+ move : function(e, ui) {
+ var $el = $(this);
+
+ $el
+ .trigger(opt.namespace + "-beforemove")
+ .trigger("navstate", { current: ui.moveTo });
+
+ if( transitionSupport ) {
+
+ $el
+ .adjRounding( opt.slide ) /* Accounts for browser rounding errors. Lookin’ at you, iOS Safari. */
+ .css('marginLeft', ui.moveTo + "%")
+ .one("transitionend webkitTransitionEnd OTransitionEnd", function() {
+ $(this).trigger( opt.namespace + "-aftermove" );
+ });
+
+ } else {
+ $el
+ .adjRounding( opt.slide )
+ .animate({ marginLeft: ui.moveTo + "%" }, { duration : opt.speed, queue : false }, function() {
+ $(this).trigger( opt.namespace + "-aftermove" );
+ });
+ }
+ },
+ nextPrev : function(e, ui) {
+ var $el = $(this),
+ left = ( $el ) ? $el.getPercentage() : 0,
+ $slide = $el.find(opt.slide),
+ constrain = ui.dir === 'prev' ? left != 0 : -left < ($slide.length - 1) * 100,
+ $target = $( '[href="#' + this.id + '"]');
+
+ if (!$el.is(":animated") && constrain ) {
+
+ if ( ui.dir === 'prev' ) {
+ left = ( left % 100 != 0 ) ? carousel.roundDown(left) : left + 100;
+ } else {
+ left = ( ( left % 100 ) != 0 ) ? carousel.roundDown(left) - 100 : left - 100;
+ }
+
+ $el.trigger('carouselmove', { moveTo: left });
+
+ $target
+ .removeClass( opt.namespace + '-disabled')
+ .removeAttr('aria-disabled');
+
+ switch( left ) {
+ case ( -($slide.length - 1) * 100 ):
+ $target.filter(opt.nextSlide)
+ .addClass( opt.namespace + '-disabled')
+ .attr('aria-disabled', true);
+ break;
+ case 0:
+ $target.filter(opt.prevSlide)
+ .addClass( opt.namespace + '-disabled')
+ .attr('aria-disabled', true);
+ break;
+ }
+ } else {
+ var reset = carousel.roundDown(left);
+
+ $el.trigger('carouselmove', { moveTo: reset });
+ }
+
+ }
+ };
+
+ carousel.init(this);
+
+ $(opt.nextSlide + ',' + opt.prevSlide)
+ .bind('click', function(e) {
+ var $el = $(this),
+ link = this.hash,
+ dir = ( $el.is(opt.prevSlide) ) ? 'prev' : 'next',
+ $slider = $(link);
+
+ if ( $el.is('.' + opt.namespace + '-disabled') ) {
+ return false;
+ }
+
+ $slider.trigger('nextprev', { dir: dir });
+
+ e.preventDefault();
+ })
+ .bind('keydown', function(e) {
+ var $el = $(this),
+ link = this.hash;
+
+ switch (e.which) {
+ case 37:
+ case 38:
+ $('#' + link).trigger('nextprev', { dir: 'next' });
+ e.preventDefault();
+ break;
+ case 39:
+ case 40:
+ $('#' + link).trigger('nextprev', { dir: 'prev' });
+ e.preventDefault();
+ break;
+ }
+ });
+
+ var setup = {
+ wrap : this,
+ slider : opt.slider
+ };
+ $slidewrap.bind( "dragSnap", setup, function(e, ui){
+ var $slider = $(this).find( opt.slider ),
+ dir = ( ui.direction === "left" ) ? 'next' : 'prev';
+
+ $slider.trigger("nextprev", { dir: dir });
+ });
+
+
+ $slidewrap.filter('[data-autorotate]').each(function() {
+ var auto,
+ $el = $(this),
+ speed = $el.attr('data-autorotate'),
+ slidenum = $el.find(opt.slide).length,
+ autoAdvance = function() {
+ var $slider = $el.find(opt.slider),
+ active = -( $(opt.slider).getPercentage() / 100 ) + 1;
+
+ switch( active ) {
+ case slidenum:
+ clearInterval(auto);
+
+ auto = setInterval(function() {
+ autoAdvance();
+ $slider.trigger("nextprev", { dir: 'prev' });
+ }, speed);
+
+ break;
+ case 1:
+ clearInterval(auto);
+
+ auto = setInterval(function() {
+ autoAdvance();
+ $slider.trigger("nextprev", { dir: 'next' });
+ }, speed);
+
+ break;
+ }
+ };
+
+ auto = setInterval(autoAdvance, speed);
+
+ $el
+ .attr('aria-live', 'polite')
+ .bind('mouseenter click touchstart', function() {
+ clearInterval(auto);
+ });
+ });
+
+ return this;
+ };
+})(jQuery);
+
+
+$.event.special.dragSnap = {
+ setup: function(setup) {
+
+ var $el = $(this),
+ transitionSwap = function($el, tog) {
+ var speed = .3,
+ transition = ( tog ) ? "margin-left " + speed + "s ease" : 'none';
+
+ $el.css({
+ "-webkit-transition" : transition,
+ "-moz-transition" : transition,
+ "-ms-transition" : transition,
+ "-o-transition" : transition,
+ "transition" : transition
+ });
+ },
+ roundDown = function(left) {
+ var left = parseInt(left, 10);
+
+ return Math.ceil( (left - (left % 100 ) ) / 100) * 100;
+ },
+ snapBack = function(e, ui) {
+ var $el = ui.target,
+ currentPos = ( $el.attr('style') != undefined ) ? $el.getPercentage() : 0,
+ left = (ui.left === false) ? roundDown(currentPos) - 100 : roundDown(currentPos),
+ dStyle = document.body.style,
+ transitionSupport = dStyle.webkitTransition !== undefined ||
+ dStyle.mozTransition !== undefined ||
+ dStyle.msTransition !== undefined ||
+ dStyle.oTransition !== undefined ||
+ dStyle.transition !== undefined;
+
+ transitionSwap($el, true);
+
+ if( transitionSupport ) {
+ $el.css('marginLeft', left + "%");
+ } else {
+ $el.animate({ marginLeft: left + "%" }, opt.speed);
+ }
+ };
+
+ $el
+ .bind("snapback", snapBack)
+ .bind("touchstart", function(e) {
+ var data = e.originalEvent.touches ? e.originalEvent.touches[0] : e,
+ start = {
+ time: (new Date).getTime(),
+ coords: [ data.pageX, data.pageY ],
+ origin: $(e.target).closest( setup.wrap )
+ },
+ stop,
+ $tEl = $(e.target).closest( setup.slider ),
+ currentPos = ( $tEl.attr('style') != undefined ) ? $tEl.getPercentage() : 0;
+
+ transitionSwap($tEl, false);
+
+ function moveHandler(e) {
+ var data = e.originalEvent.touches ? e.originalEvent.touches[0] : e;
+ stop = {
+ time: (new Date).getTime(),
+ coords: [ data.pageX, data.pageY ]
+ };
+
+ if(!start || Math.abs(start.coords[0] - stop.coords[0]) < Math.abs(start.coords[1] - stop.coords[1]) ) {
+ return;
+ }
+
+ $tEl.css({"margin-left": currentPos + ( ( (stop.coords[0] - start.coords[0]) / start.origin.width() ) * 100 ) + '%' });
+
+ // prevent scrolling
+ if (Math.abs(start.coords[0] - stop.coords[0]) > 10) {
+ e.preventDefault();
+ }
+
+ };
+
+ $el
+ .bind("gesturestart", function(e) {
+ $el
+ .unbind("touchmove", moveHandler)
+ .unbind("touchend", moveHandler);
+ })
+ .bind("touchmove", moveHandler)
+ .one("touchend", function(e) {
+
+ $el.unbind("touchmove", moveHandler);
+
+ transitionSwap($tEl, true);
+
+ if (start && stop ) {
+
+ if (Math.abs(start.coords[0] - stop.coords[0]) > 10
+ && Math.abs(start.coords[0] - stop.coords[0]) > Math.abs(start.coords[1] - stop.coords[1])) {
+ e.preventDefault();
+ } else {
+ $el.trigger('snapback', { target: $tEl, left: true });
+ return;
+ }
+
+ if (Math.abs(start.coords[0] - stop.coords[0]) > 1 && Math.abs(start.coords[1] - stop.coords[1]) < 75) {
+ var left = start.coords[0] > stop.coords[0];
+
+ if( -( stop.coords[0] - start.coords[0]) > ( start.origin.width() / 4 ) || ( stop.coords[0] - start.coords[0]) > ( start.origin.width() / 4 ) ) {
+
+ start.origin.trigger("dragSnap", {direction: left ? "left" : "right"});
+
+ } else {
+ $el.trigger('snapback', { target: $tEl, left: left });
+ }
+
+ }
+ }
+ start = stop = undefined;
+ });
+ });
+ }
+}; \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jquery.easing.js b/SemanticResultFormats/resources/jquery/jquery.easing.js
new file mode 100644
index 00000000..2e679986
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jquery.easing.js
@@ -0,0 +1,205 @@
+/*
+ * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
+ *
+ * Uses the built in easing capabilities added In jQuery 1.1
+ * to offer multiple easing options
+ *
+ * TERMS OF USE - jQuery Easing
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2008 George McGinley Smith
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+
+// t: current time, b: begInnIng value, c: change In value, d: duration
+jQuery.easing['jswing'] = jQuery.easing['swing'];
+
+jQuery.extend( jQuery.easing,
+{
+ def: 'easeOutQuad',
+ swing: function (x, t, b, c, d) {
+ //alert(jQuery.easing.default);
+ return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
+ },
+ easeInQuad: function (x, t, b, c, d) {
+ return c*(t/=d)*t + b;
+ },
+ easeOutQuad: function (x, t, b, c, d) {
+ return -c *(t/=d)*(t-2) + b;
+ },
+ easeInOutQuad: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t + b;
+ return -c/2 * ((--t)*(t-2) - 1) + b;
+ },
+ easeInCubic: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t + b;
+ },
+ easeOutCubic: function (x, t, b, c, d) {
+ return c*((t=t/d-1)*t*t + 1) + b;
+ },
+ easeInOutCubic: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t + b;
+ return c/2*((t-=2)*t*t + 2) + b;
+ },
+ easeInQuart: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t*t + b;
+ },
+ easeOutQuart: function (x, t, b, c, d) {
+ return -c * ((t=t/d-1)*t*t*t - 1) + b;
+ },
+ easeInOutQuart: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
+ return -c/2 * ((t-=2)*t*t*t - 2) + b;
+ },
+ easeInQuint: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t*t*t + b;
+ },
+ easeOutQuint: function (x, t, b, c, d) {
+ return c*((t=t/d-1)*t*t*t*t + 1) + b;
+ },
+ easeInOutQuint: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
+ return c/2*((t-=2)*t*t*t*t + 2) + b;
+ },
+ easeInSine: function (x, t, b, c, d) {
+ return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
+ },
+ easeOutSine: function (x, t, b, c, d) {
+ return c * Math.sin(t/d * (Math.PI/2)) + b;
+ },
+ easeInOutSine: function (x, t, b, c, d) {
+ return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
+ },
+ easeInExpo: function (x, t, b, c, d) {
+ return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
+ },
+ easeOutExpo: function (x, t, b, c, d) {
+ return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
+ },
+ easeInOutExpo: function (x, t, b, c, d) {
+ if (t==0) return b;
+ if (t==d) return b+c;
+ if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
+ return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
+ },
+ easeInCirc: function (x, t, b, c, d) {
+ return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
+ },
+ easeOutCirc: function (x, t, b, c, d) {
+ return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
+ },
+ easeInOutCirc: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
+ return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
+ },
+ easeInElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
+ },
+ easeOutElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
+ },
+ easeInOutElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
+ return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
+ },
+ easeInBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ return c*(t/=d)*t*((s+1)*t - s) + b;
+ },
+ easeOutBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
+ },
+ easeInOutBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
+ return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
+ },
+ easeInBounce: function (x, t, b, c, d) {
+ return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
+ },
+ easeOutBounce: function (x, t, b, c, d) {
+ if ((t/=d) < (1/2.75)) {
+ return c*(7.5625*t*t) + b;
+ } else if (t < (2/2.75)) {
+ return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
+ } else if (t < (2.5/2.75)) {
+ return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
+ } else {
+ return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
+ }
+ },
+ easeInOutBounce: function (x, t, b, c, d) {
+ if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
+ return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
+ }
+});
+
+/*
+ *
+ * TERMS OF USE - EASING EQUATIONS
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2001 Robert Penner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */ \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jquery.jStorage.js b/SemanticResultFormats/resources/jquery/jquery.jStorage.js
new file mode 100644
index 00000000..6ca21b5c
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jquery.jStorage.js
@@ -0,0 +1,1143 @@
+/*
+ * ----------------------------- JSTORAGE -------------------------------------
+ * Simple local storage wrapper to save data on the browser side, supporting
+ * all major browsers - IE6+, Firefox2+, Safari4+, Chrome4+ and Opera 10.5+
+ *
+ * Copyright (c) 2010 - 2012 Andris Reinman, andris.reinman@gmail.com
+ * Project homepage: www.jstorage.info
+ *
+ * Licensed under MIT-style license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+ (function(){
+ var
+ /* jStorage version */
+ JSTORAGE_VERSION = "0.3.0",
+
+ /* detect a dollar object or create one if not found */
+ $ = window.jQuery || window.$ || (window.$ = {}),
+
+ /* check for a JSON handling support */
+ JSON = {
+ parse:
+ window.JSON && (window.JSON.parse || window.JSON.decode) ||
+ String.prototype.evalJSON && function(str){return String(str).evalJSON();} ||
+ $.parseJSON ||
+ $.evalJSON,
+ stringify:
+ Object.toJSON ||
+ window.JSON && (window.JSON.stringify || window.JSON.encode) ||
+ $.toJSON
+ };
+
+ // Break if no JSON support was found
+ if(!JSON.parse || !JSON.stringify){
+ throw new Error("No JSON support found, include //cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js to page");
+ }
+
+ var
+ /* This is the object, that holds the cached values */
+ _storage = {},
+
+ /* Actual browser storage (localStorage or globalStorage['domain']) */
+ _storage_service = {jStorage:"{}"},
+
+ /* DOM element for older IE versions, holds userData behavior */
+ _storage_elm = null,
+
+ /* How much space does the storage take */
+ _storage_size = 0,
+
+ /* which backend is currently used */
+ _backend = false,
+
+ /* onchange observers */
+ _observers = {},
+
+ /* timeout to wait after onchange event */
+ _observer_timeout = false,
+
+ /* last update time */
+ _observer_update = 0,
+
+ /* pubsub observers */
+ _pubsub_observers = {},
+
+ /* skip published items older than current timestamp */
+ _pubsub_last = +new Date(),
+
+ /* Next check for TTL */
+ _ttl_timeout,
+
+ /* crc32 table */
+ _crc32Table = "00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 "+
+ "0EDB8832 79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 "+
+ "6AB020F2 F3B97148 84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 "+
+ "FD62F97A 8A65C9EC 14015C4F 63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 "+
+ "A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 "+
+ "32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC 51DE003A C8D75180 BFD06116 21B4F4B5 "+
+ "56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 B10BE924 2F6F7C87 58684C11 "+
+ "C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F 9FBFE4A5 "+
+ "E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 "+
+ "6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 "+
+ "12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE "+
+ "A3BC0074 D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 "+
+ "DA60B8D0 44042D73 33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 "+
+ "5768B525 206F85B3 B966D409 CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 "+
+ "2EB40D81 B7BD5C3B C0BA6CAD EDB88320 9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF "+
+ "04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E 7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 "+
+ "7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB 196C3671 6E6B06E7 "+
+ "FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 D6D6A3E8 "+
+ "A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA AF0A1B4C "+
+ "36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 "+
+ "5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 "+
+ "C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 "+
+ "EB0E363F 72076785 05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D "+
+ "7CDCEFB7 0BDBDF21 86D3D2D4 F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 "+
+ "18B74777 88085AE6 FF0F6A70 66063BCA 11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 "+
+ "A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 4969474D 3E6E77DB AED16A4A "+
+ "D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 BDBDF21C CABAC28A "+
+ "53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E C4614AB8 5D681B02 "+
+ "2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D",
+
+ /**
+ * XML encoding and decoding as XML nodes can't be JSON'ized
+ * XML nodes are encoded and decoded if the node is the value to be saved
+ * but not if it's as a property of another object
+ * Eg. -
+ * $.jStorage.set("key", xmlNode); // IS OK
+ * $.jStorage.set("key", {xml: xmlNode}); // NOT OK
+ */
+ _XMLService = {
+
+ /**
+ * Validates a XML node to be XML
+ * based on jQuery.isXML function
+ */
+ isXML: function(elm){
+ var documentElement = (elm ? elm.ownerDocument || elm : 0).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+ },
+
+ /**
+ * Encodes a XML node to string
+ * based on http://www.mercurytide.co.uk/news/article/issues-when-working-ajax/
+ */
+ encode: function(xmlNode) {
+ if(!this.isXML(xmlNode)){
+ return false;
+ }
+ try{ // Mozilla, Webkit, Opera
+ return new XMLSerializer().serializeToString(xmlNode);
+ }catch(E1) {
+ try { // IE
+ return xmlNode.xml;
+ }catch(E2){}
+ }
+ return false;
+ },
+
+ /**
+ * Decodes a XML node from string
+ * loosely based on http://outwestmedia.com/jquery-plugins/xmldom/
+ */
+ decode: function(xmlString){
+ var dom_parser = ("DOMParser" in window && (new DOMParser()).parseFromString) ||
+ (window.ActiveXObject && function(_xmlString) {
+ var xml_doc = new ActiveXObject('Microsoft.XMLDOM');
+ xml_doc.async = 'false';
+ xml_doc.loadXML(_xmlString);
+ return xml_doc;
+ }),
+ resultXML;
+ if(!dom_parser){
+ return false;
+ }
+ resultXML = dom_parser.call("DOMParser" in window && (new DOMParser()) || window, xmlString, 'text/xml');
+ return this.isXML(resultXML)?resultXML:false;
+ }
+ },
+
+ _localStoragePolyfillSetKey = function(){};
+
+
+ ////////////////////////// PRIVATE METHODS ////////////////////////
+
+ /**
+ * Initialization function. Detects if the browser supports DOM Storage
+ * or userData behavior and behaves accordingly.
+ */
+ function _init(){
+ /* Check if browser supports localStorage */
+ var localStorageReallyWorks = false;
+ if("localStorage" in window){
+ try {
+ window.localStorage.setItem('_tmptest', 'tmpval');
+ localStorageReallyWorks = true;
+ window.localStorage.removeItem('_tmptest');
+ } catch(BogusQuotaExceededErrorOnIos5) {
+ // Thanks be to iOS5 Private Browsing mode which throws
+ // QUOTA_EXCEEDED_ERRROR DOM Exception 22.
+ }
+ }
+
+ if(localStorageReallyWorks){
+ try {
+ if(window.localStorage) {
+ _storage_service = window.localStorage;
+ _backend = "localStorage";
+ _observer_update = _storage_service.jStorage_update;
+ }
+ } catch(E3) {/* Firefox fails when touching localStorage and cookies are disabled */}
+ }
+ /* Check if browser supports globalStorage */
+ else if("globalStorage" in window){
+ try {
+ if(window.globalStorage) {
+ _storage_service = window.globalStorage[window.location.hostname];
+ _backend = "globalStorage";
+ _observer_update = _storage_service.jStorage_update;
+ }
+ } catch(E4) {/* Firefox fails when touching localStorage and cookies are disabled */}
+ }
+ /* Check if browser supports userData behavior */
+ else {
+ _storage_elm = document.createElement('link');
+ if(_storage_elm.addBehavior){
+
+ /* Use a DOM element to act as userData storage */
+ _storage_elm.style.behavior = 'url(#default#userData)';
+
+ /* userData element needs to be inserted into the DOM! */
+ document.getElementsByTagName('head')[0].appendChild(_storage_elm);
+
+ try{
+ _storage_elm.load("jStorage");
+ }catch(E){
+ // try to reset cache
+ _storage_elm.setAttribute("jStorage", "{}");
+ _storage_elm.save("jStorage");
+ _storage_elm.load("jStorage");
+ }
+
+ var data = "{}";
+ try{
+ data = _storage_elm.getAttribute("jStorage");
+ }catch(E5){}
+
+ try{
+ _observer_update = _storage_elm.getAttribute("jStorage_update");
+ }catch(E6){}
+
+ _storage_service.jStorage = data;
+ _backend = "userDataBehavior";
+ }else{
+ _storage_elm = null;
+ return;
+ }
+ }
+
+ // Load data from storage
+ _load_storage();
+
+ // remove dead keys
+ _handleTTL();
+
+ // create localStorage and sessionStorage polyfills if needed
+ _createPolyfillStorage("local");
+ _createPolyfillStorage("session");
+
+ // start listening for changes
+ _setupObserver();
+
+ // initialize publish-subscribe service
+ _handlePubSub();
+
+ // handle cached navigation
+ if("addEventListener" in window){
+ window.addEventListener("pageshow", function(event){
+ if(event.persisted){
+ _storageObserver();
+ }
+ }, false);
+ }
+ }
+
+ /**
+ * Create a polyfill for localStorage (type="local") or sessionStorage (type="session")
+ *
+ * @param {String} type Either "local" or "session"
+ * @param {Boolean} forceCreate If set to true, recreate the polyfill (needed with flush)
+ */
+ function _createPolyfillStorage(type, forceCreate){
+ var _skipSave = false,
+ _length = 0,
+ i,
+ storage,
+ storage_source = {};
+
+ var rand = Math.random();
+
+ if(!forceCreate && typeof window[type+"Storage"] != "undefined"){
+ return;
+ }
+
+ // Use globalStorage for localStorage if available
+ if(type == "local" && window.globalStorage){
+ localStorage = window.globalStorage[window.location.hostname];
+ return;
+ }
+
+ // only IE6/7 from this point on
+ if(_backend != "userDataBehavior"){
+ return;
+ }
+
+ // Remove existing storage element if available
+ if(forceCreate && window[type+"Storage"] && window[type+"Storage"].parentNode){
+ window[type+"Storage"].parentNode.removeChild(window[type+"Storage"]);
+ }
+
+ storage = document.createElement("button");
+ document.getElementsByTagName('head')[0].appendChild(storage);
+
+ if(type == "local"){
+ storage_source = _storage;
+ }else if(type == "session"){
+ _sessionStoragePolyfillUpdate();
+ }
+
+ for(i in storage_source){
+
+ if(storage_source.hasOwnProperty(i) && i != "__jstorage_meta" && i != "length" && typeof storage_source[i] != "undefined"){
+ if(!(i in storage)){
+ _length++;
+ }
+ storage[i] = storage_source[i];
+ }
+ }
+
+ // Polyfill API
+
+ /**
+ * Indicates how many keys are stored in the storage
+ */
+ storage.length = _length;
+
+ /**
+ * Returns the key of the nth stored value
+ *
+ * @param {Number} n Index position
+ * @return {String} Key name of the nth stored value
+ */
+ storage.key = function(n){
+ var count = 0, i;
+ _sessionStoragePolyfillUpdate();
+ for(i in storage_source){
+ if(storage_source.hasOwnProperty(i) && i != "__jstorage_meta" && i!="length" && typeof storage_source[i] != "undefined"){
+ if(count == n){
+ return i;
+ }
+ count++;
+ }
+ }
+ }
+
+ /**
+ * Returns the current value associated with the given key
+ *
+ * @param {String} key key name
+ * @return {Mixed} Stored value
+ */
+ storage.getItem = function(key){
+ _sessionStoragePolyfillUpdate();
+ if(type == "session"){
+ return storage_source[key];
+ }
+ return $.jStorage.get(key);
+ }
+
+ /**
+ * Sets or updates value for a give key
+ *
+ * @param {String} key Key name to be updated
+ * @param {String} value String value to be stored
+ */
+ storage.setItem = function(key, value){
+ if(typeof value == "undefined"){
+ return;
+ }
+ storage[key] = (value || "").toString();
+ }
+
+ /**
+ * Removes key from the storage
+ *
+ * @param {String} key Key name to be removed
+ */
+ storage.removeItem = function(key){
+ if(type == "local"){
+ return $.jStorage.deleteKey(key);
+ }
+
+ storage[key] = undefined;
+
+ _skipSave = true;
+ if(key in storage){
+ storage.removeAttribute(key);
+ }
+ _skipSave = false;
+ }
+
+ /**
+ * Clear storage
+ */
+ storage.clear = function(){
+ if(type == "session"){
+ window.name = "";
+ _createPolyfillStorage("session", true);
+ return;
+ }
+ $.jStorage.flush();
+ }
+
+ if(type == "local"){
+
+ _localStoragePolyfillSetKey = function(key, value){
+ if(key == "length"){
+ return;
+ }
+ _skipSave = true;
+ if(typeof value == "undefined"){
+ if(key in storage){
+ _length--;
+ storage.removeAttribute(key);
+ }
+ }else{
+ if(!(key in storage)){
+ _length++;
+ }
+ storage[key] = (value || "").toString();
+ }
+ storage.length = _length;
+ _skipSave = false;
+ }
+ }
+
+ function _sessionStoragePolyfillUpdate(){
+ if(type != "session"){
+ return;
+ }
+ try{
+ storage_source = JSON.parse(window.name || "{}");
+ }catch(E){
+ storage_source = {};
+ }
+ }
+
+ function _sessionStoragePolyfillSave(){
+ if(type != "session"){
+ return;
+ }
+ window.name = JSON.stringify(storage_source);
+ };
+
+ storage.attachEvent("onpropertychange", function(e){
+ if(e.propertyName == "length"){
+ return;
+ }
+
+ if(_skipSave || e.propertyName == "length"){
+ return;
+ }
+
+ if(type == "local"){
+ if(!(e.propertyName in storage_source) && typeof storage[e.propertyName] != "undefined"){
+ _length ++;
+ }
+ }else if(type == "session"){
+ _sessionStoragePolyfillUpdate();
+ if(typeof storage[e.propertyName] != "undefined" && !(e.propertyName in storage_source)){
+ storage_source[e.propertyName] = storage[e.propertyName];
+ _length++;
+ }else if(typeof storage[e.propertyName] == "undefined" && e.propertyName in storage_source){
+ delete storage_source[e.propertyName];
+ _length--;
+ }else{
+ storage_source[e.propertyName] = storage[e.propertyName];
+ }
+
+ _sessionStoragePolyfillSave();
+ storage.length = _length;
+ return;
+ }
+
+ $.jStorage.set(e.propertyName, storage[e.propertyName]);
+ storage.length = _length;
+ });
+
+ window[type+"Storage"] = storage;
+ }
+
+ /**
+ * Reload data from storage when needed
+ */
+ function _reloadData(){
+ var data = "{}";
+
+ if(_backend == "userDataBehavior"){
+ _storage_elm.load("jStorage");
+
+ try{
+ data = _storage_elm.getAttribute("jStorage");
+ }catch(E5){}
+
+ try{
+ _observer_update = _storage_elm.getAttribute("jStorage_update");
+ }catch(E6){}
+
+ _storage_service.jStorage = data;
+ }
+
+ _load_storage();
+
+ // remove dead keys
+ _handleTTL();
+
+ _handlePubSub();
+ }
+
+ /**
+ * Sets up a storage change observer
+ */
+ function _setupObserver(){
+ if(_backend == "localStorage" || _backend == "globalStorage"){
+ if("addEventListener" in window){
+ window.addEventListener("storage", _storageObserver, false);
+ }else{
+ document.attachEvent("onstorage", _storageObserver);
+ }
+ }else if(_backend == "userDataBehavior"){
+ setInterval(_storageObserver, 1000);
+ }
+ }
+
+ /**
+ * Fired on any kind of data change, needs to check if anything has
+ * really been changed
+ */
+ function _storageObserver(){
+ var updateTime;
+ // cumulate change notifications with timeout
+ clearTimeout(_observer_timeout);
+ _observer_timeout = setTimeout(function(){
+
+ if(_backend == "localStorage" || _backend == "globalStorage"){
+ updateTime = _storage_service.jStorage_update;
+ }else if(_backend == "userDataBehavior"){
+ _storage_elm.load("jStorage");
+ try{
+ updateTime = _storage_elm.getAttribute("jStorage_update");
+ }catch(E5){}
+ }
+
+ if(updateTime && updateTime != _observer_update){
+ _observer_update = updateTime;
+ _checkUpdatedKeys();
+ }
+
+ }, 25);
+ }
+
+ /**
+ * Reloads the data and checks if any keys are changed
+ */
+ function _checkUpdatedKeys(){
+ var oldCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32)),
+ newCrc32List;
+
+ _reloadData();
+ newCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32));
+
+ var key,
+ updated = [],
+ removed = [];
+
+ for(key in oldCrc32List){
+ if(oldCrc32List.hasOwnProperty(key)){
+ if(!newCrc32List[key]){
+ removed.push(key);
+ continue;
+ }
+ if(oldCrc32List[key] != newCrc32List[key]){
+ updated.push(key);
+ }
+ }
+ }
+
+ for(key in newCrc32List){
+ if(newCrc32List.hasOwnProperty(key)){
+ if(!oldCrc32List[key]){
+ updated.push(key);
+ }
+ }
+ }
+
+ _fireObservers(updated, "updated");
+ _fireObservers(removed, "deleted");
+ }
+
+ /**
+ * Fires observers for updated keys
+ *
+ * @param {Array|String} keys Array of key names or a key
+ * @param {String} action What happened with the value (updated, deleted, flushed)
+ */
+ function _fireObservers(keys, action){
+ keys = [].concat(keys || []);
+ if(action == "flushed"){
+ keys = [];
+ for(var key in _observers){
+ if(_observers.hasOwnProperty(key)){
+ keys.push(key);
+ }
+ }
+ action = "deleted";
+ }
+ for(var i=0, len = keys.length; i<len; i++){
+ if(_observers[keys[i]]){
+ for(var j=0, jlen = _observers[keys[i]].length; j<jlen; j++){
+ _observers[keys[i]][j](keys[i], action);
+ }
+ }
+ }
+ }
+
+ /**
+ * Publishes key change to listeners
+ */
+ function _publishChange(){
+ var updateTime = (+new Date()).toString();
+
+ if(_backend == "localStorage" || _backend == "globalStorage"){
+ _storage_service.jStorage_update = updateTime;
+ }else if(_backend == "userDataBehavior"){
+ _storage_elm.setAttribute("jStorage_update", updateTime);
+ _storage_elm.save("jStorage");
+ }
+
+ _storageObserver();
+ }
+
+ /**
+ * Loads the data from the storage based on the supported mechanism
+ */
+ function _load_storage(){
+ /* if jStorage string is retrieved, then decode it */
+ if(_storage_service.jStorage){
+ try{
+ _storage = JSON.parse(String(_storage_service.jStorage));
+ }catch(E6){_storage_service.jStorage = "{}";}
+ }else{
+ _storage_service.jStorage = "{}";
+ }
+ _storage_size = _storage_service.jStorage?String(_storage_service.jStorage).length:0;
+
+ if(!_storage.__jstorage_meta){
+ _storage.__jstorage_meta = {};
+ }
+ if(!_storage.__jstorage_meta.CRC32){
+ _storage.__jstorage_meta.CRC32 = {};
+ }
+ }
+
+ /**
+ * This functions provides the "save" mechanism to store the jStorage object
+ */
+ function _save(){
+ _dropOldEvents(); // remove expired events
+ try{
+ _storage_service.jStorage = JSON.stringify(_storage);
+ // If userData is used as the storage engine, additional
+ if(_storage_elm) {
+ _storage_elm.setAttribute("jStorage",_storage_service.jStorage);
+ _storage_elm.save("jStorage");
+ }
+ _storage_size = _storage_service.jStorage?String(_storage_service.jStorage).length:0;
+ }catch(E7){/* probably cache is full, nothing is saved this way*/}
+ }
+
+ /**
+ * Function checks if a key is set and is string or numberic
+ *
+ * @param {String} key Key name
+ */
+ function _checkKey(key){
+ if(!key || (typeof key != "string" && typeof key != "number")){
+ throw new TypeError('Key name must be string or numeric');
+ }
+ if(key == "__jstorage_meta"){
+ throw new TypeError('Reserved key name');
+ }
+ return true;
+ }
+
+ /**
+ * Removes expired keys
+ */
+ function _handleTTL(){
+ var curtime, i, TTL, CRC32, nextExpire = Infinity, changed = false, deleted = [];
+
+ clearTimeout(_ttl_timeout);
+
+ if(!_storage.__jstorage_meta || typeof _storage.__jstorage_meta.TTL != "object"){
+ // nothing to do here
+ return;
+ }
+
+ curtime = +new Date();
+ TTL = _storage.__jstorage_meta.TTL;
+
+ CRC32 = _storage.__jstorage_meta.CRC32;
+ for(i in TTL){
+ if(TTL.hasOwnProperty(i)){
+ if(TTL[i] <= curtime){
+ delete TTL[i];
+ delete CRC32[i];
+ delete _storage[i];
+ changed = true;
+ deleted.push(i);
+ }else if(TTL[i] < nextExpire){
+ nextExpire = TTL[i];
+ }
+ }
+ }
+
+ // set next check
+ if(nextExpire != Infinity){
+ _ttl_timeout = setTimeout(_handleTTL, nextExpire - curtime);
+ }
+
+ // save changes
+ if(changed){
+ _save();
+ _publishChange();
+ _fireObservers(deleted, "deleted");
+ }
+ }
+
+ /**
+ * Checks if there's any events on hold to be fired to listeners
+ */
+ function _handlePubSub(){
+ if(!_storage.__jstorage_meta.PubSub){
+ return;
+ }
+ var pubelm,
+ _pubsubCurrent = _pubsub_last;
+
+ for(var i=len=_storage.__jstorage_meta.PubSub.length-1; i>=0; i--){
+ pubelm = _storage.__jstorage_meta.PubSub[i];
+ if(pubelm[0] > _pubsub_last){
+ _pubsubCurrent = pubelm[0];
+ _fireSubscribers(pubelm[1], pubelm[2]);
+ }
+ }
+
+ _pubsub_last = _pubsubCurrent;
+ }
+
+ /**
+ * Fires all subscriber listeners for a pubsub channel
+ *
+ * @param {String} channel Channel name
+ * @param {Mixed} payload Payload data to deliver
+ */
+ function _fireSubscribers(channel, payload){
+ if(_pubsub_observers[channel]){
+ for(var i=0, len = _pubsub_observers[channel].length; i<len; i++){
+ // send immutable data that can't be modified by listeners
+ _pubsub_observers[channel][i](channel, JSON.parse(JSON.stringify(payload)));
+ }
+ }
+ }
+
+ /**
+ * Remove old events from the publish stream (at least 2sec old)
+ */
+ function _dropOldEvents(){
+ if(!_storage.__jstorage_meta.PubSub){
+ return;
+ }
+
+ var retire = +new Date() - 2000;
+
+ for(var i=0, len = _storage.__jstorage_meta.PubSub.length; i<len; i++){
+ if(_storage.__jstorage_meta.PubSub[i][0] <= retire){
+ // deleteCount is needed for IE6
+ _storage.__jstorage_meta.PubSub.splice(i, _storage.__jstorage_meta.PubSub.length - i);
+ break;
+ }
+ }
+
+ if(!_storage.__jstorage_meta.PubSub.length){
+ delete _storage.__jstorage_meta.PubSub;
+ }
+
+ }
+
+ /**
+ * Publish payload to a channel
+ *
+ * @param {String} channel Channel name
+ * @param {Mixed} payload Payload to send to the subscribers
+ */
+ function _publish(channel, payload){
+ if(!_storage.__jstorage_meta){
+ _storage.__jstorage_meta = {};
+ }
+ if(!_storage.__jstorage_meta.PubSub){
+ _storage.__jstorage_meta.PubSub = [];
+ }
+
+ _storage.__jstorage_meta.PubSub.unshift([+new Date, channel, payload]);
+
+ _save();
+ _publishChange();
+ }
+
+ /**
+ * CRC32 calculation based on http://noteslog.com/post/crc32-for-javascript/
+ *
+ * @param {String} str String to be hashed
+ * @param {Number} [crc] Last crc value in case of streams
+ */
+ function _crc32(str, crc){
+ crc = crc || 0;
+
+ var n = 0, //a number between 0 and 255
+ x = 0; //an hex number
+
+ crc = crc ^ (-1);
+ for(var i = 0, len = str.length; i < len; i++){
+ n = (crc ^ str.charCodeAt(i)) & 0xFF;
+ x = "0x" + _crc32Table.substr(n * 9, 8);
+ crc = (crc >>> 8)^x;
+ }
+ return crc^(-1);
+ }
+
+ ////////////////////////// PUBLIC INTERFACE /////////////////////////
+
+ $.jStorage = {
+ /* Version number */
+ version: JSTORAGE_VERSION,
+
+ /**
+ * Sets a key's value.
+ *
+ * @param {String} key Key to set. If this value is not set or not
+ * a string an exception is raised.
+ * @param {Mixed} value Value to set. This can be any value that is JSON
+ * compatible (Numbers, Strings, Objects etc.).
+ * @param {Object} [options] - possible options to use
+ * @param {Number} [options.TTL] - optional TTL value
+ * @return {Mixed} the used value
+ */
+ set: function(key, value, options){
+ _checkKey(key);
+
+ options = options || {};
+
+ // undefined values are deleted automatically
+ if(typeof value == "undefined"){
+ this.deleteKey(key);
+ return value;
+ }
+
+ if(_XMLService.isXML(value)){
+ value = {_is_xml:true,xml:_XMLService.encode(value)};
+ }else if(typeof value == "function"){
+ return undefined; // functions can't be saved!
+ }else if(value && typeof value == "object"){
+ // clone the object before saving to _storage tree
+ value = JSON.parse(JSON.stringify(value));
+ }
+
+ _storage[key] = value;
+
+ _storage.__jstorage_meta.CRC32[key] = _crc32(JSON.stringify(value));
+
+ this.setTTL(key, options.TTL || 0); // also handles saving and _publishChange
+
+ _localStoragePolyfillSetKey(key, value);
+
+ _fireObservers(key, "updated");
+ return value;
+ },
+
+ /**
+ * Looks up a key in cache
+ *
+ * @param {String} key - Key to look up.
+ * @param {mixed} def - Default value to return, if key didn't exist.
+ * @return {Mixed} the key value, default value or null
+ */
+ get: function(key, def){
+ _checkKey(key);
+ if(key in _storage){
+ if(_storage[key] && typeof _storage[key] == "object" &&
+ _storage[key]._is_xml &&
+ _storage[key]._is_xml){
+ return _XMLService.decode(_storage[key].xml);
+ }else{
+ return _storage[key];
+ }
+ }
+ return typeof(def) == 'undefined' ? null : def;
+ },
+
+ /**
+ * Deletes a key from cache.
+ *
+ * @param {String} key - Key to delete.
+ * @return {Boolean} true if key existed or false if it didn't
+ */
+ deleteKey: function(key){
+ _checkKey(key);
+ if(key in _storage){
+ delete _storage[key];
+ // remove from TTL list
+ if(typeof _storage.__jstorage_meta.TTL == "object" &&
+ key in _storage.__jstorage_meta.TTL){
+ delete _storage.__jstorage_meta.TTL[key];
+ }
+
+ delete _storage.__jstorage_meta.CRC32[key];
+ _localStoragePolyfillSetKey(key, undefined);
+
+ _save();
+ _publishChange();
+ _fireObservers(key, "deleted");
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Sets a TTL for a key, or remove it if ttl value is 0 or below
+ *
+ * @param {String} key - key to set the TTL for
+ * @param {Number} ttl - TTL timeout in milliseconds
+ * @return {Boolean} true if key existed or false if it didn't
+ */
+ setTTL: function(key, ttl){
+ var curtime = +new Date();
+ _checkKey(key);
+ ttl = Number(ttl) || 0;
+ if(key in _storage){
+
+ if(!_storage.__jstorage_meta.TTL){
+ _storage.__jstorage_meta.TTL = {};
+ }
+
+ // Set TTL value for the key
+ if(ttl>0){
+ _storage.__jstorage_meta.TTL[key] = curtime + ttl;
+ }else{
+ delete _storage.__jstorage_meta.TTL[key];
+ }
+
+ _save();
+
+ _handleTTL();
+
+ _publishChange();
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Gets remaining TTL (in milliseconds) for a key or 0 when no TTL has been set
+ *
+ * @param {String} key Key to check
+ * @return {Number} Remaining TTL in milliseconds
+ */
+ getTTL: function(key){
+ var curtime = +new Date(), ttl;
+ _checkKey(key);
+ if(key in _storage && _storage.__jstorage_meta.TTL && _storage.__jstorage_meta.TTL[key]){
+ ttl = _storage.__jstorage_meta.TTL[key] - curtime;
+ return ttl || 0;
+ }
+ return 0;
+ },
+
+ /**
+ * Deletes everything in cache.
+ *
+ * @return {Boolean} Always true
+ */
+ flush: function(){
+ _storage = {__jstorage_meta:{CRC32:{}}};
+ _createPolyfillStorage("local", true);
+ _save();
+ _publishChange();
+ _fireObservers(null, "flushed");
+ return true;
+ },
+
+ /**
+ * Returns a read-only copy of _storage
+ *
+ * @return {Object} Read-only copy of _storage
+ */
+ storageObj: function(){
+ function F() {}
+ F.prototype = _storage;
+ return new F();
+ },
+
+ /**
+ * Returns an index of all used keys as an array
+ * ['key1', 'key2',..'keyN']
+ *
+ * @return {Array} Used keys
+ */
+ index: function(){
+ var index = [], i;
+ for(i in _storage){
+ if(_storage.hasOwnProperty(i) && i != "__jstorage_meta"){
+ index.push(i);
+ }
+ }
+ return index;
+ },
+
+ /**
+ * How much space in bytes does the storage take?
+ *
+ * @return {Number} Storage size in chars (not the same as in bytes,
+ * since some chars may take several bytes)
+ */
+ storageSize: function(){
+ return _storage_size;
+ },
+
+ /**
+ * Which backend is currently in use?
+ *
+ * @return {String} Backend name
+ */
+ currentBackend: function(){
+ return _backend;
+ },
+
+ /**
+ * Test if storage is available
+ *
+ * @return {Boolean} True if storage can be used
+ */
+ storageAvailable: function(){
+ return !!_backend;
+ },
+
+ /**
+ * Register change listeners
+ *
+ * @param {String} key Key name
+ * @param {Function} callback Function to run when the key changes
+ */
+ listenKeyChange: function(key, callback){
+ _checkKey(key);
+ if(!_observers[key]){
+ _observers[key] = [];
+ }
+ _observers[key].push(callback);
+ },
+
+ /**
+ * Remove change listeners
+ *
+ * @param {String} key Key name to unregister listeners against
+ * @param {Function} [callback] If set, unregister the callback, if not - unregister all
+ */
+ stopListening: function(key, callback){
+ _checkKey(key);
+
+ if(!_observers[key]){
+ return;
+ }
+
+ if(!callback){
+ delete _observers[key];
+ return;
+ }
+
+ for(var i = _observers[key].length - 1; i>=0; i--){
+ if(_observers[key][i] == callback){
+ _observers[key].splice(i,1);
+ }
+ }
+ },
+
+ /**
+ * Subscribe to a Publish/Subscribe event stream
+ *
+ * @param {String} channel Channel name
+ * @param {Function} callback Function to run when the something is published to the channel
+ */
+ subscribe: function(channel, callback){
+ channel = (channel || "").toString();
+ if(!channel){
+ throw new TypeError('Channel not defined');
+ }
+ if(!_pubsub_observers[channel]){
+ _pubsub_observers[channel] = [];
+ }
+ _pubsub_observers[channel].push(callback);
+ },
+
+ /**
+ * Publish data to an event stream
+ *
+ * @param {String} channel Channel name
+ * @param {Mixed} payload Payload to deliver
+ */
+ publish: function(channel, payload){
+ channel = (channel || "").toString();
+ if(!channel){
+ throw new TypeError('Channel not defined');
+ }
+
+ _publish(channel, payload);
+ },
+
+ /**
+ * Reloads the data from browser storage
+ */
+ reInit: function(){
+ _reloadData();
+ }
+ };
+
+ // Initialize jStorage
+ _init();
+
+})();
diff --git a/SemanticResultFormats/resources/jquery/jquery.jcarousel.js b/SemanticResultFormats/resources/jquery/jquery.jcarousel.js
new file mode 100644
index 00000000..dff253f8
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jquery.jcarousel.js
@@ -0,0 +1,1057 @@
+/*!
+ * jCarousel - Riding carousels with jQuery
+ * http://sorgalla.com/jcarousel/
+ *
+ * Copyright (c) 2006 Jan Sorgalla (http://sorgalla.com)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * Built on top of the jQuery library
+ * http://jquery.com
+ *
+ * Inspired by the "Carousel Component" by Bill Scott
+ * http://billwscott.com/carousel/
+ */
+
+/*global window, jQuery */
+(function($) {
+ // Default configuration properties.
+ var defaults = {
+ vertical: false,
+ rtl: false,
+ start: 1,
+ offset: 1,
+ size: null,
+ scroll: 3,
+ visible: null,
+ animation: 'normal',
+ easing: 'swing',
+ auto: 0,
+ wrap: null,
+ initCallback: null,
+ setupCallback: null,
+ reloadCallback: null,
+ itemLoadCallback: null,
+ itemFirstInCallback: null,
+ itemFirstOutCallback: null,
+ itemLastInCallback: null,
+ itemLastOutCallback: null,
+ itemVisibleInCallback: null,
+ itemVisibleOutCallback: null,
+ animationStepCallback: null,
+ buttonNextHTML: '<div></div>',
+ buttonPrevHTML: '<div></div>',
+ buttonNextEvent: 'click',
+ buttonPrevEvent: 'click',
+ buttonNextCallback: null,
+ buttonPrevCallback: null,
+ itemFallbackDimension: null
+ }, windowLoaded = false;
+
+ $(window).bind('load.jcarousel', function() { windowLoaded = true; });
+
+ /**
+ * The jCarousel object.
+ *
+ * @constructor
+ * @class jcarousel
+ * @param e {HTMLElement} The element to create the carousel for.
+ * @param o {Object} A set of key/value pairs to set as configuration properties.
+ * @cat Plugins/jCarousel
+ */
+ $.jcarousel = function(e, o) {
+ this.options = $.extend({}, defaults, o || {});
+
+ this.locked = false;
+ this.autoStopped = false;
+
+ this.container = null;
+ this.clip = null;
+ this.list = null;
+ this.buttonNext = null;
+ this.buttonPrev = null;
+ this.buttonNextState = null;
+ this.buttonPrevState = null;
+
+ // Only set if not explicitly passed as option
+ if (!o || o.rtl === undefined) {
+ this.options.rtl = ($(e).attr('dir') || $('html').attr('dir') || '').toLowerCase() == 'rtl';
+ }
+
+ this.wh = !this.options.vertical ? 'width' : 'height';
+ this.lt = !this.options.vertical ? (this.options.rtl ? 'right' : 'left') : 'top';
+
+ // Extract skin class
+ var skin = '', split = e.className.split(' ');
+
+ for (var i = 0; i < split.length; i++) {
+ if (split[i].indexOf('jcarousel-skin') != -1) {
+ $(e).removeClass(split[i]);
+ skin = split[i];
+ break;
+ }
+ }
+
+ if (e.nodeName.toUpperCase() == 'UL' || e.nodeName.toUpperCase() == 'OL') {
+ this.list = $(e);
+ this.clip = this.list.parents('.jcarousel-clip');
+ this.container = this.list.parents('.jcarousel-container');
+ } else {
+ this.container = $(e);
+ this.list = this.container.find('ul,ol').eq(0);
+ this.clip = this.container.find('.jcarousel-clip');
+ }
+
+ if (this.clip.size() === 0) {
+ this.clip = this.list.wrap('<div></div>').parent();
+ }
+
+ if (this.container.size() === 0) {
+ this.container = this.clip.wrap('<div></div>').parent();
+ }
+
+ if (skin !== '' && this.container.parent()[0].className.indexOf('jcarousel-skin') == -1) {
+ this.container.wrap('<div class=" '+ skin + '"></div>');
+ }
+
+ this.buttonPrev = $('.jcarousel-prev', this.container);
+
+ if (this.buttonPrev.size() === 0 && this.options.buttonPrevHTML !== null) {
+ this.buttonPrev = $(this.options.buttonPrevHTML).appendTo(this.container);
+ }
+
+ this.buttonPrev.addClass(this.className('jcarousel-prev'));
+
+ this.buttonNext = $('.jcarousel-next', this.container);
+
+ if (this.buttonNext.size() === 0 && this.options.buttonNextHTML !== null) {
+ this.buttonNext = $(this.options.buttonNextHTML).appendTo(this.container);
+ }
+
+ this.buttonNext.addClass(this.className('jcarousel-next'));
+
+ this.clip.addClass(this.className('jcarousel-clip')).css({
+ position: 'relative'
+ });
+
+ this.list.addClass(this.className('jcarousel-list')).css({
+ overflow: 'hidden',
+ position: 'relative',
+ top: 0,
+ margin: 0,
+ padding: 0
+ }).css((this.options.rtl ? 'right' : 'left'), 0);
+
+ this.container.addClass(this.className('jcarousel-container')).css({
+ position: 'relative'
+ });
+
+ if (!this.options.vertical && this.options.rtl) {
+ this.container.addClass('jcarousel-direction-rtl').attr('dir', 'rtl');
+ }
+
+ var di = this.options.visible !== null ? Math.ceil(this.clipping() / this.options.visible) : null;
+ var li = this.list.children('li');
+
+ var self = this;
+
+ if (li.size() > 0) {
+ var wh = 0, j = this.options.offset;
+ li.each(function() {
+ self.format(this, j++);
+ wh += self.dimension(this, di);
+ });
+
+ this.list.css(this.wh, (wh + 100) + 'px');
+
+ // Only set if not explicitly passed as option
+ if (!o || o.size === undefined) {
+ this.options.size = li.size();
+ }
+ }
+
+ // For whatever reason, .show() does not work in Safari...
+ this.container.css('display', 'block');
+ this.buttonNext.css('display', 'block');
+ this.buttonPrev.css('display', 'block');
+
+ this.funcNext = function() { self.next(); };
+ this.funcPrev = function() { self.prev(); };
+ this.funcResize = function() {
+ if (self.resizeTimer) {
+ clearTimeout(self.resizeTimer);
+ }
+
+ self.resizeTimer = setTimeout(function() {
+ self.reload();
+ }, 100);
+ };
+
+ if (this.options.initCallback !== null) {
+ this.options.initCallback(this, 'init');
+ }
+
+ if (!windowLoaded && $.browser.safari) {
+ this.buttons(false, false);
+ $(window).bind('load.jcarousel', function() { self.setup(); });
+ } else {
+ this.setup();
+ }
+ };
+
+ // Create shortcut for internal use
+ var $jc = $.jcarousel;
+
+ $jc.fn = $jc.prototype = {
+ jcarousel: '0.2.8'
+ };
+
+ $jc.fn.extend = $jc.extend = $.extend;
+
+ $jc.fn.extend({
+ /**
+ * Setups the carousel.
+ *
+ * @method setup
+ * @return undefined
+ */
+ setup: function() {
+ this.first = null;
+ this.last = null;
+ this.prevFirst = null;
+ this.prevLast = null;
+ this.animating = false;
+ this.timer = null;
+ this.resizeTimer = null;
+ this.tail = null;
+ this.inTail = false;
+
+ if (this.locked) {
+ return;
+ }
+
+ this.list.css(this.lt, this.pos(this.options.offset) + 'px');
+ var p = this.pos(this.options.start, true);
+ this.prevFirst = this.prevLast = null;
+ this.animate(p, false);
+
+ $(window).unbind('resize.jcarousel', this.funcResize).bind('resize.jcarousel', this.funcResize);
+
+ if (this.options.setupCallback !== null) {
+ this.options.setupCallback(this);
+ }
+ },
+
+ /**
+ * Clears the list and resets the carousel.
+ *
+ * @method reset
+ * @return undefined
+ */
+ reset: function() {
+ this.list.empty();
+
+ this.list.css(this.lt, '0px');
+ this.list.css(this.wh, '10px');
+
+ if (this.options.initCallback !== null) {
+ this.options.initCallback(this, 'reset');
+ }
+
+ this.setup();
+ },
+
+ /**
+ * Reloads the carousel and adjusts positions.
+ *
+ * @method reload
+ * @return undefined
+ */
+ reload: function() {
+ if (this.tail !== null && this.inTail) {
+ this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + this.tail);
+ }
+
+ this.tail = null;
+ this.inTail = false;
+
+ if (this.options.reloadCallback !== null) {
+ this.options.reloadCallback(this);
+ }
+
+ if (this.options.visible !== null) {
+ var self = this;
+ var di = Math.ceil(this.clipping() / this.options.visible), wh = 0, lt = 0;
+ this.list.children('li').each(function(i) {
+ wh += self.dimension(this, di);
+ if (i + 1 < self.first) {
+ lt = wh;
+ }
+ });
+
+ this.list.css(this.wh, wh + 'px');
+ this.list.css(this.lt, -lt + 'px');
+ }
+
+ this.scroll(this.first, false);
+ },
+
+ /**
+ * Locks the carousel.
+ *
+ * @method lock
+ * @return undefined
+ */
+ lock: function() {
+ this.locked = true;
+ this.buttons();
+ },
+
+ /**
+ * Unlocks the carousel.
+ *
+ * @method unlock
+ * @return undefined
+ */
+ unlock: function() {
+ this.locked = false;
+ this.buttons();
+ },
+
+ /**
+ * Sets the size of the carousel.
+ *
+ * @method size
+ * @return undefined
+ * @param s {Number} The size of the carousel.
+ */
+ size: function(s) {
+ if (s !== undefined) {
+ this.options.size = s;
+ if (!this.locked) {
+ this.buttons();
+ }
+ }
+
+ return this.options.size;
+ },
+
+ /**
+ * Checks whether a list element exists for the given index (or index range).
+ *
+ * @method get
+ * @return bool
+ * @param i {Number} The index of the (first) element.
+ * @param i2 {Number} The index of the last element.
+ */
+ has: function(i, i2) {
+ if (i2 === undefined || !i2) {
+ i2 = i;
+ }
+
+ if (this.options.size !== null && i2 > this.options.size) {
+ i2 = this.options.size;
+ }
+
+ for (var j = i; j <= i2; j++) {
+ var e = this.get(j);
+ if (!e.length || e.hasClass('jcarousel-item-placeholder')) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ /**
+ * Returns a jQuery object with list element for the given index.
+ *
+ * @method get
+ * @return jQuery
+ * @param i {Number} The index of the element.
+ */
+ get: function(i) {
+ return $('>.jcarousel-item-' + i, this.list);
+ },
+
+ /**
+ * Adds an element for the given index to the list.
+ * If the element already exists, it updates the inner html.
+ * Returns the created element as jQuery object.
+ *
+ * @method add
+ * @return jQuery
+ * @param i {Number} The index of the element.
+ * @param s {String} The innerHTML of the element.
+ */
+ add: function(i, s) {
+ var e = this.get(i), old = 0, n = $(s);
+
+ if (e.length === 0) {
+ var c, j = $jc.intval(i);
+ e = this.create(i);
+ while (true) {
+ c = this.get(--j);
+ if (j <= 0 || c.length) {
+ if (j <= 0) {
+ this.list.prepend(e);
+ } else {
+ c.after(e);
+ }
+ break;
+ }
+ }
+ } else {
+ old = this.dimension(e);
+ }
+
+ if (n.get(0).nodeName.toUpperCase() == 'LI') {
+ e.replaceWith(n);
+ e = n;
+ } else {
+ e.empty().append(s);
+ }
+
+ this.format(e.removeClass(this.className('jcarousel-item-placeholder')), i);
+
+ var di = this.options.visible !== null ? Math.ceil(this.clipping() / this.options.visible) : null;
+ var wh = this.dimension(e, di) - old;
+
+ if (i > 0 && i < this.first) {
+ this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) - wh + 'px');
+ }
+
+ this.list.css(this.wh, $jc.intval(this.list.css(this.wh)) + wh + 'px');
+
+ return e;
+ },
+
+ /**
+ * Removes an element for the given index from the list.
+ *
+ * @method remove
+ * @return undefined
+ * @param i {Number} The index of the element.
+ */
+ remove: function(i) {
+ var e = this.get(i);
+
+ // Check if item exists and is not currently visible
+ if (!e.length || (i >= this.first && i <= this.last)) {
+ return;
+ }
+
+ var d = this.dimension(e);
+
+ if (i < this.first) {
+ this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + d + 'px');
+ }
+
+ e.remove();
+
+ this.list.css(this.wh, $jc.intval(this.list.css(this.wh)) - d + 'px');
+ },
+
+ /**
+ * Moves the carousel forwards.
+ *
+ * @method next
+ * @return undefined
+ */
+ next: function() {
+ if (this.tail !== null && !this.inTail) {
+ this.scrollTail(false);
+ } else {
+ this.scroll(((this.options.wrap == 'both' || this.options.wrap == 'last') && this.options.size !== null && this.last == this.options.size) ? 1 : this.first + this.options.scroll);
+ }
+ },
+
+ /**
+ * Moves the carousel backwards.
+ *
+ * @method prev
+ * @return undefined
+ */
+ prev: function() {
+ if (this.tail !== null && this.inTail) {
+ this.scrollTail(true);
+ } else {
+ this.scroll(((this.options.wrap == 'both' || this.options.wrap == 'first') && this.options.size !== null && this.first == 1) ? this.options.size : this.first - this.options.scroll);
+ }
+ },
+
+ /**
+ * Scrolls the tail of the carousel.
+ *
+ * @method scrollTail
+ * @return undefined
+ * @param b {Boolean} Whether scroll the tail back or forward.
+ */
+ scrollTail: function(b) {
+ if (this.locked || this.animating || !this.tail) {
+ return;
+ }
+
+ this.pauseAuto();
+
+ var pos = $jc.intval(this.list.css(this.lt));
+
+ pos = !b ? pos - this.tail : pos + this.tail;
+ this.inTail = !b;
+
+ // Save for callbacks
+ this.prevFirst = this.first;
+ this.prevLast = this.last;
+
+ this.animate(pos);
+ },
+
+ /**
+ * Scrolls the carousel to a certain position.
+ *
+ * @method scroll
+ * @return undefined
+ * @param i {Number} The index of the element to scoll to.
+ * @param a {Boolean} Flag indicating whether to perform animation.
+ */
+ scroll: function(i, a) {
+ if (this.locked || this.animating) {
+ return;
+ }
+
+ this.pauseAuto();
+ this.animate(this.pos(i), a);
+ },
+
+ /**
+ * Prepares the carousel and return the position for a certian index.
+ *
+ * @method pos
+ * @return {Number}
+ * @param i {Number} The index of the element to scoll to.
+ * @param fv {Boolean} Whether to force last item to be visible.
+ */
+ pos: function(i, fv) {
+ var pos = $jc.intval(this.list.css(this.lt));
+
+ if (this.locked || this.animating) {
+ return pos;
+ }
+
+ if (this.options.wrap != 'circular') {
+ i = i < 1 ? 1 : (this.options.size && i > this.options.size ? this.options.size : i);
+ }
+
+ var back = this.first > i;
+
+ // Create placeholders, new list width/height
+ // and new list position
+ var f = this.options.wrap != 'circular' && this.first <= 1 ? 1 : this.first;
+ var c = back ? this.get(f) : this.get(this.last);
+ var j = back ? f : f - 1;
+ var e = null, l = 0, p = false, d = 0, g;
+
+ while (back ? --j >= i : ++j < i) {
+ e = this.get(j);
+ p = !e.length;
+ if (e.length === 0) {
+ e = this.create(j).addClass(this.className('jcarousel-item-placeholder'));
+ c[back ? 'before' : 'after' ](e);
+
+ if (this.first !== null && this.options.wrap == 'circular' && this.options.size !== null && (j <= 0 || j > this.options.size)) {
+ g = this.get(this.index(j));
+ if (g.length) {
+ e = this.add(j, g.clone(true));
+ }
+ }
+ }
+
+ c = e;
+ d = this.dimension(e);
+
+ if (p) {
+ l += d;
+ }
+
+ if (this.first !== null && (this.options.wrap == 'circular' || (j >= 1 && (this.options.size === null || j <= this.options.size)))) {
+ pos = back ? pos + d : pos - d;
+ }
+ }
+
+ // Calculate visible items
+ var clipping = this.clipping(), cache = [], visible = 0, v = 0;
+ c = this.get(i - 1);
+ j = i;
+
+ while (++visible) {
+ e = this.get(j);
+ p = !e.length;
+ if (e.length === 0) {
+ e = this.create(j).addClass(this.className('jcarousel-item-placeholder'));
+ // This should only happen on a next scroll
+ if (c.length === 0) {
+ this.list.prepend(e);
+ } else {
+ c[back ? 'before' : 'after' ](e);
+ }
+
+ if (this.first !== null && this.options.wrap == 'circular' && this.options.size !== null && (j <= 0 || j > this.options.size)) {
+ g = this.get(this.index(j));
+ if (g.length) {
+ e = this.add(j, g.clone(true));
+ }
+ }
+ }
+
+ c = e;
+ d = this.dimension(e);
+ if (d === 0) {
+ throw new Error('jCarousel: No width/height set for items. This will cause an infinite loop. Aborting...');
+ }
+
+ if (this.options.wrap != 'circular' && this.options.size !== null && j > this.options.size) {
+ cache.push(e);
+ } else if (p) {
+ l += d;
+ }
+
+ v += d;
+
+ if (v >= clipping) {
+ break;
+ }
+
+ j++;
+ }
+
+ // Remove out-of-range placeholders
+ for (var x = 0; x < cache.length; x++) {
+ cache[x].remove();
+ }
+
+ // Resize list
+ if (l > 0) {
+ this.list.css(this.wh, this.dimension(this.list) + l + 'px');
+
+ if (back) {
+ pos -= l;
+ this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) - l + 'px');
+ }
+ }
+
+ // Calculate first and last item
+ var last = i + visible - 1;
+ if (this.options.wrap != 'circular' && this.options.size && last > this.options.size) {
+ last = this.options.size;
+ }
+
+ if (j > last) {
+ visible = 0;
+ j = last;
+ v = 0;
+ while (++visible) {
+ e = this.get(j--);
+ if (!e.length) {
+ break;
+ }
+ v += this.dimension(e);
+ if (v >= clipping) {
+ break;
+ }
+ }
+ }
+
+ var first = last - visible + 1;
+ if (this.options.wrap != 'circular' && first < 1) {
+ first = 1;
+ }
+
+ if (this.inTail && back) {
+ pos += this.tail;
+ this.inTail = false;
+ }
+
+ this.tail = null;
+ if (this.options.wrap != 'circular' && last == this.options.size && (last - visible + 1) >= 1) {
+ var m = $jc.intval(this.get(last).css(!this.options.vertical ? 'marginRight' : 'marginBottom'));
+ if ((v - m) > clipping) {
+ this.tail = v - clipping - m;
+ }
+ }
+
+ if (fv && i === this.options.size && this.tail) {
+ pos -= this.tail;
+ this.inTail = true;
+ }
+
+ // Adjust position
+ while (i-- > first) {
+ pos += this.dimension(this.get(i));
+ }
+
+ // Save visible item range
+ this.prevFirst = this.first;
+ this.prevLast = this.last;
+ this.first = first;
+ this.last = last;
+
+ return pos;
+ },
+
+ /**
+ * Animates the carousel to a certain position.
+ *
+ * @method animate
+ * @return undefined
+ * @param p {Number} Position to scroll to.
+ * @param a {Boolean} Flag indicating whether to perform animation.
+ */
+ animate: function(p, a) {
+ if (this.locked || this.animating) {
+ return;
+ }
+
+ this.animating = true;
+
+ var self = this;
+ var scrolled = function() {
+ self.animating = false;
+
+ if (p === 0) {
+ self.list.css(self.lt, 0);
+ }
+
+ if (!self.autoStopped && (self.options.wrap == 'circular' || self.options.wrap == 'both' || self.options.wrap == 'last' || self.options.size === null || self.last < self.options.size || (self.last == self.options.size && self.tail !== null && !self.inTail))) {
+ self.startAuto();
+ }
+
+ self.buttons();
+ self.notify('onAfterAnimation');
+
+ // This function removes items which are appended automatically for circulation.
+ // This prevents the list from growing infinitely.
+ if (self.options.wrap == 'circular' && self.options.size !== null) {
+ for (var i = self.prevFirst; i <= self.prevLast; i++) {
+ if (i !== null && !(i >= self.first && i <= self.last) && (i < 1 || i > self.options.size)) {
+ self.remove(i);
+ }
+ }
+ }
+ };
+
+ this.notify('onBeforeAnimation');
+
+ // Animate
+ if (!this.options.animation || a === false) {
+ this.list.css(this.lt, p + 'px');
+ scrolled();
+ } else {
+ var o = !this.options.vertical ? (this.options.rtl ? {'right': p} : {'left': p}) : {'top': p};
+ // Define animation settings.
+ var settings = {
+ duration: this.options.animation,
+ easing: this.options.easing,
+ complete: scrolled
+ };
+ // If we have a step callback, specify it as well.
+ if ($.isFunction(this.options.animationStepCallback)) {
+ settings.step = this.options.animationStepCallback;
+ }
+ // Start the animation.
+ this.list.animate(o, settings);
+ }
+ },
+
+ /**
+ * Starts autoscrolling.
+ *
+ * @method auto
+ * @return undefined
+ * @param s {Number} Seconds to periodically autoscroll the content.
+ */
+ startAuto: function(s) {
+ if (s !== undefined) {
+ this.options.auto = s;
+ }
+
+ if (this.options.auto === 0) {
+ return this.stopAuto();
+ }
+
+ if (this.timer !== null) {
+ return;
+ }
+
+ this.autoStopped = false;
+
+ var self = this;
+ this.timer = window.setTimeout(function() { self.next(); }, this.options.auto * 1000);
+ },
+
+ /**
+ * Stops autoscrolling.
+ *
+ * @method stopAuto
+ * @return undefined
+ */
+ stopAuto: function() {
+ this.pauseAuto();
+ this.autoStopped = true;
+ },
+
+ /**
+ * Pauses autoscrolling.
+ *
+ * @method pauseAuto
+ * @return undefined
+ */
+ pauseAuto: function() {
+ if (this.timer === null) {
+ return;
+ }
+
+ window.clearTimeout(this.timer);
+ this.timer = null;
+ },
+
+ /**
+ * Sets the states of the prev/next buttons.
+ *
+ * @method buttons
+ * @return undefined
+ */
+ buttons: function(n, p) {
+ if (n == null) {
+ n = !this.locked && this.options.size !== 0 && ((this.options.wrap && this.options.wrap != 'first') || this.options.size === null || this.last < this.options.size);
+ if (!this.locked && (!this.options.wrap || this.options.wrap == 'first') && this.options.size !== null && this.last >= this.options.size) {
+ n = this.tail !== null && !this.inTail;
+ }
+ }
+
+ if (p == null) {
+ p = !this.locked && this.options.size !== 0 && ((this.options.wrap && this.options.wrap != 'last') || this.first > 1);
+ if (!this.locked && (!this.options.wrap || this.options.wrap == 'last') && this.options.size !== null && this.first == 1) {
+ p = this.tail !== null && this.inTail;
+ }
+ }
+
+ var self = this;
+
+ if (this.buttonNext.size() > 0) {
+ this.buttonNext.unbind(this.options.buttonNextEvent + '.jcarousel', this.funcNext);
+
+ if (n) {
+ this.buttonNext.bind(this.options.buttonNextEvent + '.jcarousel', this.funcNext);
+ }
+
+ this.buttonNext[n ? 'removeClass' : 'addClass'](this.className('jcarousel-next-disabled')).attr('disabled', n ? false : true);
+
+ if (this.options.buttonNextCallback !== null && this.buttonNext.data('jcarouselstate') != n) {
+ this.buttonNext.each(function() { self.options.buttonNextCallback(self, this, n); }).data('jcarouselstate', n);
+ }
+ } else {
+ if (this.options.buttonNextCallback !== null && this.buttonNextState != n) {
+ this.options.buttonNextCallback(self, null, n);
+ }
+ }
+
+ if (this.buttonPrev.size() > 0) {
+ this.buttonPrev.unbind(this.options.buttonPrevEvent + '.jcarousel', this.funcPrev);
+
+ if (p) {
+ this.buttonPrev.bind(this.options.buttonPrevEvent + '.jcarousel', this.funcPrev);
+ }
+
+ this.buttonPrev[p ? 'removeClass' : 'addClass'](this.className('jcarousel-prev-disabled')).attr('disabled', p ? false : true);
+
+ if (this.options.buttonPrevCallback !== null && this.buttonPrev.data('jcarouselstate') != p) {
+ this.buttonPrev.each(function() { self.options.buttonPrevCallback(self, this, p); }).data('jcarouselstate', p);
+ }
+ } else {
+ if (this.options.buttonPrevCallback !== null && this.buttonPrevState != p) {
+ this.options.buttonPrevCallback(self, null, p);
+ }
+ }
+
+ this.buttonNextState = n;
+ this.buttonPrevState = p;
+ },
+
+ /**
+ * Notify callback of a specified event.
+ *
+ * @method notify
+ * @return undefined
+ * @param evt {String} The event name
+ */
+ notify: function(evt) {
+ var state = this.prevFirst === null ? 'init' : (this.prevFirst < this.first ? 'next' : 'prev');
+
+ // Load items
+ this.callback('itemLoadCallback', evt, state);
+
+ if (this.prevFirst !== this.first) {
+ this.callback('itemFirstInCallback', evt, state, this.first);
+ this.callback('itemFirstOutCallback', evt, state, this.prevFirst);
+ }
+
+ if (this.prevLast !== this.last) {
+ this.callback('itemLastInCallback', evt, state, this.last);
+ this.callback('itemLastOutCallback', evt, state, this.prevLast);
+ }
+
+ this.callback('itemVisibleInCallback', evt, state, this.first, this.last, this.prevFirst, this.prevLast);
+ this.callback('itemVisibleOutCallback', evt, state, this.prevFirst, this.prevLast, this.first, this.last);
+ },
+
+ callback: function(cb, evt, state, i1, i2, i3, i4) {
+ if (this.options[cb] == null || (typeof this.options[cb] != 'object' && evt != 'onAfterAnimation')) {
+ return;
+ }
+
+ var callback = typeof this.options[cb] == 'object' ? this.options[cb][evt] : this.options[cb];
+
+ if (!$.isFunction(callback)) {
+ return;
+ }
+
+ var self = this;
+
+ if (i1 === undefined) {
+ callback(self, state, evt);
+ } else if (i2 === undefined) {
+ this.get(i1).each(function() { callback(self, this, i1, state, evt); });
+ } else {
+ var call = function(i) {
+ self.get(i).each(function() { callback(self, this, i, state, evt); });
+ };
+ for (var i = i1; i <= i2; i++) {
+ if (i !== null && !(i >= i3 && i <= i4)) {
+ call(i);
+ }
+ }
+ }
+ },
+
+ create: function(i) {
+ return this.format('<li></li>', i);
+ },
+
+ format: function(e, i) {
+ e = $(e);
+ var split = e.get(0).className.split(' ');
+ for (var j = 0; j < split.length; j++) {
+ if (split[j].indexOf('jcarousel-') != -1) {
+ e.removeClass(split[j]);
+ }
+ }
+ e.addClass(this.className('jcarousel-item')).addClass(this.className('jcarousel-item-' + i)).css({
+ 'float': (this.options.rtl ? 'right' : 'left'),
+ 'list-style': 'none'
+ }).attr('jcarouselindex', i);
+ return e;
+ },
+
+ className: function(c) {
+ return c + ' ' + c + (!this.options.vertical ? '-horizontal' : '-vertical');
+ },
+
+ dimension: function(e, d) {
+ var el = $(e);
+
+ if (d == null) {
+ return !this.options.vertical ?
+ (el.outerWidth(true) || $jc.intval(this.options.itemFallbackDimension)) :
+ (el.outerHeight(true) || $jc.intval(this.options.itemFallbackDimension));
+ } else {
+ var w = !this.options.vertical ?
+ d - $jc.intval(el.css('marginLeft')) - $jc.intval(el.css('marginRight')) :
+ d - $jc.intval(el.css('marginTop')) - $jc.intval(el.css('marginBottom'));
+
+ $(el).css(this.wh, w + 'px');
+
+ return this.dimension(el);
+ }
+ },
+
+ clipping: function() {
+ return !this.options.vertical ?
+ this.clip[0].offsetWidth - $jc.intval(this.clip.css('borderLeftWidth')) - $jc.intval(this.clip.css('borderRightWidth')) :
+ this.clip[0].offsetHeight - $jc.intval(this.clip.css('borderTopWidth')) - $jc.intval(this.clip.css('borderBottomWidth'));
+ },
+
+ index: function(i, s) {
+ if (s == null) {
+ s = this.options.size;
+ }
+
+ return Math.round((((i-1) / s) - Math.floor((i-1) / s)) * s) + 1;
+ }
+ });
+
+ $jc.extend({
+ /**
+ * Gets/Sets the global default configuration properties.
+ *
+ * @method defaults
+ * @return {Object}
+ * @param d {Object} A set of key/value pairs to set as configuration properties.
+ */
+ defaults: function(d) {
+ return $.extend(defaults, d || {});
+ },
+
+ intval: function(v) {
+ v = parseInt(v, 10);
+ return isNaN(v) ? 0 : v;
+ },
+
+ windowLoaded: function() {
+ windowLoaded = true;
+ }
+ });
+
+ /**
+ * Creates a carousel for all matched elements.
+ *
+ * @example $("#mycarousel").jcarousel();
+ * @before <ul id="mycarousel" class="jcarousel-skin-name"><li>First item</li><li>Second item</li></ul>
+ * @result
+ *
+ * <div class="jcarousel-skin-name">
+ * <div class="jcarousel-container">
+ * <div class="jcarousel-clip">
+ * <ul class="jcarousel-list">
+ * <li class="jcarousel-item-1">First item</li>
+ * <li class="jcarousel-item-2">Second item</li>
+ * </ul>
+ * </div>
+ * <div disabled="disabled" class="jcarousel-prev jcarousel-prev-disabled"></div>
+ * <div class="jcarousel-next"></div>
+ * </div>
+ * </div>
+ *
+ * @method jcarousel
+ * @return jQuery
+ * @param o {Hash|String} A set of key/value pairs to set as configuration properties or a method name to call on a formerly created instance.
+ */
+ $.fn.jcarousel = function(o) {
+ if (typeof o == 'string') {
+ var instance = $(this).data('jcarousel'), args = Array.prototype.slice.call(arguments, 1);
+ return instance[o].apply(instance, args);
+ } else {
+ return this.each(function() {
+ var instance = $(this).data('jcarousel');
+ if (instance) {
+ if (o) {
+ $.extend(instance.options, o);
+ }
+ instance.reload();
+ } else {
+ $(this).data('jcarousel', new $jc(this, o));
+ }
+ });
+ }
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jquery.listmenu.js b/SemanticResultFormats/resources/jquery/jquery.listmenu.js
new file mode 100644
index 00000000..d9c93ec7
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jquery.listmenu.js
@@ -0,0 +1,281 @@
+/*
+*
+* jQuery listmenu plugin
+* Copyright (c) 2009 iHwy, Inc.
+* Author: Jack Killpatrick
+*
+* Version 1.1 (08/09/2009)
+* Requires jQuery 1.3.2 or jquery 1.2.6
+*
+* Visit http://www.ihwy.com/labs/jquery-listmenu-plugin.aspx for more information.
+*
+* Dual licensed under the MIT and GPL licenses:
+* http://www.opensource.org/licenses/mit-license.php
+* http://www.gnu.org/licenses/gpl.html
+*
+*/
+
+(function($) {
+ $.fn.listmenu = function(options) {
+ var opts = $.extend({}, $.fn.listmenu.defaults, options);
+ var alph = ['_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '-'];
+
+ return this.each(function() {
+ var $wrapper, list, $list, $letters, letters = {}, $letterCount, id, $menu, colOpts = $.extend({}, $.fn.listmenu.defaults.cols, opts.cols), onNav = false, onMenu = false, currentLetter = '';
+ id = this.id;
+ $list = $(this);
+
+ function init() {
+ $list.css('visibility', 'hidden'); // hiding to prevent pre-load flicker. Using visibility:hidden so that list item dimensions remain available
+
+ setTimeout(function() {
+ $list.before(createWrapperHtml());
+
+ $wrapper = $('#' + id + '-menu');
+ $wrapper.append(createLettersHtml());
+
+ $letters = $('.lm-letters', $wrapper).slice(0, 1); // will always be a single item
+ if (opts.showCounts) $letterCount = $('.lm-letter-count', $wrapper).slice(0, 1); // will always be a single item
+
+ $wrapper.append(createMenuHtml());
+ $menu = $('.lm-menu', $wrapper);
+ populateMenu();
+ if (opts.flagDisabled) addDisabledClass(); // run after populateMenu(): needs some data from there
+
+ bindHandlers();
+
+ // decide whether to include num and/or other links
+ //
+ if (!opts.includeNums) $('._', $letters).remove();
+ if (!opts.includeOther) $('.-', $letters).remove();
+ $(':last', $letters).addClass('lm-last');
+
+ $wrapper.show();
+ }, 50);
+ }
+
+ // positions the letter count div above the letter links (so we only have to do it once: after this we just change it's left position via mouseover)
+ //
+ function setLetterCountTop() {
+ $letterCount.css({ top: $('.a', $letters).slice(0, 1).offset({ margin: false, border: true }).top - $letterCount.outerHeight({ margin: true }) });
+ }
+
+ function addDisabledClass() {
+ for (var i = 0; i < alph.length; i++) {
+ if (letters[alph[i]] === undefined) $('.' + alph[i], $letters).addClass('lm-disabled');
+ }
+ }
+
+ function populateMenu() {
+ var gutter = colOpts.gutter,
+ cols = colOpts.count,
+ menuWidth,
+ colWidth;
+
+ if (opts.menuWidth) menuWidth = opts.menuWidth; // use user defined menu width if one provided, else calculate one
+ else menuWidth = $('.lm-letters', $wrapper).width() - ($menu.outerWidth() - $menu.width());
+
+ colWidth = (cols == 1) ? menuWidth : Math.floor((menuWidth - (gutter * (cols - 1))) / cols);
+ $menu.width(menuWidth); // prevents it from resizing based on content
+
+ $list.width(colWidth);
+
+ var letter, outerHeight;
+ $list.children().each(function() {
+ str = $(this).text().replace(/\s+/g, ''); // strip all white space from text (including tabs and linebreaks that might have been in the HTML) // thanks to Liam Byrne, liam@onsight.ie
+ // Deployed with SRF 1.9 to recognize the data-sortkey
+ var sortKey = String( $(this).data( 'sortkey' ) );
+ if ( sortKey !== 'undefined' ){
+ firstChar = sortKey.toLowerCase();
+ } else {
+ if (str !== '') {
+ firstChar = str.slice(0, 1).toLowerCase();
+ if (/\W/.test(firstChar)) firstChar = '-'; // not A-Z, a-z or 0-9, so considered "other"
+ if (!isNaN(firstChar)) firstChar = '_'; // use '_' if the first char is a number
+ }
+ }
+
+ outerHeight = $(this).outerHeight();
+
+ if (letters[firstChar] === undefined) letters[firstChar] = { totHeight: 0, count: 0, colHeight: 0, hasMenu: false };
+ letter = letters[firstChar];
+ letter.totHeight += outerHeight;
+ letter.count++;
+
+ $.data($(this)[0], id, { firstChar: firstChar, height: outerHeight });
+ });
+
+ $.each(letters, function() {
+ this.colHeight = (this.count > 1) ? Math.ceil(this.totHeight / cols) : this.totHeight;
+ });
+
+ var $this, data, iHeight, iLetter, cols = {}, c;
+ var tagName = $list[0].tagName.toLowerCase();
+ $list.children().each(function() {
+ $this = $(this);
+ data = $.data($this.get(0), id); iLetter = data.firstChar; iHeight = data.height;
+ if (!letters[l = iLetter].hasMenu) {
+ $menu.append('<div class="lm-submenu ' + iLetter + '" style="display:none;"></div>');
+ letters[iLetter].hasMenu = true;
+ }
+
+ if (cols[iLetter] === undefined) cols[iLetter] = { height: 0, colNum: 0, itemCount: 0, $colRoot: null };
+ c = cols[iLetter];
+ c.itemCount++;
+ if (c.height === 0) {
+ c.colNum++;
+ $('.lm-submenu.' + iLetter, $menu).append('<div class="lm-col c' + c.colNum + '"><' + tagName + ((tagName == 'ol') ? ' start="' + c.itemCount + '"' : '') + ' id="lm-' + id + '-' + iLetter + '-' + c.colNum + '" class="lm-col-root"></' + tagName + '></div>'); // reset start number for OL lists (deprecacted, but no reliable css solution). Creating an id to make lookups for appending list items faster
+ }
+ $('#lm-' + id + '-' + iLetter + '-' + c.colNum).append($(this));
+
+ c.height += iHeight;
+ if (c.height >= letters[iLetter].colHeight) c.height = 0; // forces another column to get started if this letter comes up again
+ });
+
+ $.each(letters, function(idx) {
+ if (this.hasMenu) {
+ $('.lm-submenu.' + idx + ' .lm-col', $menu).css({ 'width': colWidth, 'float': 'left' });
+ $('.lm-submenu.' + idx + ' .lm-col:not(:last)', $menu).css({ 'marginRight': gutter });
+ }
+ });
+
+ $menu.append('<div class="lm-no-match" style="display:none">' + opts.noMatchText + '</div>');
+ $list.remove();
+ }
+
+ function getLetterCount(el) {
+ var letter = letters[$(el).attr('class').split(' ')[0]];
+ return (letter !== undefined) ? letter.count : 0; // some letters may not be in the hash
+ }
+
+ function hideCurrentSubmenu() {
+ if (currentLetter !== '') $('.lm-submenu.' + currentLetter, $menu).hide();
+ $('.lm-no-match', $menu).hide(); // hiding each time, rather than checking to see if we need to hide it
+ }
+
+ function bindHandlers() {
+
+ // sets the top position of the count div in case something above it on the page has resized
+ //
+ if (opts.showCounts) {
+ $wrapper.mouseover(function() {
+ setLetterCountTop();
+ });
+ }
+
+ // kill letter clicks
+ //
+ $('a', $letters).click(function() {
+ $(this).blur();
+ return false;
+ });
+
+ $letters.hover(
+ function() { onNav = true; },
+ function() {
+ onNav = false;
+
+ setTimeout(function() {
+ if (!onMenu) {
+ $('a.lm-selected', $letters).removeClass('lm-selected');
+ $('.lm-menu', $wrapper).hide();
+ hideCurrentSubmenu();
+ currentLetter = '';
+ }
+ }, 10);
+ }
+ );
+
+ $('a', $letters).mouseover(function() {
+ var count = getLetterCount(this);
+ var $this = $(this);
+
+ if (opts.showCounts) {
+ var left = $this.position().left;
+ var width = $this.outerWidth({ margin: true });
+ if (opts.showCounts) $letterCount.css({ left: left, width: width + 'px' }).text(count).show(); // set left position and width of letter count, set count text and show it
+ }
+
+ var newLetter = $this.attr('class').split(' ')[0];
+ if (newLetter != currentLetter) {
+ if (currentLetter !== '') {
+ hideCurrentSubmenu();
+ $('a.lm-selected', $letters).removeClass('lm-selected');
+ }
+ $this.addClass('lm-selected');
+
+ if (count > 0) $('.lm-submenu.' + newLetter, $wrapper).show();
+ else $('.lm-no-match', $wrapper).show();
+
+ if (currentLetter === '') $('.lm-menu', $wrapper).show();
+ currentLetter = newLetter;
+ }
+ });
+
+ $('a', $letters).mouseout(function() {
+ if (opts.showCounts) $letterCount.hide();
+ });
+
+ $menu.hover(
+ function() {
+ onMenu = true;
+ },
+ function() {
+ onMenu = false;
+ setTimeout(function() {
+ if (!onNav) {
+ $('a.lm-selected', $letters).removeClass('lm-selected');
+ $('.lm-menu', $wrapper).hide();
+ hideCurrentSubmenu();
+ currentLetter = '';
+ }
+ }, 10);
+ }
+ );
+
+ if (opts.onClick !== null) {
+ $menu.click(function(e) {
+ var $target = $(e.target);
+ opts.onClick($target);
+ return false;
+ });
+ }
+ }
+
+ // creates the HTML for the letter links
+ //
+ function createLettersHtml() {
+ var html = [];
+ for (var i = 1; i < alph.length; i++) {
+ if (html.length === 0) html.push('<a class="_" href="#">0-9</a>');
+ html.push('<a class="' + alph[i] + '" href="#">' + ((alph[i] == '-') ? '...' : alph[i].toUpperCase()) + '</a>');
+ }
+ return '<div class="lm-letters">' + html.join('') + '</div>' + ((opts.showCounts) ? '<div class="lm-letter-count" style="display:none; position:absolute; top:0; left:0; width:20px;">0</div>' : ''); // the styling for letterCount is to give us a starting point for the element, which will be repositioned when made visible (ie, should not need to be styled by the user)
+ }
+
+ function createMenuHtml() {
+ return '<div class="lm-menu"></div>';
+ }
+
+ function createWrapperHtml() {
+ return '<div id="' + id + '-menu" class="lm-wrapper"></div>';
+ }
+
+ init();
+ });
+ };
+
+ $.fn.listmenu.defaults = {
+ includeNums: true,
+ includeOther: false,
+ flagDisabled: true,
+ noMatchText: 'No matching entries',
+ showCounts: true,
+ menuWidth: null,
+ cols: {
+ count: 4,
+ gutter: 40
+ },
+ onClick: null
+ };
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jquery.listnav.js b/SemanticResultFormats/resources/jquery/jquery.listnav.js
new file mode 100644
index 00000000..2e3f62a4
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jquery.listnav.js
@@ -0,0 +1,232 @@
+/*
+*
+* jQuery listnav plugin
+* Copyright (c) 2009 iHwy, Inc.
+* Author: Jack Killpatrick
+*
+* Version 2.1 (08/09/2009)
+* Requires jQuery 1.3.2, jquery 1.2.6 or jquery 1.2.x plus the jquery dimensions plugin
+*
+* Visit http://www.ihwy.com/labs/jquery-listnav-plugin.aspx for more information.
+*
+* Dual licensed under the MIT and GPL licenses:
+* http://www.opensource.org/licenses/mit-license.php
+* http://www.gnu.org/licenses/gpl.html
+*
+*/
+
+(function($) {
+ $.fn.listnav = function(options) {
+ var opts = $.extend({}, $.fn.listnav.defaults, options);
+ var letters = ['_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '-'];
+ var firstClick = false;
+ opts.prefixes = $.map(opts.prefixes, function(n) { return n.toLowerCase(); });
+
+ return this.each(function() {
+ var $wrapper, list, $list, $letters, $letterCount, id;
+ id = this.id;
+ $wrapper = $('#' + id + '-nav'); // user must abide by the convention: <ul id="myList"> for list and <div id="myList-nav"> for nav wrapper
+ $list = $(this);
+
+ var counts = {}, allCount = 0, isAll = true, numCount = 0, prevLetter = '';
+
+ function init() {
+ $wrapper.append(createLettersHtml());
+
+ $letters = $('.ln-letters', $wrapper).slice(0, 1); // will always be a single item
+ if (opts.showCounts) $letterCount = $('.ln-letter-count', $wrapper).slice(0, 1); // will always be a single item
+
+ addClasses();
+ addNoMatchLI();
+ if (opts.flagDisabled) addDisabledClass();
+ bindHandlers();
+
+ if (!opts.includeAll) $list.show(); // show the list in case the recommendation for includeAll=false was taken
+
+ // remove nav items we don't need
+ //
+ if (!opts.includeAll) $('.all', $letters).remove();
+ if (!opts.includeNums) $('._', $letters).remove();
+ if (!opts.includeOther) $('.-', $letters).remove();
+
+ $(':last', $letters).addClass('ln-last'); // allows for styling a case where last item needs right border set (because items before that only have top, left and bottom so that border between items isn't doubled)
+
+ if ($.cookie && (opts.cookieName !== null)) {
+ var cookieLetter = $.cookie(opts.cookieName);
+ if (cookieLetter !== null) opts.initLetter = cookieLetter;
+ }
+
+ // decide what to show first
+ //
+ if (opts.initLetter !== '') {
+ firstClick = true;
+ $('.' + opts.initLetter.toLowerCase(), $letters).slice(0, 1).click(); // click the initLetter if there was one
+ }
+ else {
+ if (opts.includeAll) $('.all', $letters).addClass('ln-selected'); // showing all: we don't need to click this: the whole list is already loaded
+ else { // ALL link is hidden, click the first letter that will display LI's
+ for (var i = ((opts.includeNums) ? 0 : 1); i < letters.length; i++) {
+ if (counts[letters[i]] > 0) {
+ firstClick = true;
+ $('.' + letters[i], $letters).slice(0, 1).click();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // positions the letter count div above the letter links (so we only have to do it once: after this we just change it's left position via mouseover)
+ //
+ function setLetterCountTop() {
+ $letterCount.css({ top: $('.a', $letters).slice(0, 1).offset({ margin: false, border: true }).top - $letterCount.outerHeight({ margin: true }) }); // note: don't set top based on '.all': it might not be visible
+ }
+
+ // adds a class to each LI that has text content inside of it (ie, inside an <a>, a <div>, nested DOM nodes, etc)
+ //
+ function addClasses() {
+ var str, firstChar, firstWord, spl, $this, hasPrefixes = (opts.prefixes.length > 0);
+ $($list).children().each(function() {
+ $this = $(this), firstChar = '', str = $.trim($this.text()).toLowerCase();
+ if (str !== '') {
+ if (hasPrefixes) {
+ spl = str.split(' ');
+ if ((spl.length > 1) && ($.inArray(spl[0], opts.prefixes) > -1)) {
+ firstChar = spl[1].charAt(0);
+ addLetterClass(firstChar, $this, true);
+ }
+ }
+ firstChar = str.charAt(0);
+ addLetterClass(firstChar, $this);
+ }
+ });
+ }
+
+ function addLetterClass(firstChar, $el, isPrefix) {
+ // Deployed with SRF 1.9 to recognize the data-sortkey
+ var sortKey = String( $el.data( 'sortkey' ) );
+ if ( sortKey !== 'undefined' ){
+ firstChar = sortKey.toLowerCase();
+ } else {
+ if (/\W/.test(firstChar)) firstChar = '-'; // not A-Z, a-z or 0-9, so considered "other"
+ if (!isNaN(firstChar)) firstChar = '_'; // use '_' if the first char is a number
+ }
+
+ $el.addClass('ln-' + firstChar);
+
+ if (counts[firstChar] === undefined) counts[firstChar] = 0;
+ counts[firstChar]++;
+ if (!isPrefix) allCount++;
+ }
+
+ function addDisabledClass() {
+ for (var i = 0; i < letters.length; i++) {
+ if (counts[letters[i]] === undefined) $('.' + letters[i], $letters).addClass('ln-disabled');
+ }
+ }
+
+ function addNoMatchLI() {
+ $list.append('<li class="ln-no-match" style="display:none">' + opts.noMatchText + '</li>');
+ }
+
+ function getLetterCount(el) {
+ if ($(el).hasClass('all')) return allCount;
+ else {
+ var count = counts[$(el).attr('class').split(' ')[0]];
+ return (count !== undefined) ? count : 0; // some letters may not have a count in the hash
+ }
+ }
+
+ function bindHandlers() {
+
+ // sets the top position of the count div in case something above it on the page has resized
+ //
+ if (opts.showCounts) {
+ $wrapper.mouseover(function() {
+ setLetterCountTop();
+ });
+ }
+
+ // mouseover for each letter: shows the count above the letter
+ //
+ if (opts.showCounts) {
+ $('a', $letters).mouseover(function() {
+ var left = $(this).position().left;
+ var width = ($(this).outerWidth({ margin: true }) - 1) + 'px'; // the -1 is to tweak the width a bit due to a seeming inaccuracy in jquery ui/dimensions outerWidth (same result in FF2 and IE6/7)
+ var count = getLetterCount(this);
+ $letterCount.css({ left: left, width: width }).text(count).show(); // set left position and width of letter count, set count text and show it
+ });
+
+ // mouseout for each letter: hide the count
+ //
+ $('a', $letters).mouseout(function() {
+ $letterCount.hide();
+ });
+ }
+
+ // click handler for letters: shows/hides relevant LI's
+ //
+ $('a', $letters).click(function() {
+ $('a.ln-selected', $letters).removeClass('ln-selected');
+
+ var letter = $(this).attr('class').split(' ')[0];
+
+ if (letter == 'all') {
+ $list.children().show();
+ $list.children('.ln-no-match').hide();
+ isAll = true;
+ } else {
+ if (isAll) {
+ $list.children().hide();
+ isAll = false;
+ } else if (prevLetter !== '') $list.children('.ln-' + prevLetter).hide();
+
+ var count = getLetterCount(this);
+ if (count > 0) {
+ $list.children('.ln-no-match').hide(); // in case it's showing
+ $list.children('.ln-' + letter).show();
+ }
+ else $list.children('.ln-no-match').show();
+
+ prevLetter = letter;
+ }
+
+ if ($.cookie && (opts.cookieName !== null)) $.cookie(opts.cookieName, letter);
+
+
+ $(this).addClass('ln-selected');
+ $(this).blur();
+ if (!firstClick && (opts.onClick !== null)) opts.onClick(letter);
+ else firstClick = false;
+ return false;
+ });
+ }
+
+ // creates the HTML for the letter links
+ //
+ function createLettersHtml() {
+ var html = [];
+ for (var i = 1; i < letters.length; i++) {
+ if (html.length === 0) html.push('<a class="all" href="#">ALL</a><a class="_" href="#">0-9</a>');
+ html.push('<a class="' + letters[i] + '" href="#">' + ((letters[i] == '-') ? '...' : letters[i].toUpperCase()) + '</a>');
+ }
+ return '<div class="ln-letters">' + html.join('') + '</div>' + ((opts.showCounts) ? '<div class="ln-letter-count" style="display:none; position:absolute; top:0; left:0; width:20px;">0</div>' : ''); // the styling for ln-letter-count is to give us a starting point for the element, which will be repositioned when made visible (ie, should not need to be styled by the user)
+ }
+
+ init();
+ });
+ };
+
+ $.fn.listnav.defaults = {
+ initLetter: '',
+ includeAll: true,
+ incudeOther: false,
+ includeNums: true,
+ flagDisabled: true,
+ noMatchText: 'No matching entries',
+ showCounts: true,
+ cookieName: null,
+ onClick: null,
+ prefixes: []
+ };
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jquery.pajinate.js b/SemanticResultFormats/resources/jquery/jquery.pajinate.js
new file mode 100644
index 00000000..a6fa442b
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jquery.pajinate.js
@@ -0,0 +1,313 @@
+;(function($){
+/*******************************************************************************************/
+// jquery.pajinate.js - version 0.4
+// A jQuery plugin for paginating through any number of DOM elements
+//
+// Copyright (c) 2010, Wes Nolte (http://wesnolte.com)
+// Licensed under the MIT License (MIT-LICENSE.txt)
+// http://www.opensource.org/licenses/mit-license.php
+// Created: 2010-04-16 | Updated: 2010-04-26
+//
+/*******************************************************************************************/
+
+ $.fn.pajinate = function(options){
+ // Set some state information
+ var current_page = 'current_page';
+ var items_per_page = 'items_per_page';
+
+ var meta;
+
+ // Setup default option values
+ var defaults = {
+ item_container_id : '.content',
+ items_per_page : 10,
+ nav_panel_id : '.page_navigation',
+ nav_info_id : '.info_text',
+ num_page_links_to_display : 20,
+ start_page : 0,
+ wrap_around : false,
+ nav_label_first : 'First',
+ nav_label_prev : 'Prev',
+ nav_label_next : 'Next',
+ nav_label_last : 'Last',
+ nav_order : ["first", "prev", "num", "next", "last"],
+ nav_label_info : 'Showing {0}-{1} of {2} results',
+ show_first_last: true,
+ abort_on_small_lists: false,
+ jquery_ui: false,
+ jquery_ui_active: "ui-state-highlight",
+ jquery_ui_default: "ui-state-default",
+ jquery_ui_disabled: "ui-state-disabled"
+ };
+ var options = $.extend(defaults,options);
+ var $item_container;
+ var $page_container;
+ var $items;
+ var $nav_panels;
+ var total_page_no_links;
+ var jquery_ui_default_class = options.jquery_ui ? options.jquery_ui_default : '';
+ var jquery_ui_active_class = options.jquery_ui ? options.jquery_ui_active : '';
+ var jquery_ui_disabled_class = options.jquery_ui ? options.jquery_ui_disabled : '';
+
+ return this.each(function(){
+ $page_container = $(this);
+ $item_container = $(this).find(options.item_container_id);
+ $items = $page_container.find(options.item_container_id).children();
+
+ if (options.abort_on_small_lists && options.items_per_page >= $items.size())
+ return $page_container;
+
+ meta = $page_container;
+
+ // Initialize meta data
+ meta.data(current_page,0);
+ meta.data(items_per_page, options.items_per_page);
+
+ // Get the total number of items
+ var total_items = $item_container.children().size();
+
+ // Calculate the number of pages needed
+ var number_of_pages = Math.ceil(total_items/options.items_per_page);
+
+ // Construct the nav bar
+ var more = '<span class="ellipse more">...</span>';
+ var less = '<span class="ellipse less">...</span>';
+ var first = !options.show_first_last ? '' : '<a class="first_link '+ jquery_ui_default_class +'" href="">'+ options.nav_label_first +'</a>';
+ var last = !options.show_first_last ? '' : '<a class="last_link '+ jquery_ui_default_class +'" href="">'+ options.nav_label_last +'</a>';
+
+ var navigation_html = "";
+
+ for(var i = 0; i < options.nav_order.length; i++) {
+ switch (options.nav_order[i]) {
+ case "first":
+ navigation_html += first;
+ break;
+ case "last":
+ navigation_html += last;
+ break;
+ case "next":
+ navigation_html += '<a class="next_link '+ jquery_ui_default_class +'" href="">'+ options.nav_label_next +'</a>';
+ break;
+ case "prev":
+ navigation_html += '<a class="previous_link '+ jquery_ui_default_class +'" href="">'+ options.nav_label_prev +'</a>';
+ break;
+ case "num":
+ navigation_html += less;
+ var current_link = 0;
+ while(number_of_pages > current_link){
+ navigation_html += '<a class="page_link '+ jquery_ui_default_class +'" href="" longdesc="' + current_link +'">'+ (current_link + 1) +'</a>';
+ current_link++;
+ }
+ navigation_html += more;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ // And add it to the appropriate area of the DOM
+ $nav_panels = $page_container.find(options.nav_panel_id);
+ $nav_panels.html(navigation_html).each(function(){
+
+ $(this).find('.page_link:first').addClass('first');
+ $(this).find('.page_link:last').addClass('last');
+
+ });
+
+ // Hide the more/less indicators
+ $nav_panels.children('.ellipse').hide();
+
+ // Set the active page link styling
+ $nav_panels.find('.previous_link').next().next().addClass('active_page '+ jquery_ui_active_class);
+
+ /* Setup Page Display */
+ // And hide all pages
+ $items.hide();
+ // Show the first page
+ $items.slice(0, meta.data(items_per_page)).show();
+
+ /* Setup Nav Menu Display */
+ // Page number slices
+
+ total_page_no_links = $page_container.children(options.nav_panel_id+':first').children('.page_link').size();
+ options.num_page_links_to_display = Math.min(options.num_page_links_to_display,total_page_no_links);
+
+ $nav_panels.children('.page_link').hide(); // Hide all the page links
+
+ // And only show the number we should be seeing
+ $nav_panels.each(function(){
+ $(this).children('.page_link').slice(0, options.num_page_links_to_display).show();
+ });
+
+ /* Bind the actions to their respective links */
+
+ // Event handler for 'First' link
+ $page_container.find('.first_link').click(function(e){
+ e.preventDefault();
+
+ movePageNumbersRight($(this),0);
+ gotopage(0);
+ });
+
+ // Event handler for 'Last' link
+ $page_container.find('.last_link').click(function(e){
+ e.preventDefault();
+ var lastPage = total_page_no_links - 1;
+ movePageNumbersLeft($(this),lastPage);
+ gotopage(lastPage);
+ });
+
+ // Event handler for 'Prev' link
+ $page_container.find('.previous_link').click(function(e){
+ e.preventDefault();
+ showPrevPage($(this));
+ });
+
+
+ // Event handler for 'Next' link
+ $page_container.find('.next_link').click(function(e){
+ e.preventDefault();
+ showNextPage($(this));
+ });
+
+ // Event handler for each 'Page' link
+ $page_container.find('.page_link').click(function(e){
+ e.preventDefault();
+ gotopage($(this).attr('longdesc'));
+ });
+
+ // Goto the required page
+ gotopage(parseInt(options.start_page));
+ toggleMoreLess();
+ if(!options.wrap_around)
+ tagNextPrev();
+ });
+
+ function showPrevPage(e){
+ new_page = parseInt(meta.data(current_page)) - 1;
+
+ // Check that we aren't on a boundary link
+ if($(e).siblings('.active_page').prev('.page_link').length==true){
+ movePageNumbersRight(e,new_page);
+ gotopage(new_page);
+ }else if(options.wrap_around){
+ gotopage(total_page_no_links-1);
+ }
+
+ }
+
+ function showNextPage(e){
+ new_page = parseInt(meta.data(current_page)) + 1;
+
+ // Check that we aren't on a boundary link
+ if($(e).siblings('.active_page').next('.page_link').length==true){
+ movePageNumbersLeft(e,new_page);
+ gotopage(new_page);
+ } else if (options.wrap_around) {
+ gotopage(0);
+ }
+
+ }
+
+ function gotopage(page_num){
+
+ var ipp = parseInt(meta.data(items_per_page));
+
+ var isLastPage = false;
+
+ // Find the start of the next slice
+ start_from = page_num * ipp;
+
+ // Find the end of the next slice
+ end_on = start_from + ipp;
+ // Hide the current page
+ var items = $items.hide().slice(start_from, end_on);
+
+ items.show();
+
+ // Reassign the active class
+ $page_container.find(options.nav_panel_id).children('.page_link[longdesc=' + page_num +']').addClass('active_page '+ jquery_ui_active_class)
+ .siblings('.active_page')
+ .removeClass('active_page ' + jquery_ui_active_class);
+
+ // Set the current page meta data
+ meta.data(current_page,page_num);
+
+ $page_container.find(options.nav_info_id).html(options.nav_label_info.replace("{0}",start_from+1).
+ replace("{1}",start_from + items.length).replace("{2}",$items.length));
+
+ // Hide the more and/or less indicators
+ toggleMoreLess();
+
+ // Add a class to the next or prev links if there are no more pages next or previous to the active page
+ tagNextPrev();
+ }
+ // Methods to shift the diplayed index of page numbers to the left or right
+ function movePageNumbersLeft(e, new_p){
+ var new_page = new_p;
+
+ var $current_active_link = $(e).siblings('.active_page');
+
+ if($current_active_link.siblings('.page_link[longdesc=' + new_page +']').css('display') == 'none'){
+
+ $nav_panels.each(function(){
+ $(this).children('.page_link')
+ .hide() // Hide all the page links
+ .slice(parseInt(new_page - options.num_page_links_to_display + 1) , new_page + 1)
+ .show();
+ });
+ }
+
+ }
+
+ function movePageNumbersRight(e, new_p){
+ var new_page = new_p;
+
+ var $current_active_link = $(e).siblings('.active_page');
+
+ if($current_active_link.siblings('.page_link[longdesc=' + new_page +']').css('display') == 'none'){
+
+ $nav_panels.each(function(){
+ $(this).children('.page_link')
+ .hide() // Hide all the page links
+ .slice( new_page , new_page + parseInt(options.num_page_links_to_display))
+ .show();
+ });
+ }
+ }
+
+ // Show or remove the ellipses that indicate that more page numbers exist in the page index than are currently shown
+ function toggleMoreLess(){
+
+ if(!$nav_panels.children('.page_link:visible').hasClass('last')){
+ $nav_panels.children('.more').show();
+ }else {
+ $nav_panels.children('.more').hide();
+ }
+
+ if(!$nav_panels.children('.page_link:visible').hasClass('first')){
+ $nav_panels.children('.less').show();
+ }else {
+ $nav_panels.children('.less').hide();
+ }
+ }
+
+ /* Add the style class ".no_more" to the first/prev and last/next links to allow custom styling */
+ function tagNextPrev() {
+ if($nav_panels.children('.last').hasClass('active_page')){
+ $nav_panels.children('.next_link').add('.last_link').addClass('no_more ' + jquery_ui_disabled_class);
+ } else {
+ $nav_panels.children('.next_link').add('.last_link').removeClass('no_more ' + jquery_ui_disabled_class);
+ }
+
+ if($nav_panels.children('.first').hasClass('active_page')){
+ $nav_panels.children('.previous_link').add('.first_link').addClass('no_more ' + jquery_ui_disabled_class);
+ } else {
+ $nav_panels.children('.previous_link').add('.first_link').removeClass('no_more ' + jquery_ui_disabled_class);
+ }
+ }
+
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jquery.responsiveslides.js b/SemanticResultFormats/resources/jquery/jquery.responsiveslides.js
new file mode 100644
index 00000000..2924396d
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jquery.responsiveslides.js
@@ -0,0 +1,391 @@
+/*! ResponsiveSlides.js v1.53
+ * http://responsiveslides.com
+ * http://viljamis.com
+ *
+ * Copyright (c) 2011-2012 @viljamis
+ * Available under the MIT license
+ */
+
+/*jslint browser: true, sloppy: true, vars: true, plusplus: true, indent: 2 */
+
+(function ($, window, i) {
+ $.fn.responsiveSlides = function (options) {
+
+ // Default settings
+ var settings = $.extend({
+ "auto": true, // Boolean: Animate automatically, true or false
+ "speed": 500, // Integer: Speed of the transition, in milliseconds
+ "timeout": 4000, // Integer: Time between slide transitions, in milliseconds
+ "pager": false, // Boolean: Show pager, true or false
+ "nav": false, // Boolean: Show navigation, true or false
+ "random": false, // Boolean: Randomize the order of the slides, true or false
+ "pause": false, // Boolean: Pause on hover, true or false
+ "pauseControls": true, // Boolean: Pause when hovering controls, true or false
+ "prevText": "Previous", // String: Text for the "previous" button
+ "nextText": "Next", // String: Text for the "next" button
+ "maxwidth": "", // Integer: Max-width of the slideshow, in pixels
+ "navContainer": "", // Selector: Where auto generated controls should be appended to, default is after the <ul>
+ "manualControls": "", // Selector: Declare custom pager navigation
+ "namespace": "rslides", // String: change the default namespace used
+ before: function () {}, // Function: Before callback
+ after: function () {} // Function: After callback
+ }, options);
+
+ return this.each(function () {
+
+ // Index for namespacing
+ i++;
+
+ var $this = $(this),
+
+ // Local variables
+ vendor,
+ selectTab,
+ startCycle,
+ restartCycle,
+ rotate,
+ $tabs,
+
+ // Helpers
+ index = 0,
+ $slide = $this.children(),
+ length = $slide.size(),
+ fadeTime = parseFloat(settings.speed),
+ waitTime = parseFloat(settings.timeout),
+ maxw = parseFloat(settings.maxwidth),
+
+ // Namespacing
+ namespace = settings.namespace,
+ namespaceIdx = namespace + i,
+
+ // Classes
+ navClass = namespace + "_nav " + namespaceIdx + "_nav",
+ activeClass = namespace + "_here",
+ visibleClass = namespaceIdx + "_on",
+ slideClassPrefix = namespaceIdx + "_s",
+
+ // Pager
+ $pager = $("<ul class='" + namespace + "_tabs " + namespaceIdx + "_tabs' />"),
+
+ // Styles for visible and hidden slides
+ visible = {"float": "left", "position": "relative", "opacity": 1, "zIndex": 2},
+ hidden = {"float": "none", "position": "absolute", "opacity": 0, "zIndex": 1},
+
+ // Detect transition support
+ supportsTransitions = (function () {
+ var docBody = document.body || document.documentElement;
+ var styles = docBody.style;
+ var prop = "transition";
+ if (typeof styles[prop] === "string") {
+ return true;
+ }
+ // Tests for vendor specific prop
+ vendor = ["Moz", "Webkit", "Khtml", "O", "ms"];
+ prop = prop.charAt(0).toUpperCase() + prop.substr(1);
+ var i;
+ for (i = 0; i < vendor.length; i++) {
+ if (typeof styles[vendor[i] + prop] === "string") {
+ return true;
+ }
+ }
+ return false;
+ })(),
+
+ // Fading animation
+ slideTo = function (idx) {
+ settings.before();
+ // If CSS3 transitions are supported
+ if (supportsTransitions) {
+ $slide
+ .removeClass(visibleClass)
+ .css(hidden)
+ .eq(idx)
+ .addClass(visibleClass)
+ .css(visible);
+ index = idx;
+ setTimeout(function () {
+ settings.after();
+ }, fadeTime);
+ // If not, use jQuery fallback
+ } else {
+ $slide
+ .stop()
+ .fadeOut(fadeTime, function () {
+ $(this)
+ .removeClass(visibleClass)
+ .css(hidden)
+ .css("opacity", 1);
+ })
+ .eq(idx)
+ .fadeIn(fadeTime, function () {
+ $(this)
+ .addClass(visibleClass)
+ .css(visible);
+ settings.after();
+ index = idx;
+ });
+ }
+ };
+
+ // Random order
+ if (settings.random) {
+ $slide.sort(function () {
+ return (Math.round(Math.random()) - 0.5);
+ });
+ $this
+ .empty()
+ .append($slide);
+ }
+
+ // Add ID's to each slide
+ $slide.each(function (i) {
+ this.id = slideClassPrefix + i;
+ });
+
+ // Add max-width and classes
+ $this.addClass(namespace + " " + namespaceIdx);
+ if (options && options.maxwidth) {
+ $this.css("max-width", maxw);
+ }
+
+ // Hide all slides, then show first one
+ $slide
+ .hide()
+ .css(hidden)
+ .eq(0)
+ .addClass(visibleClass)
+ .css(visible)
+ .show();
+
+ // CSS transitions
+ if (supportsTransitions) {
+ $slide
+ .show()
+ .css({
+ // -ms prefix isn't needed as IE10 uses prefix free version
+ "-webkit-transition": "opacity " + fadeTime + "ms ease-in-out",
+ "-moz-transition": "opacity " + fadeTime + "ms ease-in-out",
+ "-o-transition": "opacity " + fadeTime + "ms ease-in-out",
+ "transition": "opacity " + fadeTime + "ms ease-in-out"
+ });
+ }
+
+ // Only run if there's more than one slide
+ if ($slide.size() > 1) {
+
+ // Make sure the timeout is at least 100ms longer than the fade
+ if (waitTime < fadeTime + 100) {
+ return;
+ }
+
+ // Pager
+ if (settings.pager && !settings.manualControls) {
+ var tabMarkup = [];
+ $slide.each(function (i) {
+ var n = i + 1;
+ tabMarkup +=
+ "<li>" +
+ "<a href='#' class='" + slideClassPrefix + n + "'>" + n + "</a>" +
+ "</li>";
+ });
+ $pager.append(tabMarkup);
+
+ // Inject pager
+ if (options.navContainer) {
+ $(settings.navContainer).append($pager);
+ } else {
+ $this.after($pager);
+ }
+ }
+
+ // Manual pager controls
+ if (settings.manualControls) {
+ $pager = $(settings.manualControls);
+ $pager.addClass(namespace + "_tabs " + namespaceIdx + "_tabs");
+ }
+
+ // Add pager slide class prefixes
+ if (settings.pager || settings.manualControls) {
+ $pager.find('li').each(function (i) {
+ $(this).addClass(slideClassPrefix + (i + 1));
+ });
+ }
+
+ // If we have a pager, we need to set up the selectTab function
+ if (settings.pager || settings.manualControls) {
+ $tabs = $pager.find('a');
+
+ // Select pager item
+ selectTab = function (idx) {
+ $tabs
+ .closest("li")
+ .removeClass(activeClass)
+ .eq(idx)
+ .addClass(activeClass);
+ };
+ }
+
+ // Auto cycle
+ if (settings.auto) {
+
+ startCycle = function () {
+ rotate = setInterval(function () {
+
+ // Clear the event queue
+ $slide.stop(true, true);
+
+ var idx = index + 1 < length ? index + 1 : 0;
+
+ // Remove active state and set new if pager is set
+ if (settings.pager || settings.manualControls) {
+ selectTab(idx);
+ }
+
+ slideTo(idx);
+ }, waitTime);
+ };
+
+ // Init cycle
+ startCycle();
+ }
+
+ // Restarting cycle
+ restartCycle = function () {
+ if (settings.auto) {
+ // Stop
+ clearInterval(rotate);
+ // Restart
+ startCycle();
+ }
+ };
+
+ // Pause on hover
+ if (settings.pause) {
+ $this.hover(function () {
+ clearInterval(rotate);
+ }, function () {
+ restartCycle();
+ });
+ }
+
+ // Pager click event handler
+ if (settings.pager || settings.manualControls) {
+ $tabs.bind("click", function (e) {
+ e.preventDefault();
+
+ if (!settings.pauseControls) {
+ restartCycle();
+ }
+
+ // Get index of clicked tab
+ var idx = $tabs.index(this);
+
+ // Break if element is already active or currently animated
+ if (index === idx || $("." + visibleClass).queue('fx').length) {
+ return;
+ }
+
+ // Remove active state from old tab and set new one
+ selectTab(idx);
+
+ // Do the animation
+ slideTo(idx);
+ })
+ .eq(0)
+ .closest("li")
+ .addClass(activeClass);
+
+ // Pause when hovering pager
+ if (settings.pauseControls) {
+ $tabs.hover(function () {
+ clearInterval(rotate);
+ }, function () {
+ restartCycle();
+ });
+ }
+ }
+
+ // Navigation
+ if (settings.nav) {
+ var navMarkup =
+ "<a href='#' class='" + navClass + " prev'>" + settings.prevText + "</a>" +
+ "<a href='#' class='" + navClass + " next'>" + settings.nextText + "</a>";
+
+ // Inject navigation
+ if (options.navContainer) {
+ $(settings.navContainer).append(navMarkup);
+ } else {
+ $this.after(navMarkup);
+ }
+
+ var $trigger = $("." + namespaceIdx + "_nav"),
+ $prev = $trigger.filter(".prev");
+
+ // Click event handler
+ $trigger.bind("click", function (e) {
+ e.preventDefault();
+
+ var $visibleClass = $("." + visibleClass);
+
+ // Prevent clicking if currently animated
+ if ($visibleClass.queue('fx').length) {
+ return;
+ }
+
+ // Adds active class during slide animation
+ // $(this)
+ // .addClass(namespace + "_active")
+ // .delay(fadeTime)
+ // .queue(function (next) {
+ // $(this).removeClass(namespace + "_active");
+ // next();
+ // });
+
+ // Determine where to slide
+ var idx = $slide.index($visibleClass),
+ prevIdx = idx - 1,
+ nextIdx = idx + 1 < length ? index + 1 : 0;
+
+ // Go to slide
+ slideTo($(this)[0] === $prev[0] ? prevIdx : nextIdx);
+ if (settings.pager || settings.manualControls) {
+ selectTab($(this)[0] === $prev[0] ? prevIdx : nextIdx);
+ }
+
+ if (!settings.pauseControls) {
+ restartCycle();
+ }
+ });
+
+ // Pause when hovering navigation
+ if (settings.pauseControls) {
+ $trigger.hover(function () {
+ clearInterval(rotate);
+ }, function () {
+ restartCycle();
+ });
+ }
+ }
+
+ }
+
+ // Max-width fallback
+ if (typeof document.body.style.maxWidth === "undefined" && options.maxwidth) {
+ var widthSupport = function () {
+ $this.css("width", "100%");
+ if ($this.width() > maxw) {
+ $this.css("width", maxw);
+ }
+ };
+
+ // Init fallback
+ widthSupport();
+ $(window).bind("resize", function () {
+ widthSupport();
+ });
+ }
+
+ });
+
+ };
+})(jQuery, this, 0); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jquery.sparkline.js b/SemanticResultFormats/resources/jquery/jquery.sparkline.js
new file mode 100644
index 00000000..6dc97b63
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jquery.sparkline.js
@@ -0,0 +1,3032 @@
+/**
+*
+* jquery.sparkline.js
+*
+* v2.1
+* (c) Splunk, Inc
+* Contact: Gareth Watts (gareth@splunk.com)
+* http://omnipotent.net/jquery.sparkline/
+*
+* Generates inline sparkline charts from data supplied either to the method
+* or inline in HTML
+*
+* Compatible with Internet Explorer 6.0+ and modern browsers equipped with the canvas tag
+* (Firefox 2.0+, Safari, Opera, etc)
+*
+* License: New BSD License
+*
+* Copyright (c) 2012, Splunk Inc.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* * Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+* * Neither the name of Splunk Inc nor the names of its contributors may
+* be used to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+* SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*
+* Usage:
+* $(selector).sparkline(values, options)
+*
+* If values is undefined or set to 'html' then the data values are read from the specified tag:
+* <p>Sparkline: <span class="sparkline">1,4,6,6,8,5,3,5</span></p>
+* $('.sparkline').sparkline();
+* There must be no spaces in the enclosed data set
+*
+* Otherwise values must be an array of numbers or null values
+* <p>Sparkline: <span id="sparkline1">This text replaced if the browser is compatible</span></p>
+* $('#sparkline1').sparkline([1,4,6,6,8,5,3,5])
+* $('#sparkline2').sparkline([1,4,6,null,null,5,3,5])
+*
+* Values can also be specified in an HTML comment, or as a values attribute:
+* <p>Sparkline: <span class="sparkline"><!--1,4,6,6,8,5,3,5 --></span></p>
+* <p>Sparkline: <span class="sparkline" values="1,4,6,6,8,5,3,5"></span></p>
+* $('.sparkline').sparkline();
+*
+* For line charts, x values can also be specified:
+* <p>Sparkline: <span class="sparkline">1:1,2.7:4,3.4:6,5:6,6:8,8.7:5,9:3,10:5</span></p>
+* $('#sparkline1').sparkline([ [1,1], [2.7,4], [3.4,6], [5,6], [6,8], [8.7,5], [9,3], [10,5] ])
+*
+* By default, options should be passed in as teh second argument to the sparkline function:
+* $('.sparkline').sparkline([1,2,3,4], {type: 'bar'})
+*
+* Options can also be set by passing them on the tag itself. This feature is disabled by default though
+* as there's a slight performance overhead:
+* $('.sparkline').sparkline([1,2,3,4], {enableTagOptions: true})
+* <p>Sparkline: <span class="sparkline" sparkType="bar" sparkBarColor="red">loading</span></p>
+* Prefix all options supplied as tag attribute with "spark" (configurable by setting tagOptionPrefix)
+*
+* Supported options:
+* lineColor - Color of the line used for the chart
+* fillColor - Color used to fill in the chart - Set to '' or false for a transparent chart
+* width - Width of the chart - Defaults to 3 times the number of values in pixels
+* height - Height of the chart - Defaults to the height of the containing element
+* chartRangeMin - Specify the minimum value to use for the Y range of the chart - Defaults to the minimum value supplied
+* chartRangeMax - Specify the maximum value to use for the Y range of the chart - Defaults to the maximum value supplied
+* chartRangeClip - Clip out of range values to the max/min specified by chartRangeMin and chartRangeMax
+* chartRangeMinX - Specify the minimum value to use for the X range of the chart - Defaults to the minimum value supplied
+* chartRangeMaxX - Specify the maximum value to use for the X range of the chart - Defaults to the maximum value supplied
+* composite - If true then don't erase any existing chart attached to the tag, but draw
+* another chart over the top - Note that width and height are ignored if an
+* existing chart is detected.
+* tagValuesAttribute - Name of tag attribute to check for data values - Defaults to 'values'
+* enableTagOptions - Whether to check tags for sparkline options
+* tagOptionPrefix - Prefix used for options supplied as tag attributes - Defaults to 'spark'
+* disableHiddenCheck - If set to true, then the plugin will assume that charts will never be drawn into a
+* hidden dom element, avoding a browser reflow
+* disableInteraction - If set to true then all mouseover/click interaction behaviour will be disabled,
+* making the plugin perform much like it did in 1.x
+* disableTooltips - If set to true then tooltips will be disabled - Defaults to false (tooltips enabled)
+* disableHighlight - If set to true then highlighting of selected chart elements on mouseover will be disabled
+* defaults to false (highlights enabled)
+* highlightLighten - Factor to lighten/darken highlighted chart values by - Defaults to 1.4 for a 40% increase
+* tooltipContainer - Specify which DOM element the tooltip should be rendered into - defaults to document.body
+* tooltipClassname - Optional CSS classname to apply to tooltips - If not specified then a default style will be applied
+* tooltipOffsetX - How many pixels away from the mouse pointer to render the tooltip on the X axis
+* tooltipOffsetY - How many pixels away from the mouse pointer to render the tooltip on the r axis
+* tooltipFormatter - Optional callback that allows you to override the HTML displayed in the tooltip
+* callback is given arguments of (sparkline, options, fields)
+* tooltipChartTitle - If specified then the tooltip uses the string specified by this setting as a title
+* tooltipFormat - A format string or SPFormat object (or an array thereof for multiple entries)
+* to control the format of the tooltip
+* tooltipPrefix - A string to prepend to each field displayed in a tooltip
+* tooltipSuffix - A string to append to each field displayed in a tooltip
+* tooltipSkipNull - If true then null values will not have a tooltip displayed (defaults to true)
+* tooltipValueLookups - An object or range map to map field values to tooltip strings
+* (eg. to map -1 to "Lost", 0 to "Draw", and 1 to "Win")
+* numberFormatter - Optional callback for formatting numbers in tooltips
+* numberDigitGroupSep - Character to use for group separator in numbers "1,234" - Defaults to ","
+* numberDecimalMark - Character to use for the decimal point when formatting numbers - Defaults to "."
+* numberDigitGroupCount - Number of digits between group separator - Defaults to 3
+*
+* There are 7 types of sparkline, selected by supplying a "type" option of 'line' (default),
+* 'bar', 'tristate', 'bullet', 'discrete', 'pie' or 'box'
+* line - Line chart. Options:
+* spotColor - Set to '' to not end each line in a circular spot
+* minSpotColor - If set, color of spot at minimum value
+* maxSpotColor - If set, color of spot at maximum value
+* spotRadius - Radius in pixels
+* lineWidth - Width of line in pixels
+* normalRangeMin
+* normalRangeMax - If set draws a filled horizontal bar between these two values marking the "normal"
+* or expected range of values
+* normalRangeColor - Color to use for the above bar
+* drawNormalOnTop - Draw the normal range above the chart fill color if true
+* defaultPixelsPerValue - Defaults to 3 pixels of width for each value in the chart
+* highlightSpotColor - The color to use for drawing a highlight spot on mouseover - Set to null to disable
+* highlightLineColor - The color to use for drawing a highlight line on mouseover - Set to null to disable
+* valueSpots - Specify which points to draw spots on, and in which color. Accepts a range map
+*
+* bar - Bar chart. Options:
+* barColor - Color of bars for postive values
+* negBarColor - Color of bars for negative values
+* zeroColor - Color of bars with zero values
+* nullColor - Color of bars with null values - Defaults to omitting the bar entirely
+* barWidth - Width of bars in pixels
+* colorMap - Optional mappnig of values to colors to override the *BarColor values above
+* can be an Array of values to control the color of individual bars or a range map
+* to specify colors for individual ranges of values
+* barSpacing - Gap between bars in pixels
+* zeroAxis - Centers the y-axis around zero if true
+*
+* tristate - Charts values of win (>0), lose (<0) or draw (=0)
+* posBarColor - Color of win values
+* negBarColor - Color of lose values
+* zeroBarColor - Color of draw values
+* barWidth - Width of bars in pixels
+* barSpacing - Gap between bars in pixels
+* colorMap - Optional mappnig of values to colors to override the *BarColor values above
+* can be an Array of values to control the color of individual bars or a range map
+* to specify colors for individual ranges of values
+*
+* discrete - Options:
+* lineHeight - Height of each line in pixels - Defaults to 30% of the graph height
+* thesholdValue - Values less than this value will be drawn using thresholdColor instead of lineColor
+* thresholdColor
+*
+* bullet - Values for bullet graphs msut be in the order: target, performance, range1, range2, range3, ...
+* options:
+* targetColor - The color of the vertical target marker
+* targetWidth - The width of the target marker in pixels
+* performanceColor - The color of the performance measure horizontal bar
+* rangeColors - Colors to use for each qualitative range background color
+*
+* pie - Pie chart. Options:
+* sliceColors - An array of colors to use for pie slices
+* offset - Angle in degrees to offset the first slice - Try -90 or +90
+* borderWidth - Width of border to draw around the pie chart, in pixels - Defaults to 0 (no border)
+* borderColor - Color to use for the pie chart border - Defaults to #000
+*
+* box - Box plot. Options:
+* raw - Set to true to supply pre-computed plot points as values
+* values should be: low_outlier, low_whisker, q1, median, q3, high_whisker, high_outlier
+* When set to false you can supply any number of values and the box plot will
+* be computed for you. Default is false.
+* showOutliers - Set to true (default) to display outliers as circles
+* outlierIQR - Interquartile range used to determine outliers. Default 1.5
+* boxLineColor - Outline color of the box
+* boxFillColor - Fill color for the box
+* whiskerColor - Line color used for whiskers
+* outlierLineColor - Outline color of outlier circles
+* outlierFillColor - Fill color of the outlier circles
+* spotRadius - Radius of outlier circles
+* medianColor - Line color of the median line
+* target - Draw a target cross hair at the supplied value (default undefined)
+*
+*
+*
+* Examples:
+* $('#sparkline1').sparkline(myvalues, { lineColor: '#f00', fillColor: false });
+* $('.barsparks').sparkline('html', { type:'bar', height:'40px', barWidth:5 });
+* $('#tristate').sparkline([1,1,-1,1,0,0,-1], { type:'tristate' }):
+* $('#discrete').sparkline([1,3,4,5,5,3,4,5], { type:'discrete' });
+* $('#bullet').sparkline([10,12,12,9,7], { type:'bullet' });
+* $('#pie').sparkline([1,1,2], { type:'pie' });
+*/
+
+/*jslint regexp: true, browser: true, jquery: true, white: true, nomen: false, plusplus: false, maxerr: 500, indent: 4 */
+
+(function(factory) {
+ if(typeof define === 'function' && define.amd) {
+ define(['jquery'], factory);
+ }
+ else {
+ factory(jQuery);
+ }
+}
+(function($) {
+ 'use strict';
+
+ var UNSET_OPTION = {},
+ getDefaults, createClass, SPFormat, clipval, quartile, normalizeValue, normalizeValues,
+ remove, isNumber, all, sum, addCSS, ensureArray, formatNumber, RangeMap,
+ MouseHandler, Tooltip, barHighlightMixin,
+ line, bar, tristate, discrete, bullet, pie, box, defaultStyles, initStyles,
+ VShape, VCanvas_base, VCanvas_canvas, VCanvas_vml, pending, shapeCount = 0;
+
+ /**
+ * Default configuration settings
+ */
+ getDefaults = function () {
+ return {
+ // Settings common to most/all chart types
+ common: {
+ type: 'line',
+ lineColor: '#00f',
+ fillColor: '#cdf',
+ defaultPixelsPerValue: 3,
+ width: 'auto',
+ height: 'auto',
+ composite: false,
+ tagValuesAttribute: 'values',
+ tagOptionsPrefix: 'spark',
+ enableTagOptions: false,
+ enableHighlight: true,
+ highlightLighten: 1.4,
+ tooltipSkipNull: true,
+ tooltipPrefix: '',
+ tooltipSuffix: '',
+ disableHiddenCheck: false,
+ numberFormatter: false,
+ numberDigitGroupCount: 3,
+ numberDigitGroupSep: ',',
+ numberDecimalMark: '.',
+ disableTooltips: false,
+ disableInteraction: false
+ },
+ // Defaults for line charts
+ line: {
+ spotColor: '#f80',
+ highlightSpotColor: '#5f5',
+ highlightLineColor: '#f22',
+ spotRadius: 1.5,
+ minSpotColor: '#f80',
+ maxSpotColor: '#f80',
+ lineWidth: 1,
+ normalRangeMin: undefined,
+ normalRangeMax: undefined,
+ normalRangeColor: '#ccc',
+ drawNormalOnTop: false,
+ chartRangeMin: undefined,
+ chartRangeMax: undefined,
+ chartRangeMinX: undefined,
+ chartRangeMaxX: undefined,
+ tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{prefix}}{{y}}{{suffix}}')
+ },
+ // Defaults for bar charts
+ bar: {
+ barColor: '#3366cc',
+ negBarColor: '#f44',
+ stackedBarColor: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',
+ '#dd4477', '#0099c6', '#990099'],
+ zeroColor: undefined,
+ nullColor: undefined,
+ zeroAxis: true,
+ barWidth: 4,
+ barSpacing: 1,
+ chartRangeMax: undefined,
+ chartRangeMin: undefined,
+ chartRangeClip: false,
+ colorMap: undefined,
+ tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{prefix}}{{value}}{{suffix}}')
+ },
+ // Defaults for tristate charts
+ tristate: {
+ barWidth: 4,
+ barSpacing: 1,
+ posBarColor: '#6f6',
+ negBarColor: '#f44',
+ zeroBarColor: '#999',
+ colorMap: {},
+ tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{value:map}}'),
+ tooltipValueLookups: { map: { '-1': 'Loss', '0': 'Draw', '1': 'Win' } }
+ },
+ // Defaults for discrete charts
+ discrete: {
+ lineHeight: 'auto',
+ thresholdColor: undefined,
+ thresholdValue: 0,
+ chartRangeMax: undefined,
+ chartRangeMin: undefined,
+ chartRangeClip: false,
+ tooltipFormat: new SPFormat('{{prefix}}{{value}}{{suffix}}')
+ },
+ // Defaults for bullet charts
+ bullet: {
+ targetColor: '#f33',
+ targetWidth: 3, // width of the target bar in pixels
+ performanceColor: '#33f',
+ rangeColors: ['#d3dafe', '#a8b6ff', '#7f94ff'],
+ base: undefined, // set this to a number to change the base start number
+ tooltipFormat: new SPFormat('{{fieldkey:fields}} - {{value}}'),
+ tooltipValueLookups: { fields: {r: 'Range', p: 'Performance', t: 'Target'} }
+ },
+ // Defaults for pie charts
+ pie: {
+ offset: 0,
+ sliceColors: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',
+ '#dd4477', '#0099c6', '#990099'],
+ borderWidth: 0,
+ borderColor: '#000',
+ tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{value}} ({{percent.1}}%)')
+ },
+ // Defaults for box plots
+ box: {
+ raw: false,
+ boxLineColor: '#000',
+ boxFillColor: '#cdf',
+ whiskerColor: '#000',
+ outlierLineColor: '#333',
+ outlierFillColor: '#fff',
+ medianColor: '#f00',
+ showOutliers: true,
+ outlierIQR: 1.5,
+ spotRadius: 1.5,
+ target: undefined,
+ targetColor: '#4a2',
+ chartRangeMax: undefined,
+ chartRangeMin: undefined,
+ tooltipFormat: new SPFormat('{{field:fields}}: {{value}}'),
+ tooltipFormatFieldlistKey: 'field',
+ tooltipValueLookups: { fields: { lq: 'Lower Quartile', med: 'Median',
+ uq: 'Upper Quartile', lo: 'Left Outlier', ro: 'Right Outlier',
+ lw: 'Left Whisker', rw: 'Right Whisker'} }
+ }
+ };
+ };
+
+ // You can have tooltips use a css class other than jqstooltip by specifying tooltipClassname
+ defaultStyles = '.jqstooltip { ' +
+ 'position: absolute;' +
+ 'left: 0px;' +
+ 'top: 0px;' +
+ 'visibility: hidden;' +
+ 'background: rgb(0, 0, 0) transparent;' +
+ 'background-color: rgba(0,0,0,0.6);' +
+ 'filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);' +
+ '-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)";' +
+ 'color: white;' +
+ 'font: 10px arial, san serif;' +
+ 'text-align: left;' +
+ 'white-space: nowrap;' +
+ 'padding: 5px;' +
+ 'border: 1px solid white;' +
+ 'z-index: 10000;' +
+ '}' +
+ '.jqsfield { ' +
+ 'color: white;' +
+ 'font: 10px arial, san serif;' +
+ 'text-align: left;' +
+ '}';
+
+ /**
+ * Utilities
+ */
+
+ createClass = function (/* [baseclass, [mixin, ...]], definition */) {
+ var Class, args;
+ Class = function () {
+ this.init.apply(this, arguments);
+ };
+ if (arguments.length > 1) {
+ if (arguments[0]) {
+ Class.prototype = $.extend(new arguments[0](), arguments[arguments.length - 1]);
+ Class._super = arguments[0].prototype;
+ } else {
+ Class.prototype = arguments[arguments.length - 1];
+ }
+ if (arguments.length > 2) {
+ args = Array.prototype.slice.call(arguments, 1, -1);
+ args.unshift(Class.prototype);
+ $.extend.apply($, args);
+ }
+ } else {
+ Class.prototype = arguments[0];
+ }
+ Class.prototype.cls = Class;
+ return Class;
+ };
+
+ /**
+ * Wraps a format string for tooltips
+ * {{x}}
+ * {{x.2}
+ * {{x:months}}
+ */
+ $.SPFormatClass = SPFormat = createClass({
+ fre: /\{\{([\w.]+?)(:(.+?))?\}\}/g,
+ precre: /(\w+)\.(\d+)/,
+
+ init: function (format, fclass) {
+ this.format = format;
+ this.fclass = fclass;
+ },
+
+ render: function (fieldset, lookups, options) {
+ var self = this,
+ fields = fieldset,
+ match, token, lookupkey, fieldvalue, prec;
+ return this.format.replace(this.fre, function () {
+ var lookup;
+ token = arguments[1];
+ lookupkey = arguments[3];
+ match = self.precre.exec(token);
+ if (match) {
+ prec = match[2];
+ token = match[1];
+ } else {
+ prec = false;
+ }
+ fieldvalue = fields[token];
+ if (fieldvalue === undefined) {
+ return '';
+ }
+ if (lookupkey && lookups && lookups[lookupkey]) {
+ lookup = lookups[lookupkey];
+ if (lookup.get) { // RangeMap
+ return lookups[lookupkey].get(fieldvalue) || fieldvalue;
+ } else {
+ return lookups[lookupkey][fieldvalue] || fieldvalue;
+ }
+ }
+ if (isNumber(fieldvalue)) {
+ if (options.get('numberFormatter')) {
+ fieldvalue = options.get('numberFormatter')(fieldvalue);
+ } else {
+ fieldvalue = formatNumber(fieldvalue, prec,
+ options.get('numberDigitGroupCount'),
+ options.get('numberDigitGroupSep'),
+ options.get('numberDecimalMark'));
+ }
+ }
+ return fieldvalue;
+ });
+ }
+ });
+
+ // convience method to avoid needing the new operator
+ $.spformat = function(format, fclass) {
+ return new SPFormat(format, fclass);
+ };
+
+ clipval = function (val, min, max) {
+ if (val < min) {
+ return min;
+ }
+ if (val > max) {
+ return max;
+ }
+ return val;
+ };
+
+ quartile = function (values, q) {
+ var vl;
+ if (q === 2) {
+ vl = Math.floor(values.length / 2);
+ return values.length % 2 ? values[vl] : (values[vl-1] + values[vl]) / 2;
+ } else {
+ if (values.length % 2 ) { // odd
+ vl = (values.length * q + q) / 4;
+ return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];
+ } else { //even
+ vl = (values.length * q + 2) / 4;
+ return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];
+
+ }
+ }
+ };
+
+ normalizeValue = function (val) {
+ var nf;
+ switch (val) {
+ case 'undefined':
+ val = undefined;
+ break;
+ case 'null':
+ val = null;
+ break;
+ case 'true':
+ val = true;
+ break;
+ case 'false':
+ val = false;
+ break;
+ default:
+ nf = parseFloat(val);
+ if (val == nf) {
+ val = nf;
+ }
+ }
+ return val;
+ };
+
+ normalizeValues = function (vals) {
+ var i, result = [];
+ for (i = vals.length; i--;) {
+ result[i] = normalizeValue(vals[i]);
+ }
+ return result;
+ };
+
+ remove = function (vals, filter) {
+ var i, vl, result = [];
+ for (i = 0, vl = vals.length; i < vl; i++) {
+ if (vals[i] !== filter) {
+ result.push(vals[i]);
+ }
+ }
+ return result;
+ };
+
+ isNumber = function (num) {
+ return !isNaN(parseFloat(num)) && isFinite(num);
+ };
+
+ formatNumber = function (num, prec, groupsize, groupsep, decsep) {
+ var p, i;
+ num = (prec === false ? parseFloat(num).toString() : num.toFixed(prec)).split('');
+ p = (p = $.inArray('.', num)) < 0 ? num.length : p;
+ if (p < num.length) {
+ num[p] = decsep;
+ }
+ for (i = p - groupsize; i > 0; i -= groupsize) {
+ num.splice(i, 0, groupsep);
+ }
+ return num.join('');
+ };
+
+ // determine if all values of an array match a value
+ // returns true if the array is empty
+ all = function (val, arr, ignoreNull) {
+ var i;
+ for (i = arr.length; i--; ) {
+ if (ignoreNull && arr[i] === null) continue;
+ if (arr[i] !== val) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ // sums the numeric values in an array, ignoring other values
+ sum = function (vals) {
+ var total = 0, i;
+ for (i = vals.length; i--;) {
+ total += typeof vals[i] === 'number' ? vals[i] : 0;
+ }
+ return total;
+ };
+
+ ensureArray = function (val) {
+ return $.isArray(val) ? val : [val];
+ };
+
+ // http://paulirish.com/2008/bookmarklet-inject-new-css-rules/
+ addCSS = function(css) {
+ var tag;
+ //if ('\v' == 'v') /* ie only */ {
+ if (document.createStyleSheet) {
+ document.createStyleSheet().cssText = css;
+ } else {
+ tag = document.createElement('style');
+ tag.type = 'text/css';
+ document.getElementsByTagName('head')[0].appendChild(tag);
+ tag[(typeof document.body.style.WebkitAppearance == 'string') /* webkit only */ ? 'innerText' : 'innerHTML'] = css;
+ }
+ };
+
+ // Provide a cross-browser interface to a few simple drawing primitives
+ $.fn.simpledraw = function (width, height, useExisting, interact) {
+ var target, mhandler;
+ if (useExisting && (target = this.data('_jqs_vcanvas'))) {
+ return target;
+ }
+ if (width === undefined) {
+ width = $(this).innerWidth();
+ }
+ if (height === undefined) {
+ height = $(this).innerHeight();
+ }
+ if ($.browser.hasCanvas) {
+ target = new VCanvas_canvas(width, height, this, interact);
+ } else if ($.browser.msie) {
+ target = new VCanvas_vml(width, height, this);
+ } else {
+ return false;
+ }
+ mhandler = $(this).data('_jqs_mhandler');
+ if (mhandler) {
+ mhandler.registerCanvas(target);
+ }
+ return target;
+ };
+
+ $.fn.cleardraw = function () {
+ var target = this.data('_jqs_vcanvas');
+ if (target) {
+ target.reset();
+ }
+ };
+
+ $.RangeMapClass = RangeMap = createClass({
+ init: function (map) {
+ var key, range, rangelist = [];
+ for (key in map) {
+ if (map.hasOwnProperty(key) && typeof key === 'string' && key.indexOf(':') > -1) {
+ range = key.split(':');
+ range[0] = range[0].length === 0 ? -Infinity : parseFloat(range[0]);
+ range[1] = range[1].length === 0 ? Infinity : parseFloat(range[1]);
+ range[2] = map[key];
+ rangelist.push(range);
+ }
+ }
+ this.map = map;
+ this.rangelist = rangelist || false;
+ },
+
+ get: function (value) {
+ var rangelist = this.rangelist,
+ i, range, result;
+ if ((result = this.map[value]) !== undefined) {
+ return result;
+ }
+ if (rangelist) {
+ for (i = rangelist.length; i--;) {
+ range = rangelist[i];
+ if (range[0] <= value && range[1] >= value) {
+ return range[2];
+ }
+ }
+ }
+ return undefined;
+ }
+ });
+
+ // Convenience function
+ $.range_map = function(map) {
+ return new RangeMap(map);
+ };
+
+ MouseHandler = createClass({
+ init: function (el, options) {
+ var $el = $(el);
+ this.$el = $el;
+ this.options = options;
+ this.currentPageX = 0;
+ this.currentPageY = 0;
+ this.el = el;
+ this.splist = [];
+ this.tooltip = null;
+ this.over = false;
+ this.displayTooltips = !options.get('disableTooltips');
+ this.highlightEnabled = !options.get('disableHighlight');
+ },
+
+ registerSparkline: function (sp) {
+ this.splist.push(sp);
+ if (this.over) {
+ this.updateDisplay();
+ }
+ },
+
+ registerCanvas: function (canvas) {
+ var $canvas = $(canvas.canvas);
+ this.canvas = canvas;
+ this.$canvas = $canvas;
+ $canvas.mouseenter($.proxy(this.mouseenter, this));
+ $canvas.mouseleave($.proxy(this.mouseleave, this));
+ $canvas.click($.proxy(this.mouseclick, this));
+ },
+
+ reset: function (removeTooltip) {
+ this.splist = [];
+ if (this.tooltip && removeTooltip) {
+ this.tooltip.remove();
+ this.tooltip = undefined;
+ }
+ },
+
+ mouseclick: function (e) {
+ var clickEvent = $.Event('sparklineClick');
+ clickEvent.originalEvent = e;
+ clickEvent.sparklines = this.splist;
+ this.$el.trigger(clickEvent);
+ },
+
+ mouseenter: function (e) {
+ $(document.body).unbind('mousemove.jqs');
+ $(document.body).bind('mousemove.jqs', $.proxy(this.mousemove, this));
+ this.over = true;
+ this.currentPageX = e.pageX;
+ this.currentPageY = e.pageY;
+ this.currentEl = e.target;
+ if (!this.tooltip && this.displayTooltips) {
+ this.tooltip = new Tooltip(this.options);
+ this.tooltip.updatePosition(e.pageX, e.pageY);
+ }
+ this.updateDisplay();
+ },
+
+ mouseleave: function () {
+ $(document.body).unbind('mousemove.jqs');
+ var splist = this.splist,
+ spcount = splist.length,
+ needsRefresh = false,
+ sp, i;
+ this.over = false;
+ this.currentEl = null;
+
+ if (this.tooltip) {
+ this.tooltip.remove();
+ this.tooltip = null;
+ }
+
+ for (i = 0; i < spcount; i++) {
+ sp = splist[i];
+ if (sp.clearRegionHighlight()) {
+ needsRefresh = true;
+ }
+ }
+
+ if (needsRefresh) {
+ this.canvas.render();
+ }
+ },
+
+ mousemove: function (e) {
+ this.currentPageX = e.pageX;
+ this.currentPageY = e.pageY;
+ this.currentEl = e.target;
+ if (this.tooltip) {
+ this.tooltip.updatePosition(e.pageX, e.pageY);
+ }
+ this.updateDisplay();
+ },
+
+ updateDisplay: function () {
+ var splist = this.splist,
+ spcount = splist.length,
+ needsRefresh = false,
+ offset = this.$canvas.offset(),
+ localX = this.currentPageX - offset.left,
+ localY = this.currentPageY - offset.top,
+ tooltiphtml, sp, i, result, changeEvent;
+ if (!this.over) {
+ return;
+ }
+ for (i = 0; i < spcount; i++) {
+ sp = splist[i];
+ result = sp.setRegionHighlight(this.currentEl, localX, localY);
+ if (result) {
+ needsRefresh = true;
+ }
+ }
+ if (needsRefresh) {
+ changeEvent = $.Event('sparklineRegionChange');
+ changeEvent.sparklines = this.splist;
+ this.$el.trigger(changeEvent);
+ if (this.tooltip) {
+ tooltiphtml = '';
+ for (i = 0; i < spcount; i++) {
+ sp = splist[i];
+ tooltiphtml += sp.getCurrentRegionTooltip();
+ }
+ this.tooltip.setContent(tooltiphtml);
+ }
+ if (!this.disableHighlight) {
+ this.canvas.render();
+ }
+ }
+ if (result === null) {
+ this.mouseleave();
+ }
+ }
+ });
+
+
+ Tooltip = createClass({
+ sizeStyle: 'position: static !important;' +
+ 'display: block !important;' +
+ 'visibility: hidden !important;' +
+ 'float: left !important;',
+
+ init: function (options) {
+ var tooltipClassname = options.get('tooltipClassname', 'jqstooltip'),
+ sizetipStyle = this.sizeStyle,
+ offset;
+ this.container = options.get('tooltipContainer') || document.body;
+ this.tooltipOffsetX = options.get('tooltipOffsetX', 10);
+ this.tooltipOffsetY = options.get('tooltipOffsetY', 12);
+ // remove any previous lingering tooltip
+ $('#jqssizetip').remove();
+ $('#jqstooltip').remove();
+ this.sizetip = $('<div/>', {
+ id: 'jqssizetip',
+ style: sizetipStyle,
+ 'class': tooltipClassname
+ });
+ this.tooltip = $('<div/>', {
+ id: 'jqstooltip',
+ 'class': tooltipClassname
+ }).appendTo(this.container);
+ // account for the container's location
+ offset = this.tooltip.offset();
+ this.offsetLeft = offset.left;
+ this.offsetTop = offset.top;
+ this.hidden = true;
+ $(window).unbind('resize.jqs scroll.jqs');
+ $(window).bind('resize.jqs scroll.jqs', $.proxy(this.updateWindowDims, this));
+ this.updateWindowDims();
+ },
+
+ updateWindowDims: function () {
+ this.scrollTop = $(window).scrollTop();
+ this.scrollLeft = $(window).scrollLeft();
+ this.scrollRight = this.scrollLeft + $(window).width();
+ this.updatePosition();
+ },
+
+ getSize: function (content) {
+ this.sizetip.html(content).appendTo(this.container);
+ this.width = this.sizetip.width() + 1;
+ this.height = this.sizetip.height();
+ this.sizetip.remove();
+ },
+
+ setContent: function (content) {
+ if (!content) {
+ this.tooltip.css('visibility', 'hidden');
+ this.hidden = true;
+ return;
+ }
+ this.getSize(content);
+ this.tooltip.html(content)
+ .css({
+ 'width': this.width,
+ 'height': this.height,
+ 'visibility': 'visible'
+ });
+ if (this.hidden) {
+ this.hidden = false;
+ this.updatePosition();
+ }
+ },
+
+ updatePosition: function (x, y) {
+ if (x === undefined) {
+ if (this.mousex === undefined) {
+ return;
+ }
+ x = this.mousex - this.offsetLeft;
+ y = this.mousey - this.offsetTop;
+
+ } else {
+ this.mousex = x = x - this.offsetLeft;
+ this.mousey = y = y - this.offsetTop;
+ }
+ if (!this.height || !this.width || this.hidden) {
+ return;
+ }
+
+ y -= this.height + this.tooltipOffsetY;
+ x += this.tooltipOffsetX;
+
+ if (y < this.scrollTop) {
+ y = this.scrollTop;
+ }
+ if (x < this.scrollLeft) {
+ x = this.scrollLeft;
+ } else if (x + this.width > this.scrollRight) {
+ x = this.scrollRight - this.width;
+ }
+
+ this.tooltip.css({
+ 'left': x,
+ 'top': y
+ });
+ },
+
+ remove: function () {
+ this.tooltip.remove();
+ this.sizetip.remove();
+ this.sizetip = this.tooltip = undefined;
+ $(window).unbind('resize.jqs scroll.jqs');
+ }
+ });
+
+ initStyles = function() {
+ addCSS(defaultStyles);
+ };
+
+ $(initStyles);
+
+ pending = [];
+ $.fn.sparkline = function (userValues, userOptions) {
+ return this.each(function () {
+ var options = new $.fn.sparkline.options(this, userOptions),
+ $this = $(this),
+ render, i;
+ render = function () {
+ var values, width, height, tmp, mhandler, sp, vals;
+ if (userValues === 'html' || userValues === undefined) {
+ vals = this.getAttribute(options.get('tagValuesAttribute'));
+ if (vals === undefined || vals === null) {
+ vals = $this.html();
+ }
+ values = vals.replace(/(^\s*<!--)|(-->\s*$)|\s+/g, '').split(',');
+ } else {
+ values = userValues;
+ }
+
+ width = options.get('width') === 'auto' ? values.length * options.get('defaultPixelsPerValue') : options.get('width');
+ if (options.get('height') === 'auto') {
+ if (!options.get('composite') || !$.data(this, '_jqs_vcanvas')) {
+ // must be a better way to get the line height
+ tmp = document.createElement('span');
+ tmp.innerHTML = 'a';
+ $this.html(tmp);
+ height = $(tmp).innerHeight() || $(tmp).height();
+ $(tmp).remove();
+ tmp = null;
+ }
+ } else {
+ height = options.get('height');
+ }
+
+ if (!options.get('disableInteraction')) {
+ mhandler = $.data(this, '_jqs_mhandler');
+ if (!mhandler) {
+ mhandler = new MouseHandler(this, options);
+ $.data(this, '_jqs_mhandler', mhandler);
+ } else if (!options.get('composite')) {
+ mhandler.reset();
+ }
+ } else {
+ mhandler = false;
+ }
+
+ if (options.get('composite') && !$.data(this, '_jqs_vcanvas')) {
+ if (!$.data(this, '_jqs_errnotify')) {
+ alert('Attempted to attach a composite sparkline to an element with no existing sparkline');
+ $.data(this, '_jqs_errnotify', true);
+ }
+ return;
+ }
+
+ sp = new $.fn.sparkline[options.get('type')](this, values, options, width, height);
+
+ sp.render();
+
+ if (mhandler) {
+ mhandler.registerSparkline(sp);
+ }
+ };
+ // jQuery 1.3.0 completely changed the meaning of :hidden :-/
+ if (($(this).html() && !options.get('disableHiddenCheck') && $(this).is(':hidden')) || ($.fn.jquery < '1.3.0' && $(this).parents().is(':hidden')) || !$(this).parents('body').length) {
+ if (!options.get('composite') && $.data(this, '_jqs_pending')) {
+ // remove any existing references to the element
+ for (i = pending.length; i; i--) {
+ if (pending[i - 1][0] == this) {
+ pending.splice(i - 1, 1);
+ }
+ }
+ }
+ pending.push([this, render]);
+ $.data(this, '_jqs_pending', true);
+ } else {
+ render.call(this);
+ }
+ });
+ };
+
+ $.fn.sparkline.defaults = getDefaults();
+
+
+ $.sparkline_display_visible = function () {
+ var el, i, pl;
+ var done = [];
+ for (i = 0, pl = pending.length; i < pl; i++) {
+ el = pending[i][0];
+ if ($(el).is(':visible') && !$(el).parents().is(':hidden')) {
+ pending[i][1].call(el);
+ $.data(pending[i][0], '_jqs_pending', false);
+ done.push(i);
+ } else if (!$(el).closest('html').length && !$.data(el, '_jqs_pending')) {
+ // element has been inserted and removed from the DOM
+ // If it was not yet inserted into the dom then the .data request
+ // will return true.
+ // removing from the dom causes the data to be removed.
+ $.data(pending[i][0], '_jqs_pending', false);
+ done.push(i);
+ }
+ }
+ for (i = done.length; i; i--) {
+ pending.splice(done[i - 1], 1);
+ }
+ };
+
+
+ /**
+ * User option handler
+ */
+ $.fn.sparkline.options = createClass({
+ init: function (tag, userOptions) {
+ var extendedOptions, defaults, base, tagOptionType;
+ this.userOptions = userOptions = userOptions || {};
+ this.tag = tag;
+ this.tagValCache = {};
+ defaults = $.fn.sparkline.defaults;
+ base = defaults.common;
+ this.tagOptionsPrefix = userOptions.enableTagOptions && (userOptions.tagOptionsPrefix || base.tagOptionsPrefix);
+
+ tagOptionType = this.getTagSetting('type');
+ if (tagOptionType === UNSET_OPTION) {
+ extendedOptions = defaults[userOptions.type || base.type];
+ } else {
+ extendedOptions = defaults[tagOptionType];
+ }
+ this.mergedOptions = $.extend({}, base, extendedOptions, userOptions);
+ },
+
+
+ getTagSetting: function (key) {
+ var prefix = this.tagOptionsPrefix,
+ val, i, pairs, keyval;
+ if (prefix === false || prefix === undefined) {
+ return UNSET_OPTION;
+ }
+ if (this.tagValCache.hasOwnProperty(key)) {
+ val = this.tagValCache.key;
+ } else {
+ val = this.tag.getAttribute(prefix + key);
+ if (val === undefined || val === null) {
+ val = UNSET_OPTION;
+ } else if (val.substr(0, 1) === '[') {
+ val = val.substr(1, val.length - 2).split(',');
+ for (i = val.length; i--;) {
+ val[i] = normalizeValue(val[i].replace(/(^\s*)|(\s*$)/g, ''));
+ }
+ } else if (val.substr(0, 1) === '{') {
+ pairs = val.substr(1, val.length - 2).split(',');
+ val = {};
+ for (i = pairs.length; i--;) {
+ keyval = pairs[i].split(':', 2);
+ val[keyval[0].replace(/(^\s*)|(\s*$)/g, '')] = normalizeValue(keyval[1].replace(/(^\s*)|(\s*$)/g, ''));
+ }
+ } else {
+ val = normalizeValue(val);
+ }
+ this.tagValCache.key = val;
+ }
+ return val;
+ },
+
+ get: function (key, defaultval) {
+ var tagOption = this.getTagSetting(key),
+ result;
+ if (tagOption !== UNSET_OPTION) {
+ return tagOption;
+ }
+ return (result = this.mergedOptions[key]) === undefined ? defaultval : result;
+ }
+ });
+
+
+ $.fn.sparkline._base = createClass({
+ disabled: false,
+
+ init: function (el, values, options, width, height) {
+ this.el = el;
+ this.$el = $(el);
+ this.values = values;
+ this.options = options;
+ this.width = width;
+ this.height = height;
+ this.currentRegion = undefined;
+ },
+
+ /**
+ * Setup the canvas
+ */
+ initTarget: function () {
+ var interactive = !this.options.get('disableInteraction');
+ if (!(this.target = this.$el.simpledraw(this.width, this.height, this.options.get('composite'), interactive))) {
+ this.disabled = true;
+ } else {
+ this.canvasWidth = this.target.pixelWidth;
+ this.canvasHeight = this.target.pixelHeight;
+ }
+ },
+
+ /**
+ * Actually render the chart to the canvas
+ */
+ render: function () {
+ if (this.disabled) {
+ this.el.innerHTML = '';
+ return false;
+ }
+ return true;
+ },
+
+ /**
+ * Return a region id for a given x/y co-ordinate
+ */
+ getRegion: function (x, y) {
+ },
+
+ /**
+ * Highlight an item based on the moused-over x,y co-ordinate
+ */
+ setRegionHighlight: function (el, x, y) {
+ var currentRegion = this.currentRegion,
+ highlightEnabled = !this.options.get('disableHighlight'),
+ newRegion;
+ if (x > this.canvasWidth || y > this.canvasHeight || x < 0 || y < 0) {
+ return null;
+ }
+ newRegion = this.getRegion(el, x, y);
+ if (currentRegion !== newRegion) {
+ if (currentRegion !== undefined && highlightEnabled) {
+ this.removeHighlight();
+ }
+ this.currentRegion = newRegion;
+ if (newRegion !== undefined && highlightEnabled) {
+ this.renderHighlight();
+ }
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Reset any currently highlighted item
+ */
+ clearRegionHighlight: function () {
+ if (this.currentRegion !== undefined) {
+ this.removeHighlight();
+ this.currentRegion = undefined;
+ return true;
+ }
+ return false;
+ },
+
+ renderHighlight: function () {
+ this.changeHighlight(true);
+ },
+
+ removeHighlight: function () {
+ this.changeHighlight(false);
+ },
+
+ changeHighlight: function (highlight) {},
+
+ /**
+ * Fetch the HTML to display as a tooltip
+ */
+ getCurrentRegionTooltip: function () {
+ var options = this.options,
+ header = '',
+ entries = [],
+ fields, formats, formatlen, fclass, text, i,
+ showFields, showFieldsKey, newFields, fv,
+ formatter, format, fieldlen, j;
+ if (this.currentRegion === undefined) {
+ return '';
+ }
+ fields = this.getCurrentRegionFields();
+ formatter = options.get('tooltipFormatter');
+ if (formatter) {
+ return formatter(this, options, fields);
+ }
+ if (options.get('tooltipChartTitle')) {
+ header += '<div class="jqs jqstitle">' + options.get('tooltipChartTitle') + '</div>\n';
+ }
+ formats = this.options.get('tooltipFormat');
+ if (!formats) {
+ return '';
+ }
+ if (!$.isArray(formats)) {
+ formats = [formats];
+ }
+ if (!$.isArray(fields)) {
+ fields = [fields];
+ }
+ showFields = this.options.get('tooltipFormatFieldlist');
+ showFieldsKey = this.options.get('tooltipFormatFieldlistKey');
+ if (showFields && showFieldsKey) {
+ // user-selected ordering of fields
+ newFields = [];
+ for (i = fields.length; i--;) {
+ fv = fields[i][showFieldsKey];
+ if ((j = $.inArray(fv, showFields)) != -1) {
+ newFields[j] = fields[i];
+ }
+ }
+ fields = newFields;
+ }
+ formatlen = formats.length;
+ fieldlen = fields.length;
+ for (i = 0; i < formatlen; i++) {
+ format = formats[i];
+ if (typeof format === 'string') {
+ format = new SPFormat(format);
+ }
+ fclass = format.fclass || 'jqsfield';
+ for (j = 0; j < fieldlen; j++) {
+ if (!fields[j].isNull || !options.get('tooltipSkipNull')) {
+ $.extend(fields[j], {
+ prefix: options.get('tooltipPrefix'),
+ suffix: options.get('tooltipSuffix')
+ });
+ text = format.render(fields[j], options.get('tooltipValueLookups'), options);
+ entries.push('<div class="' + fclass + '">' + text + '</div>');
+ }
+ }
+ }
+ if (entries.length) {
+ return header + entries.join('\n');
+ }
+ return '';
+ },
+
+ getCurrentRegionFields: function () {},
+
+ calcHighlightColor: function (color, options) {
+ var highlightColor = options.get('highlightColor'),
+ lighten = options.get('highlightLighten'),
+ parse, mult, rgbnew, i;
+ if (highlightColor) {
+ return highlightColor;
+ }
+ if (lighten) {
+ // extract RGB values
+ parse = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(color) || /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(color);
+ if (parse) {
+ rgbnew = [];
+ mult = color.length === 4 ? 16 : 1;
+ for (i = 0; i < 3; i++) {
+ rgbnew[i] = clipval(Math.round(parseInt(parse[i + 1], 16) * mult * lighten), 0, 255);
+ }
+ return 'rgb(' + rgbnew.join(',') + ')';
+ }
+
+ }
+ return color;
+ }
+
+ });
+
+ barHighlightMixin = {
+ changeHighlight: function (highlight) {
+ var currentRegion = this.currentRegion,
+ target = this.target,
+ shapeids = this.regionShapes[currentRegion],
+ newShapes;
+ // will be null if the region value was null
+ if (shapeids) {
+ newShapes = this.renderRegion(currentRegion, highlight);
+ if ($.isArray(newShapes) || $.isArray(shapeids)) {
+ target.replaceWithShapes(shapeids, newShapes);
+ this.regionShapes[currentRegion] = $.map(newShapes, function (newShape) {
+ return newShape.id;
+ });
+ } else {
+ target.replaceWithShape(shapeids, newShapes);
+ this.regionShapes[currentRegion] = newShapes.id;
+ }
+ }
+ },
+
+ render: function () {
+ var values = this.values,
+ target = this.target,
+ regionShapes = this.regionShapes,
+ shapes, ids, i, j;
+
+ if (!this.cls._super.render.call(this)) {
+ return;
+ }
+ for (i = values.length; i--;) {
+ shapes = this.renderRegion(i);
+ if (shapes) {
+ if ($.isArray(shapes)) {
+ ids = [];
+ for (j = shapes.length; j--;) {
+ shapes[j].append();
+ ids.push(shapes[j].id);
+ }
+ regionShapes[i] = ids;
+ } else {
+ shapes.append();
+ regionShapes[i] = shapes.id; // store just the shapeid
+ }
+ } else {
+ // null value
+ regionShapes[i] = null;
+ }
+ }
+ target.render();
+ }
+ };
+
+ /**
+ * Line charts
+ */
+ $.fn.sparkline.line = line = createClass($.fn.sparkline._base, {
+ type: 'line',
+
+ init: function (el, values, options, width, height) {
+ line._super.init.call(this, el, values, options, width, height);
+ this.vertices = [];
+ this.regionMap = [];
+ this.xvalues = [];
+ this.yvalues = [];
+ this.yminmax = [];
+ this.hightlightSpotId = null;
+ this.lastShapeId = null;
+ this.initTarget();
+ },
+
+ getRegion: function (el, x, y) {
+ var i,
+ regionMap = this.regionMap; // maps regions to value positions
+ for (i = regionMap.length; i--;) {
+ if (regionMap[i] !== null && x >= regionMap[i][0] && x <= regionMap[i][1]) {
+ return regionMap[i][2];
+ }
+ }
+ return undefined;
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ isNull: this.yvalues[currentRegion] === null,
+ x: this.xvalues[currentRegion],
+ y: this.yvalues[currentRegion],
+ color: this.options.get('lineColor'),
+ fillColor: this.options.get('fillColor'),
+ offset: currentRegion
+ };
+ },
+
+ renderHighlight: function () {
+ var currentRegion = this.currentRegion,
+ target = this.target,
+ vertex = this.vertices[currentRegion],
+ options = this.options,
+ spotRadius = options.get('spotRadius'),
+ highlightSpotColor = options.get('highlightSpotColor'),
+ highlightLineColor = options.get('highlightLineColor'),
+ highlightSpot, highlightLine;
+
+ if (!vertex) {
+ return;
+ }
+ if (spotRadius && highlightSpotColor) {
+ highlightSpot = target.drawCircle(vertex[0], vertex[1],
+ spotRadius, undefined, highlightSpotColor);
+ this.highlightSpotId = highlightSpot.id;
+ target.insertAfterShape(this.lastShapeId, highlightSpot);
+ }
+ if (highlightLineColor) {
+ highlightLine = target.drawLine(vertex[0], this.canvasTop, vertex[0],
+ this.canvasTop + this.canvasHeight, highlightLineColor);
+ this.highlightLineId = highlightLine.id;
+ target.insertAfterShape(this.lastShapeId, highlightLine);
+ }
+ },
+
+ removeHighlight: function () {
+ var target = this.target;
+ if (this.highlightSpotId) {
+ target.removeShapeId(this.highlightSpotId);
+ this.highlightSpotId = null;
+ }
+ if (this.highlightLineId) {
+ target.removeShapeId(this.highlightLineId);
+ this.highlightLineId = null;
+ }
+ },
+
+ scanValues: function () {
+ var values = this.values,
+ valcount = values.length,
+ xvalues = this.xvalues,
+ yvalues = this.yvalues,
+ yminmax = this.yminmax,
+ i, val, isStr, isArray, sp;
+ for (i = 0; i < valcount; i++) {
+ val = values[i];
+ isStr = typeof(values[i]) === 'string';
+ isArray = typeof(values[i]) === 'object' && values[i] instanceof Array;
+ sp = isStr && values[i].split(':');
+ if (isStr && sp.length === 2) { // x:y
+ xvalues.push(Number(sp[0]));
+ yvalues.push(Number(sp[1]));
+ yminmax.push(Number(sp[1]));
+ } else if (isArray) {
+ xvalues.push(val[0]);
+ yvalues.push(val[1]);
+ yminmax.push(val[1]);
+ } else {
+ xvalues.push(i);
+ if (values[i] === null || values[i] === 'null') {
+ yvalues.push(null);
+ } else {
+ yvalues.push(Number(val));
+ yminmax.push(Number(val));
+ }
+ }
+ }
+ if (this.options.get('xvalues')) {
+ xvalues = this.options.get('xvalues');
+ }
+
+ this.maxy = this.maxyorg = Math.max.apply(Math, yminmax);
+ this.miny = this.minyorg = Math.min.apply(Math, yminmax);
+
+ this.maxx = Math.max.apply(Math, xvalues);
+ this.minx = Math.min.apply(Math, xvalues);
+
+ this.xvalues = xvalues;
+ this.yvalues = yvalues;
+ this.yminmax = yminmax;
+
+ },
+
+ processRangeOptions: function () {
+ var options = this.options,
+ normalRangeMin = options.get('normalRangeMin'),
+ normalRangeMax = options.get('normalRangeMax');
+
+ if (normalRangeMin !== undefined) {
+ if (normalRangeMin < this.miny) {
+ this.miny = normalRangeMin;
+ }
+ if (normalRangeMax > this.maxy) {
+ this.maxy = normalRangeMax;
+ }
+ }
+ if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.miny)) {
+ this.miny = options.get('chartRangeMin');
+ }
+ if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.maxy)) {
+ this.maxy = options.get('chartRangeMax');
+ }
+ if (options.get('chartRangeMinX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMinX') < this.minx)) {
+ this.minx = options.get('chartRangeMinX');
+ }
+ if (options.get('chartRangeMaxX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMaxX') > this.maxx)) {
+ this.maxx = options.get('chartRangeMaxX');
+ }
+
+ },
+
+ drawNormalRange: function (canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey) {
+ var normalRangeMin = this.options.get('normalRangeMin'),
+ normalRangeMax = this.options.get('normalRangeMax'),
+ ytop = canvasTop + Math.round(canvasHeight - (canvasHeight * ((normalRangeMax - this.miny) / rangey))),
+ height = Math.round((canvasHeight * (normalRangeMax - normalRangeMin)) / rangey);
+ this.target.drawRect(canvasLeft, ytop, canvasWidth, height, undefined, this.options.get('normalRangeColor')).append();
+ },
+
+ render: function () {
+ var options = this.options,
+ target = this.target,
+ canvasWidth = this.canvasWidth,
+ canvasHeight = this.canvasHeight,
+ vertices = this.vertices,
+ spotRadius = options.get('spotRadius'),
+ regionMap = this.regionMap,
+ rangex, rangey, yvallast,
+ canvasTop, canvasLeft,
+ vertex, path, paths, x, y, xnext, xpos, xposnext,
+ last, next, yvalcount, lineShapes, fillShapes, plen,
+ valueSpots, hlSpotsEnabled, color, xvalues, yvalues, i;
+
+ if (!line._super.render.call(this)) {
+ return;
+ }
+
+ this.scanValues();
+ this.processRangeOptions();
+
+ xvalues = this.xvalues;
+ yvalues = this.yvalues;
+
+ if (!this.yminmax.length || this.yvalues.length < 2) {
+ // empty or all null valuess
+ return;
+ }
+
+ canvasTop = canvasLeft = 0;
+
+ rangex = this.maxx - this.minx === 0 ? 1 : this.maxx - this.minx;
+ rangey = this.maxy - this.miny === 0 ? 1 : this.maxy - this.miny;
+ yvallast = this.yvalues.length - 1;
+
+ if (spotRadius && (canvasWidth < (spotRadius * 4) || canvasHeight < (spotRadius * 4))) {
+ spotRadius = 0;
+ }
+ if (spotRadius) {
+ // adjust the canvas size as required so that spots will fit
+ hlSpotsEnabled = options.get('highlightSpotColor') && !options.get('disableInteraction');
+ if (hlSpotsEnabled || options.get('minSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.miny)) {
+ canvasHeight -= Math.ceil(spotRadius);
+ }
+ if (hlSpotsEnabled || options.get('maxSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.maxy)) {
+ canvasHeight -= Math.ceil(spotRadius);
+ canvasTop += Math.ceil(spotRadius);
+ }
+ if (hlSpotsEnabled ||
+ ((options.get('minSpotColor') || options.get('maxSpotColor')) && (yvalues[0] === this.miny || yvalues[0] === this.maxy))) {
+ canvasLeft += Math.ceil(spotRadius);
+ canvasWidth -= Math.ceil(spotRadius);
+ }
+ if (hlSpotsEnabled || options.get('spotColor') ||
+ (options.get('minSpotColor') || options.get('maxSpotColor') &&
+ (yvalues[yvallast] === this.miny || yvalues[yvallast] === this.maxy))) {
+ canvasWidth -= Math.ceil(spotRadius);
+ }
+ }
+
+
+ canvasHeight--;
+
+ if (options.get('normalRangeMin') !== undefined && !options.get('drawNormalOnTop')) {
+ this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
+ }
+
+ path = [];
+ paths = [path];
+ last = next = null;
+ yvalcount = yvalues.length;
+ for (i = 0; i < yvalcount; i++) {
+ x = xvalues[i];
+ xnext = xvalues[i + 1];
+ y = yvalues[i];
+ xpos = canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex));
+ xposnext = i < yvalcount - 1 ? canvasLeft + Math.round((xnext - this.minx) * (canvasWidth / rangex)) : canvasWidth;
+ next = xpos + ((xposnext - xpos) / 2);
+ regionMap[i] = [last || 0, next, i];
+ last = next;
+ if (y === null) {
+ if (i) {
+ if (yvalues[i - 1] !== null) {
+ path = [];
+ paths.push(path);
+ }
+ vertices.push(null);
+ }
+ } else {
+ if (y < this.miny) {
+ y = this.miny;
+ }
+ if (y > this.maxy) {
+ y = this.maxy;
+ }
+ if (!path.length) {
+ // previous value was null
+ path.push([xpos, canvasTop + canvasHeight]);
+ }
+ vertex = [xpos, canvasTop + Math.round(canvasHeight - (canvasHeight * ((y - this.miny) / rangey)))];
+ path.push(vertex);
+ vertices.push(vertex);
+ }
+ }
+
+ lineShapes = [];
+ fillShapes = [];
+ plen = paths.length;
+ for (i = 0; i < plen; i++) {
+ path = paths[i];
+ if (path.length) {
+ if (options.get('fillColor')) {
+ path.push([path[path.length - 1][0], (canvasTop + canvasHeight)]);
+ fillShapes.push(path.slice(0));
+ path.pop();
+ }
+ // if there's only a single point in this path, then we want to display it
+ // as a vertical line which means we keep path[0] as is
+ if (path.length > 2) {
+ // else we want the first value
+ path[0] = [path[0][0], path[1][1]];
+ }
+ lineShapes.push(path);
+ }
+ }
+
+ // draw the fill first, then optionally the normal range, then the line on top of that
+ plen = fillShapes.length;
+ for (i = 0; i < plen; i++) {
+ target.drawShape(fillShapes[i],
+ options.get('fillColor'), options.get('fillColor')).append();
+ }
+
+ if (options.get('normalRangeMin') !== undefined && options.get('drawNormalOnTop')) {
+ this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
+ }
+
+ plen = lineShapes.length;
+ for (i = 0; i < plen; i++) {
+ target.drawShape(lineShapes[i], options.get('lineColor'), undefined,
+ options.get('lineWidth')).append();
+ }
+
+ if (spotRadius && options.get('valueSpots')) {
+ valueSpots = options.get('valueSpots');
+ if (valueSpots.get === undefined) {
+ valueSpots = new RangeMap(valueSpots);
+ }
+ for (i = 0; i < yvalcount; i++) {
+ color = valueSpots.get(yvalues[i]);
+ if (color) {
+ target.drawCircle(canvasLeft + Math.round((xvalues[i] - this.minx) * (canvasWidth / rangex)),
+ canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[i] - this.miny) / rangey))),
+ spotRadius, undefined,
+ color).append();
+ }
+ }
+
+ }
+ if (spotRadius && options.get('spotColor')) {
+ target.drawCircle(canvasLeft + Math.round((xvalues[xvalues.length - 1] - this.minx) * (canvasWidth / rangex)),
+ canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[yvallast] - this.miny) / rangey))),
+ spotRadius, undefined,
+ options.get('spotColor')).append();
+ }
+ if (this.maxy !== this.minyorg) {
+ if (spotRadius && options.get('minSpotColor')) {
+ x = xvalues[$.inArray(this.minyorg, yvalues)];
+ target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),
+ canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.minyorg - this.miny) / rangey))),
+ spotRadius, undefined,
+ options.get('minSpotColor')).append();
+ }
+ if (spotRadius && options.get('maxSpotColor')) {
+ x = xvalues[$.inArray(this.maxyorg, yvalues)];
+ target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),
+ canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.maxyorg - this.miny) / rangey))),
+ spotRadius, undefined,
+ options.get('maxSpotColor')).append();
+ }
+ }
+
+ this.lastShapeId = target.getLastShapeId();
+ this.canvasTop = canvasTop;
+ target.render();
+ }
+ });
+
+ /**
+ * Bar charts
+ */
+ $.fn.sparkline.bar = bar = createClass($.fn.sparkline._base, barHighlightMixin, {
+ type: 'bar',
+
+ init: function (el, values, options, width, height) {
+ var barWidth = parseInt(options.get('barWidth'), 10),
+ barSpacing = parseInt(options.get('barSpacing'), 10),
+ chartRangeMin = options.get('chartRangeMin'),
+ chartRangeMax = options.get('chartRangeMax'),
+ chartRangeClip = options.get('chartRangeClip'),
+ stackMin = Infinity,
+ stackMax = -Infinity,
+ isStackString, groupMin, groupMax, stackRanges,
+ numValues, i, vlen, range, zeroAxis, xaxisOffset, min, max, clipMin, clipMax,
+ stacked, vlist, j, slen, svals, val, yoffset, yMaxCalc, canvasHeightEf;
+ bar._super.init.call(this, el, values, options, width, height);
+
+ // scan values to determine whether to stack bars
+ for (i = 0, vlen = values.length; i < vlen; i++) {
+ val = values[i];
+ isStackString = typeof(val) === 'string' && val.indexOf(':') > -1;
+ if (isStackString || $.isArray(val)) {
+ stacked = true;
+ if (isStackString) {
+ val = values[i] = normalizeValues(val.split(':'));
+ }
+ val = remove(val, null); // min/max will treat null as zero
+ groupMin = Math.min.apply(Math, val);
+ groupMax = Math.max.apply(Math, val);
+ if (groupMin < stackMin) {
+ stackMin = groupMin;
+ }
+ if (groupMax > stackMax) {
+ stackMax = groupMax;
+ }
+ }
+ }
+
+ this.stacked = stacked;
+ this.regionShapes = {};
+ this.barWidth = barWidth;
+ this.barSpacing = barSpacing;
+ this.totalBarWidth = barWidth + barSpacing;
+ this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);
+
+ this.initTarget();
+
+ if (chartRangeClip) {
+ clipMin = chartRangeMin === undefined ? -Infinity : chartRangeMin;
+ clipMax = chartRangeMax === undefined ? Infinity : chartRangeMax;
+ }
+
+ numValues = [];
+ stackRanges = stacked ? [] : numValues;
+ var stackTotals = [];
+ var stackRangesNeg = [];
+ for (i = 0, vlen = values.length; i < vlen; i++) {
+ if (stacked) {
+ vlist = values[i];
+ values[i] = svals = [];
+ stackTotals[i] = 0;
+ stackRanges[i] = stackRangesNeg[i] = 0;
+ for (j = 0, slen = vlist.length; j < slen; j++) {
+ val = svals[j] = chartRangeClip ? clipval(vlist[j], clipMin, clipMax) : vlist[j];
+ if (val !== null) {
+ if (val > 0) {
+ stackTotals[i] += val;
+ }
+ if (stackMin < 0 && stackMax > 0) {
+ if (val < 0) {
+ stackRangesNeg[i] += Math.abs(val);
+ } else {
+ stackRanges[i] += val;
+ }
+ } else {
+ stackRanges[i] += Math.abs(val - (val < 0 ? stackMax : stackMin));
+ }
+ numValues.push(val);
+ }
+ }
+ } else {
+ val = chartRangeClip ? clipval(values[i], clipMin, clipMax) : values[i];
+ val = values[i] = normalizeValue(val);
+ if (val !== null) {
+ numValues.push(val);
+ }
+ }
+ }
+ this.max = max = Math.max.apply(Math, numValues);
+ this.min = min = Math.min.apply(Math, numValues);
+ this.stackMax = stackMax = stacked ? Math.max.apply(Math, stackTotals) : max;
+ this.stackMin = stackMin = stacked ? Math.min.apply(Math, numValues) : min;
+
+ if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < min)) {
+ min = options.get('chartRangeMin');
+ }
+ if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > max)) {
+ max = options.get('chartRangeMax');
+ }
+
+ this.zeroAxis = zeroAxis = options.get('zeroAxis', true);
+ if (min <= 0 && max >= 0 && zeroAxis) {
+ xaxisOffset = 0;
+ } else if (zeroAxis == false) {
+ xaxisOffset = min;
+ } else if (min > 0) {
+ xaxisOffset = min;
+ } else {
+ xaxisOffset = max;
+ }
+ this.xaxisOffset = xaxisOffset;
+
+ range = stacked ? (Math.max.apply(Math, stackRanges) + Math.max.apply(Math, stackRangesNeg)) : max - min;
+
+ // as we plot zero/min values a single pixel line, we add a pixel to all other
+ // values - Reduce the effective canvas size to suit
+ this.canvasHeightEf = (zeroAxis && min < 0) ? this.canvasHeight - 2 : this.canvasHeight - 1;
+
+ if (min < xaxisOffset) {
+ yMaxCalc = (stacked && max >= 0) ? stackMax : max;
+ yoffset = (yMaxCalc - xaxisOffset) / range * this.canvasHeight;
+ if (yoffset !== Math.ceil(yoffset)) {
+ this.canvasHeightEf -= 2;
+ yoffset = Math.ceil(yoffset);
+ }
+ } else {
+ yoffset = this.canvasHeight;
+ }
+ this.yoffset = yoffset;
+
+ if ($.isArray(options.get('colorMap'))) {
+ this.colorMapByIndex = options.get('colorMap');
+ this.colorMapByValue = null;
+ } else {
+ this.colorMapByIndex = null;
+ this.colorMapByValue = options.get('colorMap');
+ if (this.colorMapByValue && this.colorMapByValue.get === undefined) {
+ this.colorMapByValue = new RangeMap(this.colorMapByValue);
+ }
+ }
+
+ this.range = range;
+ },
+
+ getRegion: function (el, x, y) {
+ var result = Math.floor(x / this.totalBarWidth);
+ return (result < 0 || result >= this.values.length) ? undefined : result;
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion,
+ values = ensureArray(this.values[currentRegion]),
+ result = [],
+ value, i;
+ for (i = values.length; i--;) {
+ value = values[i];
+ result.push({
+ isNull: value === null,
+ value: value,
+ color: this.calcColor(i, value, currentRegion),
+ offset: currentRegion
+ });
+ }
+ return result;
+ },
+
+ calcColor: function (stacknum, value, valuenum) {
+ var colorMapByIndex = this.colorMapByIndex,
+ colorMapByValue = this.colorMapByValue,
+ options = this.options,
+ color, newColor;
+ if (this.stacked) {
+ color = options.get('stackedBarColor');
+ } else {
+ color = (value < 0) ? options.get('negBarColor') : options.get('barColor');
+ }
+ if (value === 0 && options.get('zeroColor') !== undefined) {
+ color = options.get('zeroColor');
+ }
+ if (colorMapByValue && (newColor = colorMapByValue.get(value))) {
+ color = newColor;
+ } else if (colorMapByIndex && colorMapByIndex.length > valuenum) {
+ color = colorMapByIndex[valuenum];
+ }
+ return $.isArray(color) ? color[stacknum % color.length] : color;
+ },
+
+ /**
+ * Render bar(s) for a region
+ */
+ renderRegion: function (valuenum, highlight) {
+ var vals = this.values[valuenum],
+ options = this.options,
+ xaxisOffset = this.xaxisOffset,
+ result = [],
+ range = this.range,
+ stacked = this.stacked,
+ target = this.target,
+ x = valuenum * this.totalBarWidth,
+ canvasHeightEf = this.canvasHeightEf,
+ yoffset = this.yoffset,
+ y, height, color, isNull, yoffsetNeg, i, valcount, val, minPlotted, allMin;
+
+ vals = $.isArray(vals) ? vals : [vals];
+ valcount = vals.length;
+ val = vals[0];
+ isNull = all(null, vals);
+ allMin = all(xaxisOffset, vals, true);
+
+ if (isNull) {
+ if (options.get('nullColor')) {
+ color = highlight ? options.get('nullColor') : this.calcHighlightColor(options.get('nullColor'), options);
+ y = (yoffset > 0) ? yoffset - 1 : yoffset;
+ return target.drawRect(x, y, this.barWidth - 1, 0, color, color);
+ } else {
+ return undefined;
+ }
+ }
+ yoffsetNeg = yoffset;
+ for (i = 0; i < valcount; i++) {
+ val = vals[i];
+
+ if (stacked && val === xaxisOffset) {
+ if (!allMin || minPlotted) {
+ continue;
+ }
+ minPlotted = true;
+ }
+
+ if (range > 0) {
+ height = Math.floor(canvasHeightEf * ((Math.abs(val - xaxisOffset) / range))) + 1;
+ } else {
+ height = 1;
+ }
+ if (val < xaxisOffset || (val === xaxisOffset && yoffset === 0)) {
+ y = yoffsetNeg;
+ yoffsetNeg += height;
+ } else {
+ y = yoffset - height;
+ yoffset -= height;
+ }
+ color = this.calcColor(i, val, valuenum);
+ if (highlight) {
+ color = this.calcHighlightColor(color, options);
+ }
+ result.push(target.drawRect(x, y, this.barWidth - 1, height - 1, color, color));
+ }
+ if (result.length === 1) {
+ return result[0];
+ }
+ return result;
+ }
+ });
+
+ /**
+ * Tristate charts
+ */
+ $.fn.sparkline.tristate = tristate = createClass($.fn.sparkline._base, barHighlightMixin, {
+ type: 'tristate',
+
+ init: function (el, values, options, width, height) {
+ var barWidth = parseInt(options.get('barWidth'), 10),
+ barSpacing = parseInt(options.get('barSpacing'), 10);
+ tristate._super.init.call(this, el, values, options, width, height);
+
+ this.regionShapes = {};
+ this.barWidth = barWidth;
+ this.barSpacing = barSpacing;
+ this.totalBarWidth = barWidth + barSpacing;
+ this.values = $.map(values, Number);
+ this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);
+
+ if ($.isArray(options.get('colorMap'))) {
+ this.colorMapByIndex = options.get('colorMap');
+ this.colorMapByValue = null;
+ } else {
+ this.colorMapByIndex = null;
+ this.colorMapByValue = options.get('colorMap');
+ if (this.colorMapByValue && this.colorMapByValue.get === undefined) {
+ this.colorMapByValue = new RangeMap(this.colorMapByValue);
+ }
+ }
+ this.initTarget();
+ },
+
+ getRegion: function (el, x, y) {
+ return Math.floor(x / this.totalBarWidth);
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ isNull: this.values[currentRegion] === undefined,
+ value: this.values[currentRegion],
+ color: this.calcColor(this.values[currentRegion], currentRegion),
+ offset: currentRegion
+ };
+ },
+
+ calcColor: function (value, valuenum) {
+ var values = this.values,
+ options = this.options,
+ colorMapByIndex = this.colorMapByIndex,
+ colorMapByValue = this.colorMapByValue,
+ color, newColor;
+
+ if (colorMapByValue && (newColor = colorMapByValue.get(value))) {
+ color = newColor;
+ } else if (colorMapByIndex && colorMapByIndex.length > valuenum) {
+ color = colorMapByIndex[valuenum];
+ } else if (values[valuenum] < 0) {
+ color = options.get('negBarColor');
+ } else if (values[valuenum] > 0) {
+ color = options.get('posBarColor');
+ } else {
+ color = options.get('zeroBarColor');
+ }
+ return color;
+ },
+
+ renderRegion: function (valuenum, highlight) {
+ var values = this.values,
+ options = this.options,
+ target = this.target,
+ canvasHeight, height, halfHeight,
+ x, y, color;
+
+ canvasHeight = target.pixelHeight;
+ halfHeight = Math.round(canvasHeight / 2);
+
+ x = valuenum * this.totalBarWidth;
+ if (values[valuenum] < 0) {
+ y = halfHeight;
+ height = halfHeight - 1;
+ } else if (values[valuenum] > 0) {
+ y = 0;
+ height = halfHeight - 1;
+ } else {
+ y = halfHeight - 1;
+ height = 2;
+ }
+ color = this.calcColor(values[valuenum], valuenum);
+ if (color === null) {
+ return;
+ }
+ if (highlight) {
+ color = this.calcHighlightColor(color, options);
+ }
+ return target.drawRect(x, y, this.barWidth - 1, height - 1, color, color);
+ }
+ });
+
+ /**
+ * Discrete charts
+ */
+ $.fn.sparkline.discrete = discrete = createClass($.fn.sparkline._base, barHighlightMixin, {
+ type: 'discrete',
+
+ init: function (el, values, options, width, height) {
+ discrete._super.init.call(this, el, values, options, width, height);
+
+ this.regionShapes = {};
+ this.values = values = $.map(values, Number);
+ this.min = Math.min.apply(Math, values);
+ this.max = Math.max.apply(Math, values);
+ this.range = this.max - this.min;
+ this.width = width = options.get('width') === 'auto' ? values.length * 2 : this.width;
+ this.interval = Math.floor(width / values.length);
+ this.itemWidth = width / values.length;
+ if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.min)) {
+ this.min = options.get('chartRangeMin');
+ }
+ if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.max)) {
+ this.max = options.get('chartRangeMax');
+ }
+ this.initTarget();
+ if (this.target) {
+ this.lineHeight = options.get('lineHeight') === 'auto' ? Math.round(this.canvasHeight * 0.3) : options.get('lineHeight');
+ }
+ },
+
+ getRegion: function (el, x, y) {
+ return Math.floor(x / this.itemWidth);
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ isNull: this.values[currentRegion] === undefined,
+ value: this.values[currentRegion],
+ offset: currentRegion
+ };
+ },
+
+ renderRegion: function (valuenum, highlight) {
+ var values = this.values,
+ options = this.options,
+ min = this.min,
+ max = this.max,
+ range = this.range,
+ interval = this.interval,
+ target = this.target,
+ canvasHeight = this.canvasHeight,
+ lineHeight = this.lineHeight,
+ pheight = canvasHeight - lineHeight,
+ ytop, val, color, x;
+
+ val = clipval(values[valuenum], min, max);
+ x = valuenum * interval;
+ ytop = Math.round(pheight - pheight * ((val - min) / range));
+ color = (options.get('thresholdColor') && val < options.get('thresholdValue')) ? options.get('thresholdColor') : options.get('lineColor');
+ if (highlight) {
+ color = this.calcHighlightColor(color, options);
+ }
+ return target.drawLine(x, ytop, x, ytop + lineHeight, color);
+ }
+ });
+
+ /**
+ * Bullet charts
+ */
+ $.fn.sparkline.bullet = bullet = createClass($.fn.sparkline._base, {
+ type: 'bullet',
+
+ init: function (el, values, options, width, height) {
+ var min, max, vals;
+ bullet._super.init.call(this, el, values, options, width, height);
+
+ // values: target, performance, range1, range2, range3
+ this.values = values = normalizeValues(values);
+ // target or performance could be null
+ vals = values.slice();
+ vals[0] = vals[0] === null ? vals[2] : vals[0];
+ vals[1] = values[1] === null ? vals[2] : vals[1];
+ min = Math.min.apply(Math, values);
+ max = Math.max.apply(Math, values);
+ if (options.get('base') === undefined) {
+ min = min < 0 ? min : 0;
+ } else {
+ min = options.get('base');
+ }
+ this.min = min;
+ this.max = max;
+ this.range = max - min;
+ this.shapes = {};
+ this.valueShapes = {};
+ this.regiondata = {};
+ this.width = width = options.get('width') === 'auto' ? '4.0em' : width;
+ this.target = this.$el.simpledraw(width, height, options.get('composite'));
+ if (!values.length) {
+ this.disabled = true;
+ }
+ this.initTarget();
+ },
+
+ getRegion: function (el, x, y) {
+ var shapeid = this.target.getShapeAt(el, x, y);
+ return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ fieldkey: currentRegion.substr(0, 1),
+ value: this.values[currentRegion.substr(1)],
+ region: currentRegion
+ };
+ },
+
+ changeHighlight: function (highlight) {
+ var currentRegion = this.currentRegion,
+ shapeid = this.valueShapes[currentRegion],
+ shape;
+ delete this.shapes[shapeid];
+ switch (currentRegion.substr(0, 1)) {
+ case 'r':
+ shape = this.renderRange(currentRegion.substr(1), highlight);
+ break;
+ case 'p':
+ shape = this.renderPerformance(highlight);
+ break;
+ case 't':
+ shape = this.renderTarget(highlight);
+ break;
+ }
+ this.valueShapes[currentRegion] = shape.id;
+ this.shapes[shape.id] = currentRegion;
+ this.target.replaceWithShape(shapeid, shape);
+ },
+
+ renderRange: function (rn, highlight) {
+ var rangeval = this.values[rn],
+ rangewidth = Math.round(this.canvasWidth * ((rangeval - this.min) / this.range)),
+ color = this.options.get('rangeColors')[rn - 2];
+ if (highlight) {
+ color = this.calcHighlightColor(color, this.options);
+ }
+ return this.target.drawRect(0, 0, rangewidth - 1, this.canvasHeight - 1, color, color);
+ },
+
+ renderPerformance: function (highlight) {
+ var perfval = this.values[1],
+ perfwidth = Math.round(this.canvasWidth * ((perfval - this.min) / this.range)),
+ color = this.options.get('performanceColor');
+ if (highlight) {
+ color = this.calcHighlightColor(color, this.options);
+ }
+ return this.target.drawRect(0, Math.round(this.canvasHeight * 0.3), perfwidth - 1,
+ Math.round(this.canvasHeight * 0.4) - 1, color, color);
+ },
+
+ renderTarget: function (highlight) {
+ var targetval = this.values[0],
+ x = Math.round(this.canvasWidth * ((targetval - this.min) / this.range) - (this.options.get('targetWidth') / 2)),
+ targettop = Math.round(this.canvasHeight * 0.10),
+ targetheight = this.canvasHeight - (targettop * 2),
+ color = this.options.get('targetColor');
+ if (highlight) {
+ color = this.calcHighlightColor(color, this.options);
+ }
+ return this.target.drawRect(x, targettop, this.options.get('targetWidth') - 1, targetheight - 1, color, color);
+ },
+
+ render: function () {
+ var vlen = this.values.length,
+ target = this.target,
+ i, shape;
+ if (!bullet._super.render.call(this)) {
+ return;
+ }
+ for (i = 2; i < vlen; i++) {
+ shape = this.renderRange(i).append();
+ this.shapes[shape.id] = 'r' + i;
+ this.valueShapes['r' + i] = shape.id;
+ }
+ if (this.values[1] !== null) {
+ shape = this.renderPerformance().append();
+ this.shapes[shape.id] = 'p1';
+ this.valueShapes.p1 = shape.id;
+ }
+ if (this.values[0] !== null) {
+ shape = this.renderTarget().append();
+ this.shapes[shape.id] = 't0';
+ this.valueShapes.t0 = shape.id;
+ }
+ target.render();
+ }
+ });
+
+ /**
+ * Pie charts
+ */
+ $.fn.sparkline.pie = pie = createClass($.fn.sparkline._base, {
+ type: 'pie',
+
+ init: function (el, values, options, width, height) {
+ var total = 0, i;
+
+ pie._super.init.call(this, el, values, options, width, height);
+
+ this.shapes = {}; // map shape ids to value offsets
+ this.valueShapes = {}; // maps value offsets to shape ids
+ this.values = values = $.map(values, Number);
+
+ if (options.get('width') === 'auto') {
+ this.width = this.height;
+ }
+
+ if (values.length > 0) {
+ for (i = values.length; i--;) {
+ total += values[i];
+ }
+ }
+ this.total = total;
+ this.initTarget();
+ this.radius = Math.floor(Math.min(this.canvasWidth, this.canvasHeight) / 2);
+ },
+
+ getRegion: function (el, x, y) {
+ var shapeid = this.target.getShapeAt(el, x, y);
+ return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;
+ },
+
+ getCurrentRegionFields: function () {
+ var currentRegion = this.currentRegion;
+ return {
+ isNull: this.values[currentRegion] === undefined,
+ value: this.values[currentRegion],
+ percent: this.values[currentRegion] / this.total * 100,
+ color: this.options.get('sliceColors')[currentRegion % this.options.get('sliceColors').length],
+ offset: currentRegion
+ };
+ },
+
+ changeHighlight: function (highlight) {
+ var currentRegion = this.currentRegion,
+ newslice = this.renderSlice(currentRegion, highlight),
+ shapeid = this.valueShapes[currentRegion];
+ delete this.shapes[shapeid];
+ this.target.replaceWithShape(shapeid, newslice);
+ this.valueShapes[currentRegion] = newslice.id;
+ this.shapes[newslice.id] = currentRegion;
+ },
+
+ renderSlice: function (valuenum, highlight) {
+ var target = this.target,
+ options = this.options,
+ radius = this.radius,
+ borderWidth = options.get('borderWidth'),
+ offset = options.get('offset'),
+ circle = 2 * Math.PI,
+ values = this.values,
+ total = this.total,
+ next = offset ? (2*Math.PI)*(offset/360) : 0,
+ start, end, i, vlen, color;
+
+ vlen = values.length;
+ for (i = 0; i < vlen; i++) {
+ start = next;
+ end = next;
+ if (total > 0) { // avoid divide by zero
+ end = next + (circle * (values[i] / total));
+ }
+ if (valuenum === i) {
+ color = options.get('sliceColors')[i % options.get('sliceColors').length];
+ if (highlight) {
+ color = this.calcHighlightColor(color, options);
+ }
+
+ return target.drawPieSlice(radius, radius, radius - borderWidth, start, end, undefined, color);
+ }
+ next = end;
+ }
+ },
+
+ render: function () {
+ var target = this.target,
+ values = this.values,
+ options = this.options,
+ radius = this.radius,
+ borderWidth = options.get('borderWidth'),
+ shape, i;
+
+ if (!pie._super.render.call(this)) {
+ return;
+ }
+ if (borderWidth) {
+ target.drawCircle(radius, radius, Math.floor(radius - (borderWidth / 2)),
+ options.get('borderColor'), undefined, borderWidth).append();
+ }
+ for (i = values.length; i--;) {
+ if (values[i]) { // don't render zero values
+ shape = this.renderSlice(i).append();
+ this.valueShapes[i] = shape.id; // store just the shapeid
+ this.shapes[shape.id] = i;
+ }
+ }
+ target.render();
+ }
+ });
+
+ /**
+ * Box plots
+ */
+ $.fn.sparkline.box = box = createClass($.fn.sparkline._base, {
+ type: 'box',
+
+ init: function (el, values, options, width, height) {
+ box._super.init.call(this, el, values, options, width, height);
+ this.values = $.map(values, Number);
+ this.width = options.get('width') === 'auto' ? '4.0em' : width;
+ this.initTarget();
+ if (!this.values.length) {
+ this.disabled = 1;
+ }
+ },
+
+ /**
+ * Simulate a single region
+ */
+ getRegion: function () {
+ return 1;
+ },
+
+ getCurrentRegionFields: function () {
+ var result = [
+ { field: 'lq', value: this.quartiles[0] },
+ { field: 'med', value: this.quartiles[1] },
+ { field: 'uq', value: this.quartiles[2] }
+ ];
+ if (this.loutlier !== undefined) {
+ result.push({ field: 'lo', value: this.loutlier});
+ }
+ if (this.routlier !== undefined) {
+ result.push({ field: 'ro', value: this.routlier});
+ }
+ if (this.lwhisker !== undefined) {
+ result.push({ field: 'lw', value: this.lwhisker});
+ }
+ if (this.rwhisker !== undefined) {
+ result.push({ field: 'rw', value: this.rwhisker});
+ }
+ return result;
+ },
+
+ render: function () {
+ var target = this.target,
+ values = this.values,
+ vlen = values.length,
+ options = this.options,
+ canvasWidth = this.canvasWidth,
+ canvasHeight = this.canvasHeight,
+ minValue = options.get('chartRangeMin') === undefined ? Math.min.apply(Math, values) : options.get('chartRangeMin'),
+ maxValue = options.get('chartRangeMax') === undefined ? Math.max.apply(Math, values) : options.get('chartRangeMax'),
+ canvasLeft = 0,
+ lwhisker, loutlier, iqr, q1, q2, q3, rwhisker, routlier, i,
+ size, unitSize;
+
+ if (!box._super.render.call(this)) {
+ return;
+ }
+
+ if (options.get('raw')) {
+ if (options.get('showOutliers') && values.length > 5) {
+ loutlier = values[0];
+ lwhisker = values[1];
+ q1 = values[2];
+ q2 = values[3];
+ q3 = values[4];
+ rwhisker = values[5];
+ routlier = values[6];
+ } else {
+ lwhisker = values[0];
+ q1 = values[1];
+ q2 = values[2];
+ q3 = values[3];
+ rwhisker = values[4];
+ }
+ } else {
+ values.sort(function (a, b) { return a - b; });
+ q1 = quartile(values, 1);
+ q2 = quartile(values, 2);
+ q3 = quartile(values, 3);
+ iqr = q3 - q1;
+ if (options.get('showOutliers')) {
+ lwhisker = rwhisker = undefined;
+ for (i = 0; i < vlen; i++) {
+ if (lwhisker === undefined && values[i] > q1 - (iqr * options.get('outlierIQR'))) {
+ lwhisker = values[i];
+ }
+ if (values[i] < q3 + (iqr * options.get('outlierIQR'))) {
+ rwhisker = values[i];
+ }
+ }
+ loutlier = values[0];
+ routlier = values[vlen - 1];
+ } else {
+ lwhisker = values[0];
+ rwhisker = values[vlen - 1];
+ }
+ }
+ this.quartiles = [q1, q2, q3];
+ this.lwhisker = lwhisker;
+ this.rwhisker = rwhisker;
+ this.loutlier = loutlier;
+ this.routlier = routlier;
+
+ unitSize = canvasWidth / (maxValue - minValue + 1);
+ if (options.get('showOutliers')) {
+ canvasLeft = Math.ceil(options.get('spotRadius'));
+ canvasWidth -= 2 * Math.ceil(options.get('spotRadius'));
+ unitSize = canvasWidth / (maxValue - minValue + 1);
+ if (loutlier < lwhisker) {
+ target.drawCircle((loutlier - minValue) * unitSize + canvasLeft,
+ canvasHeight / 2,
+ options.get('spotRadius'),
+ options.get('outlierLineColor'),
+ options.get('outlierFillColor')).append();
+ }
+ if (routlier > rwhisker) {
+ target.drawCircle((routlier - minValue) * unitSize + canvasLeft,
+ canvasHeight / 2,
+ options.get('spotRadius'),
+ options.get('outlierLineColor'),
+ options.get('outlierFillColor')).append();
+ }
+ }
+
+ // box
+ target.drawRect(
+ Math.round((q1 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight * 0.1),
+ Math.round((q3 - q1) * unitSize),
+ Math.round(canvasHeight * 0.8),
+ options.get('boxLineColor'),
+ options.get('boxFillColor')).append();
+ // left whisker
+ target.drawLine(
+ Math.round((lwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 2),
+ Math.round((q1 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 2),
+ options.get('lineColor')).append();
+ target.drawLine(
+ Math.round((lwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 4),
+ Math.round((lwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight - canvasHeight / 4),
+ options.get('whiskerColor')).append();
+ // right whisker
+ target.drawLine(Math.round((rwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 2),
+ Math.round((q3 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 2),
+ options.get('lineColor')).append();
+ target.drawLine(
+ Math.round((rwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight / 4),
+ Math.round((rwhisker - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight - canvasHeight / 4),
+ options.get('whiskerColor')).append();
+ // median line
+ target.drawLine(
+ Math.round((q2 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight * 0.1),
+ Math.round((q2 - minValue) * unitSize + canvasLeft),
+ Math.round(canvasHeight * 0.9),
+ options.get('medianColor')).append();
+ if (options.get('target')) {
+ size = Math.ceil(options.get('spotRadius'));
+ target.drawLine(
+ Math.round((options.get('target') - minValue) * unitSize + canvasLeft),
+ Math.round((canvasHeight / 2) - size),
+ Math.round((options.get('target') - minValue) * unitSize + canvasLeft),
+ Math.round((canvasHeight / 2) + size),
+ options.get('targetColor')).append();
+ target.drawLine(
+ Math.round((options.get('target') - minValue) * unitSize + canvasLeft - size),
+ Math.round(canvasHeight / 2),
+ Math.round((options.get('target') - minValue) * unitSize + canvasLeft + size),
+ Math.round(canvasHeight / 2),
+ options.get('targetColor')).append();
+ }
+ target.render();
+ }
+ });
+
+ // Setup a very simple "virtual canvas" to make drawing the few shapes we need easier
+ // This is accessible as $(foo).simpledraw()
+
+ if ($.browser.msie && document.namespaces && !document.namespaces.v) {
+ document.namespaces.add('v', 'urn:schemas-microsoft-com:vml', '#default#VML');
+ }
+
+ if ($.browser.hasCanvas === undefined) {
+ $.browser.hasCanvas = document.createElement('canvas').getContext !== undefined;
+ }
+
+ VShape = createClass({
+ init: function (target, id, type, args) {
+ this.target = target;
+ this.id = id;
+ this.type = type;
+ this.args = args;
+ },
+ append: function () {
+ this.target.appendShape(this);
+ return this;
+ }
+ });
+
+ VCanvas_base = createClass({
+ _pxregex: /(\d+)(px)?\s*$/i,
+
+ init: function (width, height, target) {
+ if (!width) {
+ return;
+ }
+ this.width = width;
+ this.height = height;
+ this.target = target;
+ this.lastShapeId = null;
+ if (target[0]) {
+ target = target[0];
+ }
+ $.data(target, '_jqs_vcanvas', this);
+ },
+
+ drawLine: function (x1, y1, x2, y2, lineColor, lineWidth) {
+ return this.drawShape([[x1, y1], [x2, y2]], lineColor, lineWidth);
+ },
+
+ drawShape: function (path, lineColor, fillColor, lineWidth) {
+ return this._genShape('Shape', [path, lineColor, fillColor, lineWidth]);
+ },
+
+ drawCircle: function (x, y, radius, lineColor, fillColor, lineWidth) {
+ return this._genShape('Circle', [x, y, radius, lineColor, fillColor, lineWidth]);
+ },
+
+ drawPieSlice: function (x, y, radius, startAngle, endAngle, lineColor, fillColor) {
+ return this._genShape('PieSlice', [x, y, radius, startAngle, endAngle, lineColor, fillColor]);
+ },
+
+ drawRect: function (x, y, width, height, lineColor, fillColor) {
+ return this._genShape('Rect', [x, y, width, height, lineColor, fillColor]);
+ },
+
+ getElement: function () {
+ return this.canvas;
+ },
+
+ /**
+ * Return the most recently inserted shape id
+ */
+ getLastShapeId: function () {
+ return this.lastShapeId;
+ },
+
+ /**
+ * Clear and reset the canvas
+ */
+ reset: function () {
+ alert('reset not implemented');
+ },
+
+ _insert: function (el, target) {
+ $(target).html(el);
+ },
+
+ /**
+ * Calculate the pixel dimensions of the canvas
+ */
+ _calculatePixelDims: function (width, height, canvas) {
+ // XXX This should probably be a configurable option
+ var match;
+ match = this._pxregex.exec(height);
+ if (match) {
+ this.pixelHeight = match[1];
+ } else {
+ this.pixelHeight = $(canvas).height();
+ }
+ match = this._pxregex.exec(width);
+ if (match) {
+ this.pixelWidth = match[1];
+ } else {
+ this.pixelWidth = $(canvas).width();
+ }
+ },
+
+ /**
+ * Generate a shape object and id for later rendering
+ */
+ _genShape: function (shapetype, shapeargs) {
+ var id = shapeCount++;
+ shapeargs.unshift(id);
+ return new VShape(this, id, shapetype, shapeargs);
+ },
+
+ /**
+ * Add a shape to the end of the render queue
+ */
+ appendShape: function (shape) {
+ alert('appendShape not implemented');
+ },
+
+ /**
+ * Replace one shape with another
+ */
+ replaceWithShape: function (shapeid, shape) {
+ alert('replaceWithShape not implemented');
+ },
+
+ /**
+ * Insert one shape after another in the render queue
+ */
+ insertAfterShape: function (shapeid, shape) {
+ alert('insertAfterShape not implemented');
+ },
+
+ /**
+ * Remove a shape from the queue
+ */
+ removeShapeId: function (shapeid) {
+ alert('removeShapeId not implemented');
+ },
+
+ /**
+ * Find a shape at the specified x/y co-ordinates
+ */
+ getShapeAt: function (el, x, y) {
+ alert('getShapeAt not implemented');
+ },
+
+ /**
+ * Render all queued shapes onto the canvas
+ */
+ render: function () {
+ alert('render not implemented');
+ }
+ });
+
+ VCanvas_canvas = createClass(VCanvas_base, {
+ init: function (width, height, target, interact) {
+ VCanvas_canvas._super.init.call(this, width, height, target);
+ this.canvas = document.createElement('canvas');
+ if (target[0]) {
+ target = target[0];
+ }
+ $.data(target, '_jqs_vcanvas', this);
+ $(this.canvas).css({ display: 'inline-block', width: width, height: height, verticalAlign: 'top' });
+ this._insert(this.canvas, target);
+ this._calculatePixelDims(width, height, this.canvas);
+ this.canvas.width = this.pixelWidth;
+ this.canvas.height = this.pixelHeight;
+ this.interact = interact;
+ this.shapes = {};
+ this.shapeseq = [];
+ this.currentTargetShapeId = undefined;
+ $(this.canvas).css({width: this.pixelWidth, height: this.pixelHeight});
+ },
+
+ _getContext: function (lineColor, fillColor, lineWidth) {
+ var context = this.canvas.getContext('2d');
+ if (lineColor !== undefined) {
+ context.strokeStyle = lineColor;
+ }
+ context.lineWidth = lineWidth === undefined ? 1 : lineWidth;
+ if (fillColor !== undefined) {
+ context.fillStyle = fillColor;
+ }
+ return context;
+ },
+
+ reset: function () {
+ var context = this._getContext();
+ context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);
+ this.shapes = {};
+ this.shapeseq = [];
+ this.currentTargetShapeId = undefined;
+ },
+
+ _drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {
+ var context = this._getContext(lineColor, fillColor, lineWidth),
+ i, plen;
+ context.beginPath();
+ context.moveTo(path[0][0] + 0.5, path[0][1] + 0.5);
+ for (i = 1, plen = path.length; i < plen; i++) {
+ context.lineTo(path[i][0] + 0.5, path[i][1] + 0.5); // the 0.5 offset gives us crisp pixel-width lines
+ }
+ if (lineColor !== undefined) {
+ context.stroke();
+ }
+ if (fillColor !== undefined) {
+ context.fill();
+ }
+ if (this.targetX !== undefined && this.targetY !== undefined &&
+ context.isPointInPath(this.targetX, this.targetY)) {
+ this.currentTargetShapeId = shapeid;
+ }
+ },
+
+ _drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {
+ var context = this._getContext(lineColor, fillColor, lineWidth);
+ context.beginPath();
+ context.arc(x, y, radius, 0, 2 * Math.PI, false);
+ if (this.targetX !== undefined && this.targetY !== undefined &&
+ context.isPointInPath(this.targetX, this.targetY)) {
+ this.currentTargetShapeId = shapeid;
+ }
+ if (lineColor !== undefined) {
+ context.stroke();
+ }
+ if (fillColor !== undefined) {
+ context.fill();
+ }
+ },
+
+ _drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {
+ var context = this._getContext(lineColor, fillColor);
+ context.beginPath();
+ context.moveTo(x, y);
+ context.arc(x, y, radius, startAngle, endAngle, false);
+ context.lineTo(x, y);
+ context.closePath();
+ if (lineColor !== undefined) {
+ context.stroke();
+ }
+ if (fillColor) {
+ context.fill();
+ }
+ if (this.targetX !== undefined && this.targetY !== undefined &&
+ context.isPointInPath(this.targetX, this.targetY)) {
+ this.currentTargetShapeId = shapeid;
+ }
+ },
+
+ _drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {
+ return this._drawShape(shapeid, [[x, y], [x + width, y], [x + width, y + height], [x, y + height], [x, y]], lineColor, fillColor);
+ },
+
+ appendShape: function (shape) {
+ this.shapes[shape.id] = shape;
+ this.shapeseq.push(shape.id);
+ this.lastShapeId = shape.id;
+ return shape.id;
+ },
+
+ replaceWithShape: function (shapeid, shape) {
+ var shapeseq = this.shapeseq,
+ i;
+ this.shapes[shape.id] = shape;
+ for (i = shapeseq.length; i--;) {
+ if (shapeseq[i] == shapeid) {
+ shapeseq[i] = shape.id;
+ }
+ }
+ delete this.shapes[shapeid];
+ },
+
+ replaceWithShapes: function (shapeids, shapes) {
+ var shapeseq = this.shapeseq,
+ shapemap = {},
+ sid, i, first;
+
+ for (i = shapeids.length; i--;) {
+ shapemap[shapeids[i]] = true;
+ }
+ for (i = shapeseq.length; i--;) {
+ sid = shapeseq[i];
+ if (shapemap[sid]) {
+ shapeseq.splice(i, 1);
+ delete this.shapes[sid];
+ first = i;
+ }
+ }
+ for (i = shapes.length; i--;) {
+ shapeseq.splice(first, 0, shapes[i].id);
+ this.shapes[shapes[i].id] = shapes[i];
+ }
+
+ },
+
+ insertAfterShape: function (shapeid, shape) {
+ var shapeseq = this.shapeseq,
+ i;
+ for (i = shapeseq.length; i--;) {
+ if (shapeseq[i] === shapeid) {
+ shapeseq.splice(i + 1, 0, shape.id);
+ this.shapes[shape.id] = shape;
+ return;
+ }
+ }
+ },
+
+ removeShapeId: function (shapeid) {
+ var shapeseq = this.shapeseq,
+ i;
+ for (i = shapeseq.length; i--;) {
+ if (shapeseq[i] === shapeid) {
+ shapeseq.splice(i, 1);
+ break;
+ }
+ }
+ delete this.shapes[shapeid];
+ },
+
+ getShapeAt: function (el, x, y) {
+ this.targetX = x;
+ this.targetY = y;
+ this.render();
+ return this.currentTargetShapeId;
+ },
+
+ render: function () {
+ var shapeseq = this.shapeseq,
+ shapes = this.shapes,
+ shapeCount = shapeseq.length,
+ context = this._getContext(),
+ shapeid, shape, i;
+ context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);
+ for (i = 0; i < shapeCount; i++) {
+ shapeid = shapeseq[i];
+ shape = shapes[shapeid];
+ this['_draw' + shape.type].apply(this, shape.args);
+ }
+ if (!this.interact) {
+ // not interactive so no need to keep the shapes array
+ this.shapes = {};
+ this.shapeseq = [];
+ }
+ }
+
+ });
+
+ VCanvas_vml = createClass(VCanvas_base, {
+ init: function (width, height, target) {
+ var groupel;
+ VCanvas_vml._super.init.call(this, width, height, target);
+ if (target[0]) {
+ target = target[0];
+ }
+ $.data(target, '_jqs_vcanvas', this);
+ this.canvas = document.createElement('span');
+ $(this.canvas).css({ display: 'inline-block', position: 'relative', overflow: 'hidden', width: width, height: height, margin: '0px', padding: '0px', verticalAlign: 'top'});
+ this._insert(this.canvas, target);
+ this._calculatePixelDims(width, height, this.canvas);
+ this.canvas.width = this.pixelWidth;
+ this.canvas.height = this.pixelHeight;
+ groupel = '<v:group coordorigin="0 0" coordsize="' + this.pixelWidth + ' ' + this.pixelHeight + '"' +
+ ' style="position:absolute;top:0;left:0;width:' + this.pixelWidth + 'px;height=' + this.pixelHeight + 'px;"></v:group>';
+ this.canvas.insertAdjacentHTML('beforeEnd', groupel);
+ this.group = $(this.canvas).children()[0];
+ this.rendered = false;
+ this.prerender = '';
+ },
+
+ _drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {
+ var vpath = [],
+ initial, stroke, fill, closed, vel, plen, i;
+ for (i = 0, plen = path.length; i < plen; i++) {
+ vpath[i] = '' + (path[i][0]) + ',' + (path[i][1]);
+ }
+ initial = vpath.splice(0, 1);
+ lineWidth = lineWidth === undefined ? 1 : lineWidth;
+ stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '" ';
+ fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
+ closed = vpath[0] === vpath[vpath.length - 1] ? 'x ' : '';
+ vel = '<v:shape coordorigin="0 0" coordsize="' + this.pixelWidth + ' ' + this.pixelHeight + '" ' +
+ ' id="jqsshape' + shapeid + '" ' +
+ stroke +
+ fill +
+ ' style="position:absolute;left:0px;top:0px;height:' + this.pixelHeight + 'px;width:' + this.pixelWidth + 'px;padding:0px;margin:0px;" ' +
+ ' path="m ' + initial + ' l ' + vpath.join(', ') + ' ' + closed + 'e">' +
+ ' </v:shape>';
+ return vel;
+ },
+
+ _drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {
+ var stroke, fill, vel;
+ x -= radius;
+ y -= radius;
+ stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '" ';
+ fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
+ vel = '<v:oval ' +
+ ' id="jqsshape' + shapeid + '" ' +
+ stroke +
+ fill +
+ ' style="position:absolute;top:' + y + 'px; left:' + x + 'px; width:' + (radius * 2) + 'px; height:' + (radius * 2) + 'px"></v:oval>';
+ return vel;
+
+ },
+
+ _drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {
+ var vpath, startx, starty, endx, endy, stroke, fill, vel;
+ if (startAngle === endAngle) {
+ return; // VML seems to have problem when start angle equals end angle.
+ }
+ if ((endAngle - startAngle) === (2 * Math.PI)) {
+ startAngle = 0.0; // VML seems to have a problem when drawing a full circle that doesn't start 0
+ endAngle = (2 * Math.PI);
+ }
+
+ startx = x + Math.round(Math.cos(startAngle) * radius);
+ starty = y + Math.round(Math.sin(startAngle) * radius);
+ endx = x + Math.round(Math.cos(endAngle) * radius);
+ endy = y + Math.round(Math.sin(endAngle) * radius);
+
+ // Prevent very small slices from being mistaken as a whole pie
+ if (startx === endx && starty === endy && (endAngle - startAngle) < Math.PI) {
+ return;
+ }
+
+ vpath = [x - radius, y - radius, x + radius, y + radius, startx, starty, endx, endy];
+ stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="1px" strokeColor="' + lineColor + '" ';
+ fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
+ vel = '<v:shape coordorigin="0 0" coordsize="' + this.pixelWidth + ' ' + this.pixelHeight + '" ' +
+ ' id="jqsshape' + shapeid + '" ' +
+ stroke +
+ fill +
+ ' style="position:absolute;left:0px;top:0px;height:' + this.pixelHeight + 'px;width:' + this.pixelWidth + 'px;padding:0px;margin:0px;" ' +
+ ' path="m ' + x + ',' + y + ' wa ' + vpath.join(', ') + ' x e">' +
+ ' </v:shape>';
+ return vel;
+ },
+
+ _drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {
+ return this._drawShape(shapeid, [[x, y], [x, y + height], [x + width, y + height], [x + width, y], [x, y]], lineColor, fillColor);
+ },
+
+ reset: function () {
+ this.group.innerHTML = '';
+ },
+
+ appendShape: function (shape) {
+ var vel = this['_draw' + shape.type].apply(this, shape.args);
+ if (this.rendered) {
+ this.group.insertAdjacentHTML('beforeEnd', vel);
+ } else {
+ this.prerender += vel;
+ }
+ this.lastShapeId = shape.id;
+ return shape.id;
+ },
+
+ replaceWithShape: function (shapeid, shape) {
+ var existing = $('#jqsshape' + shapeid),
+ vel = this['_draw' + shape.type].apply(this, shape.args);
+ existing[0].outerHTML = vel;
+ },
+
+ replaceWithShapes: function (shapeids, shapes) {
+ // replace the first shapeid with all the new shapes then toast the remaining old shapes
+ var existing = $('#jqsshape' + shapeids[0]),
+ replace = '',
+ slen = shapes.length,
+ i;
+ for (i = 0; i < slen; i++) {
+ replace += this['_draw' + shapes[i].type].apply(this, shapes[i].args);
+ }
+ existing[0].outerHTML = replace;
+ for (i = 1; i < shapeids.length; i++) {
+ $('#jqsshape' + shapeids[i]).remove();
+ }
+ },
+
+ insertAfterShape: function (shapeid, shape) {
+ var existing = $('#jqsshape' + shapeid),
+ vel = this['_draw' + shape.type].apply(this, shape.args);
+ existing[0].insertAdjacentHTML('afterEnd', vel);
+ },
+
+ removeShapeId: function (shapeid) {
+ var existing = $('#jqsshape' + shapeid);
+ this.group.removeChild(existing[0]);
+ },
+
+ getShapeAt: function (el, x, y) {
+ var shapeid = el.id.substr(8);
+ return shapeid;
+ },
+
+ render: function () {
+ if (!this.rendered) {
+ // batch the intial render into a single repaint
+ this.group.innerHTML = this.prerender;
+ this.rendered = true;
+ }
+ }
+ });
+
+})); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/jquery.tagcanvas.js b/SemanticResultFormats/resources/jquery/jquery.tagcanvas.js
new file mode 100644
index 00000000..4a16a907
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/jquery.tagcanvas.js
@@ -0,0 +1,1406 @@
+/**
+ * Copyright (C) 2010-2013 Graham Breach
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * jQuery.tagcanvas 2.1.2
+ * For more information, please contact <graham@goat1000.com>
+ */
+(function($){
+"use strict";
+var i, j, abs = Math.abs, sin = Math.sin, cos = Math.cos,
+ max = Math.max, min = Math.min, ceil = Math.ceil,
+ hexlookup3 = {}, hexlookup2 = {}, hexlookup1 = {
+ 0:"0,", 1:"17,", 2:"34,", 3:"51,", 4:"68,", 5:"85,",
+ 6:"102,", 7:"119,", 8:"136,", 9:"153,", a:"170,", A:"170,",
+ b:"187,", B:"187,", c:"204,", C:"204,", d:"221,", D:"221,",
+ e:"238,", E:"238,", f:"255,", F:"255,"
+}, Oproto, Tproto, TCproto, doc = document, ocanvas, handlers = {};
+for(i = 0; i < 256; ++i) {
+ j = i.toString(16);
+ if(i < 16)
+ j = '0' + j;
+ hexlookup2[j] = hexlookup2[j.toUpperCase()] = i.toString() + ',';
+}
+function Defined(d) {
+ return typeof(d) != 'undefined';
+}
+function Clamp(v, mn, mx) {
+ return isNaN(v) ? mx : min(mx, max(mn, v));
+}
+function Nop() {
+ return false;
+}
+function SortList(l, f) {
+ var nl = [], tl = l.length, i;
+ for(i = 0; i < tl; ++i)
+ nl.push(l[i]);
+ nl.sort(f);
+ return nl;
+}
+function Shuffle(a) {
+ var i = a.length-1, t, p;
+ while(i) {
+ p = ~~(Math.random()*i);
+ t = a[i];
+ a[i] = a[p];
+ a[p] = t;
+ --i;
+ }
+}
+function Matrix(a) {
+ this[1] = {1: a[0], 2: a[1], 3: a[2], 4: a[3]};
+ this[2] = {1: a[4], 2: a[5], 3: a[6], 4: a[7]};
+ this[3] = {1: a[8], 2: a[9], 3: a[10], 4: a[11]};
+ this[4] = {1: a[12], 2: a[13], 3: a[14], 4: a[15]};
+}
+Matrix.Identity = function() {
+ return new Matrix([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]);
+}
+Matrix.prototype.mul = function(m) {
+ var a = [], i, j;
+ for(i = 1; i <= 4; ++i)
+ for(j = 1; j <= 4; ++j)
+ a.push(this[i][1] * m[1][j] +
+ this[i][2] * m[2][j] +
+ this[i][3] * m[3][j] +
+ this[i][4] * m[4][j]);
+ return new Matrix(a);
+}
+Matrix.prototype.xform = function(p) {
+ var a = {}, x = p.x, y = p.y, z = p.z, w = Defined(p.w) ? p.w : 1;
+ a.x = x * this[1][1] + y * this[2][1] + z * this[3][1] + w * this[4][1];
+ a.y = x * this[1][2] + y * this[2][2] + z * this[3][2] + w * this[4][2];
+ a.z = x * this[1][3] + y * this[2][3] + z * this[3][3] + w * this[4][3];
+ a.w = x * this[1][4] + y * this[2][4] + z * this[3][4] + w * this[4][4];
+ return a;
+}
+function PointsOnSphere(n,xr,yr,zr) {
+ var i, y, r, phi, pts = [], inc = Math.PI * (3-Math.sqrt(5)), off = 2/n;
+ for(i = 0; i < n; ++i) {
+ y = i * off - 1 + (off / 2);
+ r = Math.sqrt(1 - y*y);
+ phi = i * inc;
+ pts.push([cos(phi) * r * xr, y * yr, sin(phi) * r * zr]);
+ }
+ return pts;
+}
+function Cylinder(n,o,xr,yr,zr) {
+ var phi, pts = [], inc = Math.PI * (3-Math.sqrt(5)), off = 2/n, i, j, k, l;
+ for(i = 0; i < n; ++i) {
+ j = i * off - 1 + (off / 2);
+ phi = i * inc;
+ k = cos(phi);
+ l = sin(phi);
+ pts.push(o ? [j * xr, k * yr, l * zr] : [k * xr, j * yr, l * zr]);
+ }
+ return pts;
+}
+function Ring(o, n, xr, yr, zr, j) {
+ var phi, pts = [], inc = Math.PI * 2 / n, i, k, l;
+ for(i = 0; i < n; ++i) {
+ phi = i * inc;
+ k = cos(phi);
+ l = sin(phi);
+ pts.push(o ? [j * xr, k * yr, l * zr] : [k * xr, j * yr, l * zr]);
+ }
+ return pts;
+}
+function PointsOnCylinderV(n,xr,yr,zr) { return Cylinder(n, 0, xr, yr, zr) }
+function PointsOnCylinderH(n,xr,yr,zr) { return Cylinder(n, 1, xr, yr, zr) }
+function PointsOnRingV(n, xr, yr, zr, offset) {
+ offset = isNaN(offset) ? 0 : offset * 1;
+ return Ring(0, n, xr, yr, zr, offset);
+}
+function PointsOnRingH(n, xr, yr, zr, offset) {
+ offset = isNaN(offset) ? 0 : offset * 1;
+ return Ring(1, n, xr, yr, zr, offset);
+}
+function SetAlpha(c,a) {
+ var d = c, p1, p2, ae = (a*1).toPrecision(3) + ')';
+ if(c[0] === '#') {
+ if(!hexlookup3[c])
+ if(c.length === 4)
+ hexlookup3[c] = 'rgba(' + hexlookup1[c[1]] + hexlookup1[c[2]] + hexlookup1[c[3]];
+ else
+ hexlookup3[c] = 'rgba(' + hexlookup2[c.substr(1,2)] + hexlookup2[c.substr(3,2)] + hexlookup2[c.substr(5,2)];
+ d = hexlookup3[c] + ae;
+ } else if(c.substr(0,4) === 'rgb(' || c.substr(0,4) === 'hsl(') {
+ d = (c.replace('(','a(').replace(')', ',' + ae));
+ } else if(c.substr(0,5) === 'rgba(' || c.substr(0,5) === 'hsla(') {
+ p1 = c.lastIndexOf(',') + 1, p2 = c.indexOf(')');
+ a *= parseFloat(c.substring(p1,p2));
+ d = c.substr(0,p1) + a.toPrecision(3) + ')';
+ }
+ return d;
+}
+function NewCanvas(w,h) {
+ // if using excanvas, give up now
+ if(window.G_vmlCanvasManager)
+ return null;
+ var c = doc.createElement('canvas');
+ c.width = w;
+ c.height = h;
+ return c;
+}
+// I think all browsers pass this test now...
+function ShadowAlphaBroken() {
+ var cv = NewCanvas(3,3), c, i;
+ if(!cv)
+ return false;
+ c = cv.getContext('2d');
+ c.strokeStyle = '#000';
+ c.shadowColor = '#fff';
+ c.shadowBlur = 3;
+ c.globalAlpha = 0;
+ c.strokeRect(2,2,2,2);
+ c.globalAlpha = 1;
+ i = c.getImageData(2,2,1,1);
+ cv = null;
+ return (i.data[0] > 0);
+}
+function FindGradientColour(t,p) {
+ var l = 1024, g = t.weightGradient, cv, c, i, gd, d;
+ if(t.gCanvas) {
+ c = t.gCanvas.getContext('2d');
+ } else {
+ t.gCanvas = cv = NewCanvas(l,1);
+ if(!cv)
+ return null;
+ c = cv.getContext('2d');
+ gd = c.createLinearGradient(0,0,l,0);
+ for(i in g)
+ gd.addColorStop(1-i, g[i]);
+ c.fillStyle = gd;
+ c.fillRect(0,0,l,1);
+ }
+ d = c.getImageData(~~((l-1)*p),0,1,1).data;
+ return 'rgba(' + d[0] + ',' + d[1] + ',' + d[2] + ',' + (d[3]/255) + ')';
+}
+function TextSet(c,f,l,s,sc,sb,so,wm,wl) {
+ var xo = (sb || 0) + (so && so[0] < 0 ? abs(so[0]) : 0),
+ yo = (sb || 0) + (so && so[1] < 0 ? abs(so[1]) : 0), i, xc;
+ c.font = f;
+ c.textBaseline = 'top';
+ c.fillStyle = l;
+ sc && (c.shadowColor = sc);
+ sb && (c.shadowBlur = sb);
+ so && (c.shadowOffsetX = so[0], c.shadowOffsetY = so[1]);
+ for(i = 0; i < s.length; ++i) {
+ xc = wl ? (wm - wl[i]) / 2 : 0;
+ c.fillText(s[i], xo + xc, yo);
+ yo += parseInt(f);
+ }
+}
+function TextToCanvas(s,f,ht,w,h,l,sc,sb,so,padx,pady,wmax,wlist) {
+ var cw = w + abs(so[0]) + sb + sb, ch = h + abs(so[1]) + sb + sb, cv, c;
+ cv = NewCanvas(cw+padx,ch+pady);
+ if(!cv)
+ return null;
+ c = cv.getContext('2d');
+ TextSet(c,f,l,s,sc,sb,so,wmax,wlist);
+ return cv;
+}
+function AddShadowToImage(i,sc,sb,so) {
+ var sw = abs(so[0]), sh = abs(so[1]),
+ cw = i.width + (sw > sb ? sw + sb : sb * 2),
+ ch = i.height + (sh > sb ? sh + sb : sb * 2),
+ xo = (sb || 0) + (so[0] < 0 ? sw : 0),
+ yo = (sb || 0) + (so[1] < 0 ? sh : 0), cv, c;
+ cv = NewCanvas(cw, ch);
+ if(!cv)
+ return null;
+ c = cv.getContext('2d');
+ sc && (c.shadowColor = sc);
+ sb && (c.shadowBlur = sb);
+ so && (c.shadowOffsetX = so[0], c.shadowOffsetY = so[1]);
+ c.drawImage(i, xo, yo, i.width, i.height);
+ return cv;
+}
+function FindTextBoundingBox(s,f,ht) {
+ var w = parseInt(s.toString().length * ht), h = parseInt(ht * 2 * s.length),
+ cv = NewCanvas(w,h), c, idata, w1, h1, x, y, i, ex;
+ if(!cv)
+ return null;
+ c = cv.getContext('2d');
+ c.fillStyle = '#000';
+ c.fillRect(0,0,w,h);
+ TextSet(c,ht + 'px ' + f,'#fff',s,0,0,[])
+
+ idata = c.getImageData(0,0,w,h);
+ w1 = idata.width; h1 = idata.height;
+ ex = {
+ min: { x: w1, y: h1 },
+ max: { x: -1, y: -1 }
+ };
+ for(y = 0; y < h1; ++y) {
+ for(x = 0; x < w1; ++x) {
+ i = (y * w1 + x) * 4;
+ if(idata.data[i+1] > 0) {
+ if(x < ex.min.x) ex.min.x = x;
+ if(x > ex.max.x) ex.max.x = x;
+ if(y < ex.min.y) ex.min.y = y;
+ if(y > ex.max.y) ex.max.y = y;
+ }
+ }
+ }
+ // device pixels might not be css pixels
+ if(w1 != w) {
+ ex.min.x *= (w / w1);
+ ex.max.x *= (w / w1);
+ }
+ if(h1 != h) {
+ ex.min.y *= (w / h1);
+ ex.max.y *= (w / h1);
+ }
+
+ cv = null;
+ return ex;
+}
+function FixFont(f) {
+ return "'" + f.replace(/(\'|\")/g,'').replace(/\s*,\s*/g, "', '") + "'";
+}
+function AddHandler(h,f,e) {
+ e = e || doc;
+ if(e.addEventListener)
+ e.addEventListener(h,f,false);
+ else
+ e.attachEvent('on' + h, f);
+}
+function AddImage(i, o, t, tc) {
+ var s = tc.imageScale, ic;
+ // image not loaded, wait for image onload
+ if(!o.complete)
+ return AddHandler('load',function() { AddImage(i,o,t,tc); }, o);
+ if(!i.complete)
+ return AddHandler('load',function() { AddImage(i,o,t,tc); }, i);
+
+ // Yes, this does look like nonsense, but it makes sure that both the
+ // width and height are actually set and not just calculated. This is
+ // required to keep proportional sizes when the images are hidden, so
+ // the images can be used again for another cloud.
+ o.width = o.width;
+ o.height = o.height;
+
+ if(s) {
+ i.width = o.width * s;
+ i.height = o.height * s;
+ }
+ t.w = i.width;
+ t.h = i.height;
+ if(tc.txtOpt && tc.shadow) {
+ ic = AddShadowToImage(i, tc.shadow, tc.shadowBlur, tc.shadowOffset);
+ if(ic) {
+ t.image = ic;
+ t.w = ic.width;
+ t.h = ic.height;
+ }
+ }
+}
+function GetProperty(e,p) {
+ var dv = doc.defaultView, pc = p.replace(/\-([a-z])/g,function(a){return a.charAt(1).toUpperCase()});
+ return (dv && dv.getComputedStyle && dv.getComputedStyle(e,null).getPropertyValue(p)) ||
+ (e.currentStyle && e.currentStyle[pc]);
+}
+function FindWeight(t,a) {
+ var w = 1, p;
+ if(t.weightFrom) {
+ w = 1 * (a.getAttribute(t.weightFrom) || t.textHeight);
+ } else if(p = GetProperty(a,'font-size')) {
+ w = (p.indexOf('px') > -1 && p.replace('px','') * 1) ||
+ (p.indexOf('pt') > -1 && p.replace('pt','') * 1.25) ||
+ p * 3.3;
+ } else {
+ t.weight = false;
+ }
+ return w;
+}
+function EventToCanvasId(e) {
+ return e.target && Defined(e.target.id) ? e.target.id :
+ e.srcElement.parentNode.id;
+}
+function EventXY(e, c) {
+ var xy, p, xmul = parseInt(GetProperty(c, 'width')) / c.width,
+ ymul = parseInt(GetProperty(c, 'height')) / c.height;
+ if(Defined(e.offsetX)) {
+ xy = {x: e.offsetX, y: e.offsetY};
+ } else {
+ p = AbsPos(c.id);
+ if(Defined(e.changedTouches))
+ e = e.changedTouches[0];
+ if(e.pageX)
+ xy = {x: e.pageX - p.x, y: e.pageY - p.y};
+ }
+ if(xy && xmul && ymul) {
+ xy.x /= xmul;
+ xy.y /= ymul;
+ }
+ return xy;
+}
+function MouseOut(e) {
+ var cv = e.target || e.fromElement.parentNode, tc = TagCanvas.tc[cv.id];
+ if(tc) {
+ tc.mx = tc.my = -1;
+ tc.UnFreeze();
+ tc.EndDrag();
+ }
+}
+function MouseMove(e) {
+ var i, t = TagCanvas, tc, p, tg = EventToCanvasId(e);
+ for(i in t.tc) {
+ tc = t.tc[i];
+ if(tc.tttimer) {
+ clearTimeout(tc.tttimer);
+ tc.tttimer = null;
+ }
+ }
+ if(tg && t.tc[tg]) {
+ tc = t.tc[tg];
+ if(p = EventXY(e, tc.canvas)) {
+ tc.mx = p.x;
+ tc.my = p.y;
+ tc.Drag(e, p);
+ }
+ tc.drawn = 0;
+ }
+}
+function MouseDown(e) {
+ var t = TagCanvas, cb = doc.addEventListener ? 0 : 1,
+ tg = EventToCanvasId(e);
+ if(tg && e.button == cb && t.tc[tg]) {
+ t.tc[tg].BeginDrag(e);
+ }
+}
+function MouseUp(e) {
+ var t = TagCanvas, cb = doc.addEventListener ? 0 : 1,
+ tg = EventToCanvasId(e), tc;
+ if(tg && e.button == cb && t.tc[tg]) {
+ tc = t.tc[tg];
+ MouseMove(e);
+ if(!tc.EndDrag() && !tc.touched)
+ tc.Clicked(e);
+ }
+}
+function TouchDown(e) {
+ var t = TagCanvas, tg = EventToCanvasId(e);
+ if(tg && e.changedTouches && t.tc[tg]) {
+ t.tc[tg].touched = 1;
+ t.tc[tg].BeginDrag(e);
+ }
+}
+function TouchUp(e) {
+ var t = TagCanvas, tg = EventToCanvasId(e);
+ if(tg && e.changedTouches && t.tc[tg]) {
+ TouchMove(e);
+ if(!t.tc[tg].EndDrag()){
+ t.tc[tg].Draw();
+ t.tc[tg].Clicked(e);
+ }
+ }
+}
+function TouchMove(e) {
+ var i, t = TagCanvas, tc, p, tg = EventToCanvasId(e);
+ for(i in t.tc) {
+ tc = t.tc[i];
+ if(tc.tttimer) {
+ clearTimeout(tc.tttimer);
+ tc.tttimer = null;
+ }
+ }
+ if(tg && t.tc[tg] && e.changedTouches) {
+ tc = t.tc[tg];
+ if(p = EventXY(e, tc.canvas)) {
+ tc.mx = p.x;
+ tc.my = p.y;
+ tc.Drag(e, p);
+ }
+ tc.drawn = 0;
+ }
+}
+function MouseWheel(e) {
+ var t = TagCanvas, tg = EventToCanvasId(e);
+ if(tg && t.tc[tg]) {
+ e.cancelBubble = true;
+ e.returnValue = false;
+ e.preventDefault && e.preventDefault();
+ t.tc[tg].Wheel((e.wheelDelta || e.detail) > 0);
+ }
+}
+function DrawCanvas(t) {
+ var tc = TagCanvas.tc, i, interval;
+ t = t || new Date().valueOf();
+ for(i in tc) {
+ interval = tc[i].interval;
+ tc[i].Draw(t);
+ }
+ TagCanvas.NextFrame(interval);
+}
+function AbsPos(id) {
+ var e = doc.getElementById(id), r = e.getBoundingClientRect(),
+ dd = doc.documentElement, b = doc.body, w = window,
+ xs = w.pageXOffset || dd.scrollLeft,
+ ys = w.pageYOffset || dd.scrollTop,
+ xo = dd.clientLeft || b.clientLeft,
+ yo = dd.clientTop || b.clientTop;
+ return { x: r.left + xs - xo, y: r.top + ys - yo };
+}
+function Project(tc,p1,sx,sy) {
+ var m = tc.radius * tc.z1 / (tc.z1 + tc.z2 + p1.z);
+ return {
+ x: p1.x * m * sx,
+ y: p1.y * m * sy,
+ z: p1.z,
+ w: (tc.z1 - p1.z) / tc.z2
+ };
+}
+/**
+ * @constructor
+ * for recursively splitting tag contents on <br> tags
+ */
+function TextSplitter(e) {
+ this.e = e;
+ this.br = 0;
+ this.line = [];
+ this.text = [];
+ this.original = e.innerText || e.textContent;
+};
+TextSplitter.prototype.Lines = function(e) {
+ var r = e ? 1 : 0, cn, cl, i;
+ e = e || this.e;
+ cn = e.childNodes;
+ cl = cn.length;
+
+ for(i = 0; i < cl; ++i) {
+ if(cn[i].nodeName == 'BR') {
+ this.text.push(this.line.join(' '));
+ this.br = 1;
+ } else if(cn[i].nodeType == 3) {
+ if(this.br) {
+ this.line = [cn[i].nodeValue];
+ this.br = 0;
+ } else {
+ this.line.push(cn[i].nodeValue);
+ }
+ } else {
+ this.Lines(cn[i]);
+ }
+ }
+ r || this.br || this.text.push(this.line.join(' '));
+ return this.text;
+}
+TextSplitter.prototype.SplitWidth = function(w, c, f, h) {
+ var i, j, words, text = [];
+ c.font = h + 'px ' + f;
+ for(i = 0; i < this.text.length; ++i) {
+ words = this.text[i].split(/\s+/);
+ this.line = [words[0]];
+ for(j = 1; j < words.length; ++j) {
+ if(c.measureText(this.line.join(' ') + ' ' + words[j]).width > w) {
+ text.push(this.line.join(' '));
+ this.line = [words[j]];
+ } else {
+ this.line.push(words[j]);
+ }
+ }
+ text.push(this.line.join(' '));
+ }
+ return this.text = text;
+}
+/**
+ * @constructor
+ */
+function Outline(tc) {
+ this.ts = new Date().valueOf();
+ this.tc = tc;
+ this.x = this.y = this.w = this.h = this.sc = 1;
+ this.z = 0;
+ this.Draw = tc.pulsateTo < 1 && tc.outlineMethod != 'colour' ? this.DrawPulsate : this.DrawSimple;
+ this.SetMethod(tc.outlineMethod);
+}
+Oproto = Outline.prototype;
+Oproto.SetMethod = function(om) {
+ var methods = {
+ block: ['PreDraw','DrawBlock'],
+ colour: ['PreDraw','DrawColour'],
+ outline: ['PostDraw','DrawOutline'],
+ classic: ['LastDraw','DrawOutline'],
+ none: ['LastDraw']
+ }, funcs = methods[om] || methods.outline;
+ if(om == 'none') {
+ this.Draw = function() { return 1; }
+ } else {
+ this.drawFunc = this[funcs[1]];
+ }
+ this[funcs[0]] = this.Draw;
+};
+Oproto.Update = function(x,y,w,h,sc,z,xo,yo) {
+ var o = this.tc.outlineOffset, o2 = 2 * o;
+ this.x = sc * x + xo - o;
+ this.y = sc * y + yo - o;
+ this.w = sc * w + o2;
+ this.h = sc * h + o2;
+ this.sc = sc; // used to determine frontmost
+ this.z = z;
+};
+Oproto.DrawOutline = function(c,x,y,w,h,colour) {
+ c.strokeStyle = colour;
+ c.strokeRect(x,y,w,h);
+};
+Oproto.DrawColour = function(c,x,y,w,h,colour,tag,x1,y1) {
+ return this[tag.image ? 'DrawColourImage' : 'DrawColourText'](c,x,y,w,h,colour,tag,x1,y1);
+};
+Oproto.DrawColourText = function(c,x,y,w,h,colour,tag,x1,y1) {
+ var normal = tag.colour;
+ tag.colour = colour;
+ tag.alpha = 1;
+ tag.Draw(c,x1,y1);
+ tag.colour = normal;
+ return 1;
+};
+Oproto.DrawColourImage = function(c,x,y,w,h,colour,tag,x1,y1) {
+ var ccanvas = c.canvas, fx = ~~max(x,0), fy = ~~max(y,0),
+ fw = min(ccanvas.width - fx, w) + .5|0, fh = min(ccanvas.height - fy,h) + .5|0, cc;
+ if(ocanvas)
+ ocanvas.width = fw, ocanvas.height = fh;
+ else
+ ocanvas = NewCanvas(fw, fh);
+ if(!ocanvas)
+ return this.SetMethod('outline'); // if using IE and images, give up!
+ cc = ocanvas.getContext('2d');
+
+ cc.drawImage(ccanvas,fx,fy,fw,fh,0,0,fw,fh);
+ c.clearRect(fx,fy,fw,fh);
+ tag.alpha = 1;
+ tag.Draw(c,x1,y1);
+ c.setTransform(1,0,0,1,0,0);
+ c.save();
+ c.beginPath();
+ c.rect(fx,fy,fw,fh);
+ c.clip();
+ c.globalCompositeOperation = 'source-in';
+ c.fillStyle = colour;
+ c.fillRect(fx,fy,fw,fh);
+ c.restore();
+ c.globalCompositeOperation = 'destination-over';
+ c.drawImage(ocanvas,0,0,fw,fh,fx,fy,fw,fh);
+ c.globalCompositeOperation = 'source-over';
+ return 1;
+};
+Oproto.DrawBlock = function(c,x,y,w,h,colour) {
+ c.fillStyle = colour;
+ c.fillRect(x,y,w,h);
+};
+Oproto.DrawSimple = function(c, tag, x1, y1) {
+ var t = this.tc;
+ c.setTransform(1,0,0,1,0,0);
+ c.strokeStyle = t.outlineColour;
+ c.lineWidth = t.outlineThickness;
+ c.shadowBlur = c.shadowOffsetX = c.shadowOffsetY = 0;
+ c.globalAlpha = 1;
+ return this.drawFunc(c,this.x,this.y,this.w,this.h,t.outlineColour,tag,x1,y1);
+};
+Oproto.DrawPulsate = function(c, tag, x1, y1) {
+ var diff = new Date().valueOf() - this.ts, t = this.tc;
+ c.setTransform(1,0,0,1,0,0);
+ c.strokeStyle = t.outlineColour;
+ c.lineWidth = t.outlineThickness;
+ c.shadowBlur = c.shadowOffsetX = c.shadowOffsetY = 0;
+ c.globalAlpha = t.pulsateTo + ((1 - t.pulsateTo) *
+ (0.5 + (cos(2 * Math.PI * diff / (1000 * t.pulsateTime)) / 2)));
+ return this.drawFunc(c,this.x,this.y,this.w,this.h,t.outlineColour,tag,x1,y1);
+};
+Oproto.Active = function(c,x,y) {
+ return (x >= this.x && y >= this.y &&
+ x <= this.x + this.w && y <= this.y + this.h);
+};
+Oproto.PreDraw = Oproto.PostDraw = Oproto.LastDraw = Nop;
+/**
+ * @constructor
+ */
+function Tag(tc,text,a,v,w,h,col,font,original) {
+ var c = tc.ctxt;
+ this.tc = tc;
+ this.image = text.src ? text : null;
+ this.text = text.src ? [] : text;
+ this.text_original = original;
+ this.line_widths = [];
+ this.title = a.title || null;
+ this.a = a;
+ this.position = { x: v[0], y: v[1], z: v[2] };
+ this.x = this.y = this.z = 0;
+ this.w = w;
+ this.h = h;
+ this.colour = col || tc.textColour;
+ this.textFont = font || tc.textFont;
+ this.weight = this.sc = this.alpha = 1;
+ this.weighted = !tc.weight;
+ this.outline = new Outline(tc);
+ if(!this.image) {
+ this.textHeight = tc.textHeight;
+ this.extents = FindTextBoundingBox(this.text, this.textFont, this.textHeight);
+ this.Measure(c,tc);
+ }
+ this.SetShadowColour = tc.shadowAlpha ? this.SetShadowColourAlpha : this.SetShadowColourFixed;
+ this.SetDraw(tc);
+}
+Tproto = Tag.prototype;
+Tproto.EqualTo = function(e) {
+ var i = e.getElementsByTagName('img');
+ if(this.a.href != e.href)
+ return 0;
+ if(i.length)
+ return this.image.src == i[0].src;
+ return (e.innerText || e.textContent) == this.text_original;
+};
+Tproto.SetDraw = function(t) {
+ this.Draw = this.image ? (t.ie > 7 ? this.DrawImageIE : this.DrawImage) : this.DrawText;
+ t.noSelect && (this.CheckActive = Nop);
+};
+Tproto.MeasureText = function(c) {
+ var i, l = this.text.length, w = 0, wl;
+ for(i = 0; i < l; ++i) {
+ this.line_widths[i] = wl = c.measureText(this.text[i]).width;
+ w = max(w, wl);
+ }
+ return w;
+};
+Tproto.Measure = function(c,t) {
+ this.h = this.extents ? this.extents.max.y + this.extents.min.y : this.textHeight;
+ c.font = this.font = this.textHeight + 'px ' + this.textFont;
+ this.w = this.MeasureText(c);
+ if(t.txtOpt) {
+ var s = t.txtScale, th = s * this.textHeight, f = th + 'px ' + this.textFont,
+ soff = [s*t.shadowOffset[0],s*t.shadowOffset[1]], cw;
+ c.font = f;
+ cw = this.MeasureText(c);
+ this.image = TextToCanvas(this.text, f, th, cw, s * this.h, this.colour,
+ t.shadow, s * t.shadowBlur, soff, s, s, cw, this.line_widths);
+ if(this.image) {
+ this.w = this.image.width / s;
+ this.h = this.image.height / s;
+ }
+ this.SetDraw(t);
+ t.txtOpt = !!this.image;
+ }
+};
+Tproto.SetFont = function(f, c) {
+ this.textFont = f;
+ this.colour = c;
+ this.extents = FindTextBoundingBox(this.text, this.textFont, this.textHeight);
+ this.Measure(this.tc.ctxt, this.tc);
+};
+Tproto.SetWeight = function(w) {
+ if(!this.text.length)
+ return;
+ this.weight = w;
+ this.Weight(this.tc.ctxt, this.tc);
+ this.Measure(this.tc.ctxt, this.tc);
+};
+Tproto.Weight = function(c,t) {
+ var w = this.weight, m = t.weightMode;
+ this.weighted = true;
+ if(m == 'colour' || m == 'both')
+ this.colour = FindGradientColour(t, (w - t.min_weight) / (t.max_weight-t.min_weight));
+ if(m == 'size' || m == 'both') {
+ if(t.weightSizeMin > 0 && t.weightSizeMax > t.weightSizeMin) {
+ this.textHeight = t.weightSize *
+ (t.weightSizeMin + (t.weightSizeMax - t.weightSizeMin) *
+ (w - t.min_weight) / (t.max_weight - t.min_weight));
+ } else {
+ this.textHeight = w * t.weightSize;
+ }
+ }
+ this.extents = FindTextBoundingBox(this.text, this.textFont, this.textHeight);
+};
+Tproto.SetShadowColourFixed = function(c,s,a) {
+ c.shadowColor = s;
+};
+Tproto.SetShadowColourAlpha = function(c,s,a) {
+ c.shadowColor = SetAlpha(s, a);
+};
+Tproto.DrawText = function(c,xoff,yoff) {
+ var t = this.tc, x = this.x, y = this.y, s = this.sc, i, xl;
+ c.globalAlpha = this.alpha;
+ c.fillStyle = this.colour;
+ t.shadow && this.SetShadowColour(c,t.shadow,this.alpha);
+ c.font = this.font;
+ x += xoff / s;
+ y += (yoff / s) - (this.h / 2);
+ for(i = 0; i < this.text.length; ++i) {
+ xl = x - (this.line_widths[i] / 2);
+ c.setTransform(s, 0, 0, s, s * xl, s * y);
+ c.fillText(this.text[i], 0, 0);
+ y += this.textHeight;
+ }
+};
+Tproto.DrawImage = function(c,xoff,yoff) {
+ var x = this.x, y = this.y, s = this.sc,
+ i = this.image, w = this.w, h = this.h, a = this.alpha,
+ shadow = this.shadow;
+ c.globalAlpha = a;
+ shadow && this.SetShadowColour(c,shadow,a);
+ x += (xoff / s) - (w / 2);
+ y += (yoff / s) - (h / 2);
+ c.setTransform(s, 0, 0, s, s * x, s * y);
+ c.drawImage(i, 0, 0, w, h);
+};
+Tproto.DrawImageIE = function(c,xoff,yoff) {
+ var i = this.image, s = this.sc,
+ w = i.width = this.w*s, h = i.height = this.h * s,
+ x = (this.x*s) + xoff - (w/2), y = (this.y*s) + yoff - (h/2);
+ c.setTransform(1,0,0,1,0,0);
+ c.globalAlpha = this.alpha;
+ c.drawImage(i, x, y);
+};
+Tproto.Calc = function(m) {
+ var pp, t = this.tc, mnb = t.minBrightness,
+ mxb = t.maxBrightness, r = t.max_radius;
+ pp = m.xform(this.position);
+ pp = Project(t, pp, t.stretchX, t.stretchY);
+ this.x = pp.x;
+ this.y = pp.y;
+ this.z = pp.z;
+ this.sc = pp.w;
+ this.alpha = Clamp(mnb + (mxb - mnb) * (r - this.z) / (2 * r), 0, 1);
+};
+Tproto.CheckActive = function(c,xoff,yoff) {
+ var t = this.tc, o = this.outline,
+ w = this.w, h = this.h,
+ x = this.x - w/2, y = this.y - h/2;
+ o.Update(x, y, w, h, this.sc, this.z, xoff, yoff);
+ return o.Active(c, t.mx, t.my) ? o : null;
+};
+Tproto.Clicked = function(e) {
+ var a = this.a, t = a.target, h = a.href, evt;
+ if(t != '' && t != '_self') {
+ if(self.frames[t]) {
+ self.frames[t].document.location = h;
+ } else{
+ try {
+ if(top.frames[t]) {
+ top.frames[t].document.location = h;
+ return;
+ }
+ } catch(err) {
+ // different domain/port/protocol?
+ }
+ window.open(h, t);
+ }
+ return;
+ }
+ if(doc.createEvent) {
+ evt = doc.createEvent('MouseEvents');
+ evt.initMouseEvent('click', 1, 1, window, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
+ if(!a.dispatchEvent(evt))
+ return;
+ } else if(a.fireEvent) {
+ if(!a.fireEvent('onclick'))
+ return;
+ }
+ doc.location = h;
+};
+/**
+ * @constructor
+ */
+function TagCanvas(cid,lctr,opt) {
+ var i, p, c = doc.getElementById(cid), cp = ['id','class','innerHTML'];
+
+ if(!c) throw 0;
+ if(Defined(window.G_vmlCanvasManager)) {
+ c = window.G_vmlCanvasManager.initElement(c);
+ this.ie = parseFloat(navigator.appVersion.split('MSIE')[1]);
+ }
+ if(c && (!c.getContext || !c.getContext('2d').fillText)) {
+ p = doc.createElement('DIV');
+ for(i = 0; i < cp.length; ++i)
+ p[cp[i]] = c[cp[i]];
+ c.parentNode.insertBefore(p,c);
+ c.parentNode.removeChild(c);
+ throw 0;
+ }
+ for(i in TagCanvas.options)
+ this[i] = opt && Defined(opt[i]) ? opt[i] :
+ (Defined(TagCanvas[i]) ? TagCanvas[i] : TagCanvas.options[i]);
+
+ this.canvas = c;
+ this.ctxt = c.getContext('2d');
+ this.z1 = 250 / this.depth;
+ this.z2 = this.z1 / this.zoom;
+ this.radius = min(c.height, c.width) * 0.0075; // fits radius of 100 in canvas
+ this.max_weight = 0;
+ this.min_weight = 200;
+ this.textFont = this.textFont && FixFont(this.textFont);
+ this.textHeight *= 1;
+ this.pulsateTo = Clamp(this.pulsateTo, 0, 1);
+ this.minBrightness = Clamp(this.minBrightness, 0, 1);
+ this.maxBrightness = Clamp(this.maxBrightness, this.minBrightness, 1);
+ this.ctxt.textBaseline = 'top';
+ this.lx = (this.lock + '').indexOf('x') + 1;
+ this.ly = (this.lock + '').indexOf('y') + 1;
+ this.frozen = 0;
+ this.dx = this.dy = 0;
+ this.touched = 0;
+ this.source = lctr || cid;
+ this.transform = Matrix.Identity();
+ this.time = new Date().valueOf();
+ this.Animate = this.dragControl ? this.AnimateDrag : this.AnimatePosition;
+ if(this.shadowBlur || this.shadowOffset[0] || this.shadowOffset[1]) {
+ // let the browser translate "red" into "#ff0000"
+ this.ctxt.shadowColor = this.shadow;
+ this.shadow = this.ctxt.shadowColor;
+ this.shadowAlpha = ShadowAlphaBroken();
+ } else {
+ delete this.shadow;
+ }
+ this.Load();
+ if(lctr && this.hideTags) {
+ (function(t) {
+ if(TagCanvas.loaded)
+ t.HideTags();
+ else
+ AddHandler('load', function() { t.HideTags(); }, window);
+ })(this);
+ }
+
+ this.yaw = this.initial ? this.initial[0] * this.maxSpeed : 0;
+ this.pitch = this.initial ? this.initial[1] * this.maxSpeed : 0;
+ if(this.tooltip) {
+ if(this.tooltip == 'native') {
+ this.Tooltip = this.TooltipNative;
+ } else {
+ this.Tooltip = this.TooltipDiv;
+ if(!this.ttdiv) {
+ this.ttdiv = doc.createElement('div');
+ this.ttdiv.className = this.tooltipClass;
+ this.ttdiv.style.position = 'absolute';
+ this.ttdiv.style.zIndex = c.style.zIndex + 1;
+ AddHandler('mouseover',function(e){e.target.style.display='none';},this.ttdiv);
+ doc.body.appendChild(this.ttdiv);
+ }
+ }
+ } else {
+ this.Tooltip = this.TooltipNone;
+ }
+ if(!this.noMouse && !handlers[cid]) {
+ AddHandler('mousemove', MouseMove, c);
+ AddHandler('mouseout', MouseOut, c);
+ AddHandler('mouseup', MouseUp, c);
+ AddHandler('touchstart', TouchDown, c);
+ AddHandler('touchend', TouchUp, c);
+ AddHandler('touchcancel', TouchUp, c);
+ AddHandler('touchmove', TouchMove, c);
+ if(this.dragControl) {
+ AddHandler('mousedown', MouseDown, c);
+ AddHandler('selectstart', Nop, c);
+ }
+ if(this.wheelZoom) {
+ AddHandler('mousewheel', MouseWheel, c);
+ AddHandler('DOMMouseScroll', MouseWheel, c);
+ }
+ handlers[cid] = 1;
+ }
+ TagCanvas.started || (TagCanvas.started = setTimeout(DrawCanvas, this.interval));
+}
+TCproto = TagCanvas.prototype;
+TCproto.SourceElements = function() {
+ if(doc.querySelectorAll)
+ return doc.querySelectorAll('#' + this.source);
+ return [doc.getElementById(this.source)];
+};
+TCproto.HideTags = function() {
+ var el = this.SourceElements(), i;
+ for(i = 0; i < el.length; ++i)
+ el[i].style.display = 'none';
+};
+TCproto.GetTags = function() {
+ var el = this.SourceElements(), etl, tl = [], i, j;
+ for(i = 0; i < el.length; ++i) {
+ etl = el[i].getElementsByTagName('a');
+ for(j = 0; j < etl.length; ++j) {
+ tl.push(etl[j]);
+ }
+ }
+ return tl;
+};
+TCproto.CreateTag = function(e, p) {
+ var im = e.getElementsByTagName('img'), i, t, ts, font;
+ p = p || [0, 0, 0];
+ if(im.length) {
+ i = new Image;
+ i.src = im[0].src;
+ t = new Tag(this, i, e, p, 0, 0);
+ AddImage(i, im[0], t, this);
+ return t;
+ }
+ ts = new TextSplitter(e);
+ t = ts.Lines();
+ font = this.textFont || FixFont(GetProperty(e,'font-family'));
+ if(this.splitWidth)
+ t = ts.SplitWidth(this.splitWidth, this.ctxt, font, this.textHeight);
+
+ return new Tag(this, t, e, p, 2, this.textHeight + 2,
+ this.textColour || GetProperty(e,'color'), font, ts.original);
+};
+TCproto.UpdateTag = function(t, a) {
+ var colour = this.textColour || GetProperty(a, 'color'),
+ font = this.textFont || FixFont(GetProperty(a, 'font-family'));
+ t.title = a.title;
+ if(t.colour != colour || t.textFont != font)
+ t.SetFont(font, colour);
+};
+TCproto.Weight = function(tl) {
+ var l = tl.length, w, i, weights = [];
+ for(i = 0; i < l; ++i) {
+ w = FindWeight(this, tl[i].a);
+ if(w > this.max_weight) this.max_weight = w;
+ if(w < this.min_weight) this.min_weight = w;
+ weights.push(w);
+ }
+ if(this.max_weight > this.min_weight) {
+ for(i = 0; i < l; ++i) {
+ tl[i].SetWeight(weights[i]);
+ }
+ }
+};
+TCproto.Load = function() {
+ var tl = this.GetTags(), taglist = [], shape,
+ shapeArgs, rx, ry, rz, vl, i, tagmap = [], pfuncs = {
+ sphere: PointsOnSphere,
+ vcylinder: PointsOnCylinderV,
+ hcylinder: PointsOnCylinderH,
+ vring: PointsOnRingV,
+ hring: PointsOnRingH
+ };
+
+ if(tl.length) {
+ tagmap.length = tl.length;
+ for(i = 0; i < tl.length; ++i)
+ tagmap[i] = i;
+ this.shuffleTags && Shuffle(tagmap);
+ rx = 100 * this.radiusX;
+ ry = 100 * this.radiusY;
+ rz = 100 * this.radiusZ;
+ this.max_radius = max(rx, max(ry, rz));
+
+ if(this.shapeArgs) {
+ this.shapeArgs[0] = tl.length;
+ } else {
+ shapeArgs = this.shape.toString().split(/[(),]/);
+ shape = shapeArgs.shift();
+ this.shape = pfuncs[shape] || pfuncs.sphere;
+ this.shapeArgs = [tl.length, rx, ry, rz].concat(shapeArgs);
+ }
+ vl = this.shape.apply(this, this.shapeArgs);
+ this.listLength = tl.length;
+ for(i = 0; i < tl.length; ++i) {
+ taglist.push(this.CreateTag(tl[tagmap[i]], vl[i]));
+ }
+ this.weight && this.Weight(taglist, true);
+ }
+ this.taglist = taglist;
+};
+TCproto.Update = function() {
+ var tl = this.GetTags(), newlist = [],
+ taglist = this.taglist, found,
+ added = [], removed = [], vl, ol, nl, i, j;
+
+ if(!this.shapeArgs)
+ return this.Load();
+
+ if(tl.length) {
+ nl = this.listLength = tl.length;
+ ol = taglist.length;
+
+ // copy existing list, populate "removed"
+ for(i = 0; i < ol; ++i) {
+ newlist.push(taglist[i]);
+ removed.push(i);
+ }
+
+ // find added and removed tags
+ for(i = 0; i < nl; ++i) {
+ for(j = 0, found = 0; j < ol; ++j) {
+ if(taglist[j].EqualTo(tl[i])) {
+ this.UpdateTag(newlist[j], tl[i]);
+ found = removed[j] = -1;
+ }
+ }
+ if(!found)
+ added.push(i);
+ }
+
+ // clean out found tags from removed list
+ for(i = 0, j = 0; i < ol; ++i) {
+ if(removed[j] == -1)
+ removed.splice(j,1);
+ else
+ ++j;
+ }
+
+ // insert new tags in gaps where old tags removed
+ if(removed.length) {
+ Shuffle(removed);
+ while(removed.length && added.length) {
+ i = removed.shift();
+ j = added.shift();
+ newlist[i] = this.CreateTag(tl[j]);
+ }
+
+ // remove any more (in reverse order)
+ removed.sort(function(a,b) {return a-b});
+ while(removed.length) {
+ newlist.splice(removed.pop(), 1);
+ }
+ }
+
+ // add any extra tags
+ j = newlist.length / (added.length + 1);
+ i = 0;
+ while(added.length) {
+ newlist.splice(ceil(++i * j), 0, this.CreateTag(tl[added.shift()]));
+ }
+
+ // assign correct positions to tags
+ this.shapeArgs[0] = nl = newlist.length;
+ vl = this.shape.apply(this, this.shapeArgs);
+ for(i = 0; i < nl; ++i)
+ newlist[i].position = { x: vl[i][0], y: vl[i][1], z: vl[i][2] };
+
+ // reweight tags
+ this.weight && this.Weight(newlist);
+ }
+ this.taglist = newlist;
+};
+TCproto.SetShadow = function(c) {
+ c.shadowBlur = this.shadowBlur;
+ c.shadowOffsetX = this.shadowOffset[0];
+ c.shadowOffsetY = this.shadowOffset[1];
+};
+TCproto.Draw = function(t) {
+ if(this.paused)
+ return;
+ var cv = this.canvas, cw = cv.width, ch = cv.height, max_sc = 0,
+ tdelta = (t - this.time) * this.interval / 1000,
+ x = cw / 2 + this.offsetX, y = ch / 2 + this.offsetY, c = this.ctxt,
+ active, a, i, aindex = -1, tl = this.taglist, l = tl.length,
+ frontsel = this.frontSelect, centreDrawn = (this.centreFunc == Nop);
+ this.time = t;
+ if(this.frozen && this.drawn)
+ return this.Animate(cw,ch,tdelta);
+ c.setTransform(1,0,0,1,0,0);
+ this.active = null;
+ for(i = 0; i < l; ++i)
+ tl[i].Calc(this.transform);
+ tl = SortList(tl, function(a,b) {return b.z-a.z});
+
+ for(i = 0; i < l; ++i) {
+ a = this.mx >= 0 && this.my >= 0 && this.taglist[i].CheckActive(c, x, y);
+ if(a && a.sc > max_sc && (!frontsel || a.z <= 0)) {
+ active = a;
+ aindex = i;
+ active.tag = this.taglist[i];
+ max_sc = a.sc;
+ }
+ }
+ this.active = active;
+
+ this.txtOpt || (this.shadow && this.SetShadow(c));
+
+ c.clearRect(0,0,cw,ch);
+ for(i = 0; i < l; ++i) {
+ if(!centreDrawn && tl[i].z <= 0) {
+ // run the centreFunc if the next tag is at the front
+ try { this.centreFunc(c, cw, ch, x, y); }
+ catch(e) {
+ alert(e);
+ // don't run it again
+ this.centreFunc = Nop;
+ }
+ centreDrawn = true;
+ }
+
+ if(!(active && active.tag == tl[i] && active.PreDraw(c, tl[i], x, y)))
+ tl[i].Draw(c, x, y);
+ active && active.tag == tl[i] && active.PostDraw(c);
+ }
+ if(this.freezeActive && active) {
+ this.Freeze();
+ } else {
+ this.UnFreeze();
+ this.drawn = (l == this.listLength);
+ }
+ this.Animate(cw, ch, tdelta);
+ active && active.LastDraw(c);
+ cv.style.cursor = active ? this.activeCursor : '';
+ this.Tooltip(active,this.taglist[aindex]);
+};
+TCproto.TooltipNone = function() { };
+TCproto.TooltipNative = function(active,tag) {
+ this.canvas.title = active && tag.title ? tag.title : '';
+};
+TCproto.TooltipDiv = function(active,tag) {
+ var tc = this, s = tc.ttdiv.style, cid = tc.canvas.id, none = 'none';
+ if(active && tag.title) {
+ if(tag.title != tc.ttdiv.innerHTML)
+ s.display = none;
+ tc.ttdiv.innerHTML = tag.title;
+ tag.title = tc.ttdiv.innerHTML;
+ if(s.display == none && ! tc.tttimer) {
+ tc.tttimer = setTimeout(function() {
+ var p = AbsPos(cid);
+ s.display = 'block';
+ s.left = p.x + tc.mx + 'px';
+ s.top = p.y + tc.my + 24 + 'px';
+ tc.tttimer = null;
+ }, tc.tooltipDelay);
+ }
+ } else {
+ s.display = none;
+ }
+};
+TCproto.Transform = function(tc, p, y) {
+ if(p || y) {
+ var sp = sin(p), cp = cos(p), sy = sin(y), cy = cos(y),
+ ym = new Matrix([cy,0,sy,0, 0,1,0,0, -sy,0,cy,0, 0,0,0,1]),
+ pm = new Matrix([1,0,0,0, 0,cp,-sp,0, 0,sp,cp,0, 0,0,0,1]);
+ tc.transform = tc.transform.mul(ym.mul(pm));
+ }
+};
+TCproto.AnimatePosition = function(w, h, t) {
+ var tc = this, x = tc.mx, y = tc.my, s, r;
+ if(!tc.frozen && x >= 0 && y >= 0 && x < w && y < h) {
+ s = tc.maxSpeed, r = tc.reverse ? -1 : 1;
+ tc.lx || (tc.yaw = r * t * ((s * 2 * x / w) - s));
+ tc.ly || (tc.pitch = r * t * -((s * 2 * y / h) - s));
+ tc.initial = null;
+ } else if(!tc.initial) {
+ if(tc.frozen && !tc.freezeDecel)
+ tc.yaw = tc.pitch = 0;
+ else
+ tc.Decel(tc);
+ }
+ this.Transform(tc, tc.pitch, tc.yaw);
+};
+TCproto.AnimateDrag = function(w, h, t) {
+ var tc = this, rs = 100 * t * tc.maxSpeed / tc.max_radius / tc.zoom;
+ if(tc.dx || tc.dy) {
+ tc.lx || (tc.yaw = tc.dx * rs / tc.stretchX);
+ tc.ly || (tc.pitch = tc.dy * -rs / tc.stretchY);
+ tc.dx = tc.dy = 0;
+ tc.initial = null;
+ } else if(!tc.initial) {
+ tc.Decel(tc);
+ }
+ this.Transform(tc, tc.pitch, tc.yaw);
+};
+TCproto.Freeze = function() {
+ if(!this.frozen) {
+ this.preFreeze = [this.yaw, this.pitch];
+ this.frozen = 1;
+ this.drawn = 0;
+ }
+};
+TCproto.UnFreeze = function() {
+ if(this.frozen) {
+ this.yaw = this.preFreeze[0];
+ this.pitch = this.preFreeze[1];
+ this.frozen = 0;
+ }
+};
+TCproto.Decel = function(tc) {
+ var s = tc.minSpeed, ay = abs(tc.yaw), ap = abs(tc.pitch);
+ if(!tc.lx && ay > s)
+ tc.yaw = ay > tc.z0 ? tc.yaw * tc.decel : 0;
+ if(!tc.ly && ap > s)
+ tc.pitch = ap > tc.z0 ? tc.pitch * tc.decel : 0;
+};
+TCproto.Zoom = function(r) {
+ this.z2 = this.z1 * (1/r);
+ this.drawn = 0;
+};
+TCproto.Clicked = function(e) {
+ var a = this.active;
+ try {
+ a && a.tag && a.tag.Clicked(e);
+ } catch(ex) {
+ }
+};
+TCproto.Wheel = function(i) {
+ var z = this.zoom + this.zoomStep * (i ? 1 : -1);
+ this.zoom = min(this.zoomMax,max(this.zoomMin,z));
+ this.Zoom(this.zoom);
+};
+TCproto.BeginDrag = function(e) {
+ this.down = EventXY(e, this.canvas);
+ e.cancelBubble = true;
+ e.returnValue = false;
+ e.preventDefault && e.preventDefault();
+};
+TCproto.Drag = function(e, p) {
+ if(this.dragControl && this.down) {
+ var t2 = this.dragThreshold * this.dragThreshold,
+ dx = p.x - this.down.x, dy = p.y - this.down.y;
+ if(this.dragging || dx * dx + dy * dy > t2) {
+ this.dx = dx;
+ this.dy = dy;
+ this.dragging = 1;
+ this.down = p;
+ }
+ }
+};
+TCproto.EndDrag = function() {
+ var res = this.dragging;
+ this.dragging = this.down = null;
+ return res;
+};
+TCproto.Pause = function() { this.paused = true; };
+TCproto.Resume = function() { this.paused = false; };
+TagCanvas.Start = function(id,l,o) {
+ TagCanvas.tc[id] = new TagCanvas(id,l,o);
+};
+function tccall(f,id) {
+ TagCanvas.tc[id] && TagCanvas.tc[id][f]();
+}
+TagCanvas.Pause = function(id) {
+ tccall('Pause',id);
+};
+TagCanvas.Resume = function(id) {
+ tccall('Resume',id);
+};
+TagCanvas.Reload = function(id) {
+ tccall('Load',id);
+};
+TagCanvas.Update = function(id) {
+ tccall('Update',id);
+};
+TagCanvas.NextFrame = function(iv) {
+ var raf = window.requestAnimationFrame = window.requestAnimationFrame ||
+ window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
+ window.msRequestAnimationFrame;
+ TagCanvas.NextFrame = raf ? TagCanvas.NextFrameRAF : TagCanvas.NextFrameTimeout;
+ TagCanvas.NextFrame(iv);
+};
+TagCanvas.NextFrameRAF = function() {
+ requestAnimationFrame(DrawCanvas);
+};
+TagCanvas.NextFrameTimeout = function(iv) {
+ setTimeout(DrawCanvas, iv);
+};
+TagCanvas.tc = {};
+TagCanvas.options = {
+z1: 20000,
+z2: 20000,
+z0: 0.0002,
+freezeActive: false,
+freezeDecel: false,
+activeCursor: 'pointer',
+pulsateTo: 1,
+pulsateTime: 3,
+reverse: false,
+depth: 0.5,
+maxSpeed: 0.05,
+minSpeed: 0,
+decel: 0.95,
+interval: 20,
+minBrightness: 0.1,
+maxBrightness: 1,
+outlineColour: '#ffff99',
+outlineThickness: 2,
+outlineOffset: 5,
+outlineMethod: 'outline',
+textColour: '#ff99ff',
+textHeight: 15,
+textFont: 'Helvetica, Arial, sans-serif',
+shadow: '#000',
+shadowBlur: 0,
+shadowOffset: [0,0],
+initial: null,
+hideTags: true,
+zoom: 1,
+weight: false,
+weightMode: 'size',
+weightFrom: null,
+weightSize: 1,
+weightSizeMin: null,
+weightSizeMax: null,
+weightGradient: {0:'#f00', 0.33:'#ff0', 0.66:'#0f0', 1:'#00f'},
+txtOpt: true,
+txtScale: 2,
+frontSelect: false,
+wheelZoom: true,
+zoomMin: 0.3,
+zoomMax: 3,
+zoomStep: 0.05,
+shape: 'sphere',
+lock: null,
+tooltip: null,
+tooltipDelay: 300,
+tooltipClass: 'tctooltip',
+radiusX: 1,
+radiusY: 1,
+radiusZ: 1,
+stretchX: 1,
+stretchY: 1,
+offsetX: 0,
+offsetY: 0,
+shuffleTags: false,
+noSelect: false,
+noMouse: false,
+imageScale: 1,
+paused: false,
+dragControl: false,
+dragThreshold: 4,
+centreFunc: Nop,
+splitWidth: 0
+};
+for(i in TagCanvas.options) TagCanvas[i] = TagCanvas.options[i];
+window.TagCanvas = TagCanvas;
+jQuery.fn.tagcanvas = function(options, lctr) {
+ var fn = {
+ pause: function() {
+ $(this).each(function() {
+ tccall('Pause',$(this)[0].id);
+ });
+ },
+ resume: function() {
+ $(this).each(function() {
+ tccall('Resume',$(this)[0].id);
+ });
+ },
+ reload: function() {
+ $(this).each(function() {
+ tccall('Reload',$(this)[0].id);
+ });
+ },
+ update: function() {
+ $(this).each(function() {
+ tccall('Update',$(this)[0].id);
+ });
+ },
+ };
+ if(typeof(options) == 'string' && fn[options]) {
+ fn[options].apply(this);
+ } else {
+ TagCanvas.jquery = 1;
+ $(this).each(function() {
+ TagCanvas.Start($(this)[0].id, lctr, options);
+ });
+ return TagCanvas.started;
+ }
+};
+
+// set a flag for when the window has loaded
+AddHandler('load',function(){TagCanvas.loaded=1},window);
+})(jQuery); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.css b/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.css
new file mode 100644
index 00000000..8a08e22b
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.css
@@ -0,0 +1,23 @@
+.ui-multiselect { padding:2px 0 2px 4px; text-align:left }
+.ui-multiselect span.ui-icon { float:right }
+.ui-multiselect-single .ui-multiselect-checkboxes input { position:absolute !important; top: auto !important; left:-9999px; }
+.ui-multiselect-single .ui-multiselect-checkboxes label { padding:5px !important }
+
+.ui-multiselect-header { margin-bottom:3px; padding:3px 0 3px 4px }
+.ui-multiselect-header ul { font-size:0.9em }
+.ui-multiselect-header ul li { float:left; padding:0 10px 0 0 }
+.ui-multiselect-header a { text-decoration:none }
+.ui-multiselect-header a:hover { text-decoration:underline }
+.ui-multiselect-header span.ui-icon { float:left }
+.ui-multiselect-header li.ui-multiselect-close { float:right; text-align:right; padding-right:0 }
+
+.ui-multiselect-menu { display:none; padding:3px; position:absolute; z-index:10000; text-align: left }
+.ui-multiselect-checkboxes { position:relative /* fixes bug in IE6/7 */; overflow-y:auto }
+.ui-multiselect-checkboxes label { cursor:default; display:block; border:1px solid transparent; padding:3px 1px }
+.ui-multiselect-checkboxes label input { position:relative; top:1px }
+.ui-multiselect-checkboxes li { clear:both; font-size:0.9em; padding-right:3px }
+.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label { text-align:center; font-weight:bold; border-bottom:1px solid }
+.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label a { display:block; padding:3px; margin:1px 0; text-decoration:none }
+
+/* remove label borders in IE6 because IE6 does not support transparency */
+* html .ui-multiselect-checkboxes label { border:none }
diff --git a/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.css b/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.css
new file mode 100644
index 00000000..f8c323a7
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.css
@@ -0,0 +1,3 @@
+.ui-multiselect-hasfilter ul { position:relative; top:2px }
+.ui-multiselect-filter { float:left; margin-right:10px; font-size:11px }
+.ui-multiselect-filter input { width:100px; font-size:10px; margin-left:5px; height:15px; padding:2px; border:1px solid #292929; -webkit-appearance:textfield; -webkit-box-sizing:content-box; }
diff --git a/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.js b/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.js
new file mode 100644
index 00000000..88e04b93
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.filter.js
@@ -0,0 +1,172 @@
+/* jshint forin:true, noarg:true, noempty:true, eqeqeq:true, boss:true, undef:true, curly:true, browser:true, jquery:true */
+/*
+ * jQuery MultiSelect UI Widget Filtering Plugin 1.5pre
+ * Copyright (c) 2012 Eric Hynds
+ *
+ * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/
+ *
+ * Depends:
+ * - jQuery UI MultiSelect widget
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+(function($) {
+ var rEscape = /[\-\[\]{}()*+?.,\\\^$|#\s]/g;
+
+ $.widget('ech.multiselectfilter', {
+
+ options: {
+ label: 'Filter:',
+ width: null, /* override default width set in css file (px). null will inherit */
+ placeholder: 'Enter keywords',
+ autoReset: false
+ },
+
+ _create: function() {
+ var opts = this.options;
+
+ // get the multiselect instance
+ var instance = (this.instance = $(this.element).data('multiselect'));
+
+ // store header; add filter class so the close/check all/uncheck all links can be positioned correctly
+ var header = (this.header = instance.menu.find('.ui-multiselect-header').addClass('ui-multiselect-hasfilter'));
+
+ // wrapper elem
+ var wrapper = (this.wrapper = $('<div class="ui-multiselect-filter">' + (opts.label.length ? opts.label : '') + '<input placeholder="'+opts.placeholder+'" type="search"' + (/\d/.test(opts.width) ? 'style="width:'+opts.width+'px"' : '') + ' /></div>').prependTo(this.header));
+
+ // reference to the actual inputs
+ this.inputs = instance.menu.find('input[type="checkbox"], input[type="radio"]');
+
+ // build the input box
+ this.input = wrapper.find('input').bind({
+ keydown: function(e) {
+ // prevent the enter key from submitting the form / closing the widget
+ if(e.which === 13) {
+ e.preventDefault();
+ }
+ },
+ keyup: $.proxy(this._handler, this),
+ click: $.proxy(this._handler, this)
+ });
+
+ // cache input values for searching
+ this.updateCache();
+
+ // rewrite internal _toggleChecked fn so that when checkAll/uncheckAll is fired,
+ // only the currently filtered elements are checked
+ instance._toggleChecked = function(flag, group) {
+ var $inputs = (group && group.length) ? group : this.labels.find('input');
+
+ // do not include hidden elems if the menu isn't open.
+ var selector = instance._isOpen ? ':disabled, :hidden' : ':disabled';
+
+ $inputs = $inputs
+ .not(selector)
+ .each(this._toggleState('checked', flag));
+
+ // update text
+ this.update();
+
+ // gather an array of the values that actually changed
+ var values = $inputs.map(function() {
+ return this.value;
+ }).get();
+
+ // select option tags
+ this.element.find('option').filter(function() {
+ if(!this.disabled && $.inArray(this.value, values) > -1) {
+ _self._toggleState('selected', flag).call(this);
+ }
+ });
+
+ // trigger the change event on the select
+ if($inputs.length) {
+ this.element.trigger('change');
+ }
+ };
+
+ // rebuild cache when multiselect is updated
+ var doc = $(document).bind('multiselectrefresh', $.proxy(function() {
+ this.updateCache();
+ this._handler();
+ }, this));
+
+ // automatically reset the widget on close?
+ if(this.options.autoReset) {
+ doc.bind('multiselectclose', $.proxy(this._reset, this));
+ }
+ },
+
+ // thx for the logic here ben alman
+ _handler: function(e) {
+ var term = $.trim(this.input[0].value.toLowerCase()),
+
+ // speed up lookups
+ rows = this.rows, inputs = this.inputs, cache = this.cache;
+
+ if(!term) {
+ rows.show();
+ } else {
+ rows.hide();
+
+ var regex = new RegExp(term.replace(rEscape, "\\$&"), 'gi');
+
+ this._trigger("filter", e, $.map(cache, function(v, i) {
+ if(v.search(regex) !== -1) {
+ rows.eq(i).show();
+ return inputs.get(i);
+ }
+
+ return null;
+ }));
+ }
+
+ // show/hide optgroups
+ this.instance.menu.find(".ui-multiselect-optgroup-label").each(function() {
+ var $this = $(this);
+ var isVisible = $this.nextUntil('.ui-multiselect-optgroup-label').filter(function() {
+ return $.css(this, "display") !== 'none';
+ }).length;
+
+ $this[isVisible ? 'show' : 'hide']();
+ });
+ },
+
+ _reset: function() {
+ this.input.val('').trigger('keyup');
+ },
+
+ updateCache: function() {
+ // each list item
+ this.rows = this.instance.menu.find(".ui-multiselect-checkboxes li:not(.ui-multiselect-optgroup-label)");
+
+ // cache
+ this.cache = this.element.children().map(function() {
+ var elem = $(this);
+
+ // account for optgroups
+ if(this.tagName.toLowerCase() === "optgroup") {
+ elem = elem.children();
+ }
+
+ return elem.map(function() {
+ return this.innerHTML.toLowerCase();
+ }).get();
+ }).get();
+ },
+
+ widget: function() {
+ return this.wrapper;
+ },
+
+ destroy: function() {
+ $.Widget.prototype.destroy.call(this);
+ this.input.val('').trigger("keyup");
+ this.wrapper.remove();
+ }
+ });
+
+})(jQuery);
diff --git a/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.js b/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.js
new file mode 100644
index 00000000..a879506b
--- /dev/null
+++ b/SemanticResultFormats/resources/jquery/multiselect/jquery.multiselect.js
@@ -0,0 +1,727 @@
+/* jshint forin:true, noarg:true, noempty:true, eqeqeq:true, boss:true, undef:true, curly:true, browser:true, jquery:true */
+/*
+ * jQuery MultiSelect UI Widget 1.14pre
+ * Copyright (c) 2012 Eric Hynds
+ *
+ * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/
+ *
+ * Depends:
+ * - jQuery 1.4.2+
+ * - jQuery UI 1.8 widget factory
+ *
+ * Optional:
+ * - jQuery UI effects
+ * - jQuery UI position utility
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+(function($, undefined) {
+
+ var multiselectID = 0;
+ var $doc = $(document);
+
+ $.widget("ech.multiselect", {
+
+ // default options
+ options: {
+ header: true,
+ height: 175,
+ minWidth: 225,
+ classes: '',
+ checkAllText: 'Check all',
+ uncheckAllText: 'Uncheck all',
+ noneSelectedText: 'Select options',
+ selectedText: '# selected',
+ selectedList: 0,
+ show: null,
+ hide: null,
+ autoOpen: false,
+ multiple: true,
+ position: {}
+ },
+
+ _create: function() {
+ var el = this.element.hide();
+ var o = this.options;
+
+ this.speed = $.fx.speeds._default; // default speed for effects
+ this._isOpen = false; // assume no
+
+ // create a unique namespace for events that the widget
+ // factory cannot unbind automatically. Use eventNamespace if on
+ // jQuery UI 1.9+, and otherwise fallback to a custom string.
+ this._namespaceID = this.eventNamespace || ('multiselect' + multiselectID);
+
+ var button = (this.button = $('<button type="button"><span class="ui-icon ui-icon-triangle-2-n-s"></span></button>'))
+ .addClass('ui-multiselect ui-widget ui-state-default ui-corner-all')
+ .addClass(o.classes)
+ .attr({ 'title':el.attr('title'), 'aria-haspopup':true, 'tabIndex':el.attr('tabIndex') })
+ .insertAfter(el),
+
+ buttonlabel = (this.buttonlabel = $('<span />'))
+ .html(o.noneSelectedText)
+ .appendTo(button),
+
+ menu = (this.menu = $('<div />'))
+ .addClass('ui-multiselect-menu ui-widget ui-widget-content ui-corner-all')
+ .addClass(o.classes)
+ .appendTo(document.body),
+
+ header = (this.header = $('<div />'))
+ .addClass('ui-widget-header ui-corner-all ui-multiselect-header ui-helper-clearfix')
+ .appendTo(menu),
+
+ headerLinkContainer = (this.headerLinkContainer = $('<ul />'))
+ .addClass('ui-helper-reset')
+ .html(function() {
+ if(o.header === true) {
+ return '<li><a class="ui-multiselect-all" href="#"><span class="ui-icon ui-icon-check"></span><span>' + o.checkAllText + '</span></a></li><li><a class="ui-multiselect-none" href="#"><span class="ui-icon ui-icon-closethick"></span><span>' + o.uncheckAllText + '</span></a></li>';
+ } else if(typeof o.header === "string") {
+ return '<li>' + o.header + '</li>';
+ } else {
+ return '';
+ }
+ })
+ .append('<li class="ui-multiselect-close"><a href="#" class="ui-multiselect-close"><span class="ui-icon ui-icon-circle-close"></span></a></li>')
+ .appendTo(header),
+
+ checkboxContainer = (this.checkboxContainer = $('<ul />'))
+ .addClass('ui-multiselect-checkboxes ui-helper-reset')
+ .appendTo(menu);
+
+ // perform event bindings
+ this._bindEvents();
+
+ // build menu
+ this.refresh(true);
+
+ // some addl. logic for single selects
+ if(!o.multiple) {
+ menu.addClass('ui-multiselect-single');
+ }
+
+ // bump unique ID
+ multiselectID++;
+ },
+
+ _init: function() {
+ if(this.options.header === false) {
+ this.header.hide();
+ }
+ if(!this.options.multiple) {
+ this.headerLinkContainer.find('.ui-multiselect-all, .ui-multiselect-none').hide();
+ }
+ if(this.options.autoOpen) {
+ this.open();
+ }
+ if(this.element.is(':disabled')) {
+ this.disable();
+ }
+ },
+
+ refresh: function(init) {
+ var el = this.element;
+ var o = this.options;
+ var menu = this.menu;
+ var checkboxContainer = this.checkboxContainer;
+ var optgroups = [];
+ var html = "";
+ var id = el.attr('id') || multiselectID++; // unique ID for the label & option tags
+
+ // build items
+ el.find('option').each(function(i) {
+ var $this = $(this);
+ var parent = this.parentNode;
+ var title = this.innerHTML;
+ var description = this.title;
+ var value = this.value;
+ var inputID = 'ui-multiselect-' + (this.id || id + '-option-' + i);
+ var isDisabled = this.disabled;
+ var isSelected = this.selected;
+ var labelClasses = [ 'ui-corner-all' ];
+ var liClasses = (isDisabled ? 'ui-multiselect-disabled ' : ' ') + this.className;
+ var optLabel;
+
+ // is this an optgroup?
+ if(parent.tagName === 'OPTGROUP') {
+ optLabel = parent.getAttribute('label');
+
+ // has this optgroup been added already?
+ if($.inArray(optLabel, optgroups) === -1) {
+ html += '<li class="ui-multiselect-optgroup-label ' + parent.className + '"><a href="#">' + optLabel + '</a></li>';
+ optgroups.push(optLabel);
+ }
+ }
+
+ if(isDisabled) {
+ labelClasses.push('ui-state-disabled');
+ }
+
+ // browsers automatically select the first option
+ // by default with single selects
+ if(isSelected && !o.multiple) {
+ labelClasses.push('ui-state-active');
+ }
+
+ html += '<li class="' + liClasses + '">';
+
+ // create the label
+ html += '<label for="' + inputID + '" title="' + description + '" class="' + labelClasses.join(' ') + '">';
+ html += '<input id="' + inputID + '" name="multiselect_' + id + '" type="' + (o.multiple ? "checkbox" : "radio") + '" value="' + value + '" title="' + title + '"';
+
+ // pre-selected?
+ if(isSelected) {
+ html += ' checked="checked"';
+ html += ' aria-selected="true"';
+ }
+
+ // disabled?
+ if(isDisabled) {
+ html += ' disabled="disabled"';
+ html += ' aria-disabled="true"';
+ }
+
+ // add the title and close everything off
+ html += ' /><span>' + title + '</span></label></li>';
+ });
+
+ // insert into the DOM
+ checkboxContainer.html(html);
+
+ // cache some moar useful elements
+ this.labels = menu.find('label');
+ this.inputs = this.labels.children('input');
+
+ // set widths
+ this._setButtonWidth();
+ this._setMenuWidth();
+
+ // remember default value
+ this.button[0].defaultValue = this.update();
+
+ // broadcast refresh event; useful for widgets
+ if(!init) {
+ this._trigger('refresh');
+ }
+ },
+
+ // updates the button text. call refresh() to rebuild
+ update: function() {
+ var o = this.options;
+ var $inputs = this.inputs;
+ var $checked = $inputs.filter(':checked');
+ var numChecked = $checked.length;
+ var value;
+
+ if(numChecked === 0) {
+ value = o.noneSelectedText;
+ } else {
+ if($.isFunction(o.selectedText)) {
+ value = o.selectedText.call(this, numChecked, $inputs.length, $checked.get());
+ } else if(/\d/.test(o.selectedList) && o.selectedList > 0 && numChecked <= o.selectedList) {
+ value = $checked.map(function() { return $(this).next().html(); }).get().join(', ');
+ } else {
+ value = o.selectedText.replace('#', numChecked).replace('#', $inputs.length);
+ }
+ }
+
+ this._setButtonValue(value);
+
+ return value;
+ },
+
+ // this exists as a separate method so that the developer
+ // can easily override it.
+ _setButtonValue: function(value) {
+ this.buttonlabel.text(value);
+ },
+
+ // binds events
+ _bindEvents: function() {
+ var self = this;
+ var button = this.button;
+
+ function clickHandler() {
+ self[ self._isOpen ? 'close' : 'open' ]();
+ return false;
+ }
+
+ // webkit doesn't like it when you click on the span :(
+ button
+ .find('span')
+ .bind('click.multiselect', clickHandler);
+
+ // button events
+ button.bind({
+ click: clickHandler,
+ keypress: function(e) {
+ switch(e.which) {
+ case 27: // esc
+ case 38: // up
+ case 37: // left
+ self.close();
+ break;
+ case 39: // right
+ case 40: // down
+ self.open();
+ break;
+ }
+ },
+ mouseenter: function() {
+ if(!button.hasClass('ui-state-disabled')) {
+ $(this).addClass('ui-state-hover');
+ }
+ },
+ mouseleave: function() {
+ $(this).removeClass('ui-state-hover');
+ },
+ focus: function() {
+ if(!button.hasClass('ui-state-disabled')) {
+ $(this).addClass('ui-state-focus');
+ }
+ },
+ blur: function() {
+ $(this).removeClass('ui-state-focus');
+ }
+ });
+
+ // header links
+ this.header.delegate('a', 'click.multiselect', function(e) {
+ // close link
+ if($(this).hasClass('ui-multiselect-close')) {
+ self.close();
+
+ // check all / uncheck all
+ } else {
+ self[$(this).hasClass('ui-multiselect-all') ? 'checkAll' : 'uncheckAll']();
+ }
+
+ e.preventDefault();
+ });
+
+ // optgroup label toggle support
+ this.menu.delegate('li.ui-multiselect-optgroup-label a', 'click.multiselect', function(e) {
+ e.preventDefault();
+
+ var $this = $(this);
+ var $inputs = $this.parent().nextUntil('li.ui-multiselect-optgroup-label').find('input:visible:not(:disabled)');
+ var nodes = $inputs.get();
+ var label = $this.parent().text();
+
+ // trigger event and bail if the return is false
+ if(self._trigger('beforeoptgrouptoggle', e, { inputs:nodes, label:label }) === false) {
+ return;
+ }
+
+ // toggle inputs
+ self._toggleChecked(
+ $inputs.filter(':checked').length !== $inputs.length,
+ $inputs
+ );
+
+ self._trigger('optgrouptoggle', e, {
+ inputs: nodes,
+ label: label,
+ checked: nodes[0].checked
+ });
+ })
+ .delegate('label', 'mouseenter.multiselect', function() {
+ if(!$(this).hasClass('ui-state-disabled')) {
+ self.labels.removeClass('ui-state-hover');
+ $(this).addClass('ui-state-hover').find('input').focus();
+ }
+ })
+ .delegate('label', 'keydown.multiselect', function(e) {
+ e.preventDefault();
+
+ switch(e.which) {
+ case 9: // tab
+ case 27: // esc
+ self.close();
+ break;
+ case 38: // up
+ case 40: // down
+ case 37: // left
+ case 39: // right
+ self._traverse(e.which, this);
+ break;
+ case 13: // enter
+ $(this).find('input')[0].click();
+ break;
+ }
+ })
+ .delegate('input[type="checkbox"], input[type="radio"]', 'click.multiselect', function(e) {
+ var $this = $(this);
+ var val = this.value;
+ var checked = this.checked;
+ var tags = self.element.find('option');
+
+ // bail if this input is disabled or the event is cancelled
+ if(this.disabled || self._trigger('click', e, { value: val, text: this.title, checked: checked }) === false) {
+ e.preventDefault();
+ return;
+ }
+
+ // make sure the input has focus. otherwise, the esc key
+ // won't close the menu after clicking an item.
+ $this.focus();
+
+ // toggle aria state
+ $this.attr('aria-selected', checked);
+
+ // change state on the original option tags
+ tags.each(function() {
+ if(this.value === val) {
+ this.selected = checked;
+ } else if(!self.options.multiple) {
+ this.selected = false;
+ }
+ });
+
+ // some additional single select-specific logic
+ if(!self.options.multiple) {
+ self.labels.removeClass('ui-state-active');
+ $this.closest('label').toggleClass('ui-state-active', checked);
+
+ // close menu
+ self.close();
+ }
+
+ // fire change on the select box
+ self.element.trigger("change");
+
+ // setTimeout is to fix multiselect issue #14 and #47. caused by jQuery issue #3827
+ // http://bugs.jquery.com/ticket/3827
+ setTimeout($.proxy(self.update, self), 10);
+ });
+
+ // close each widget when clicking on any other element/anywhere else on the page
+ $doc.bind('mousedown.' + this._namespaceID, function(e) {
+ if(self._isOpen && !$.contains(self.menu[0], e.target) && !$.contains(self.button[0], e.target) && e.target !== self.button[0]) {
+ self.close();
+ }
+ });
+
+ // deal with form resets. the problem here is that buttons aren't
+ // restored to their defaultValue prop on form reset, and the reset
+ // handler fires before the form is actually reset. delaying it a bit
+ // gives the form inputs time to clear.
+ $(this.element[0].form).bind('reset.multiselect', function() {
+ setTimeout($.proxy(self.refresh, self), 10);
+ });
+ },
+
+ // set button width
+ _setButtonWidth: function() {
+ var width = this.element.outerWidth();
+ var o = this.options;
+
+ if(/\d/.test(o.minWidth) && width < o.minWidth) {
+ width = o.minWidth;
+ }
+
+ // set widths
+ this.button.outerWidth(width);
+ },
+
+ // set menu width
+ _setMenuWidth: function() {
+ var m = this.menu;
+ m.outerWidth(this.button.outerWidth());
+ },
+
+ // move up or down within the menu
+ _traverse: function(which, start) {
+ var $start = $(start);
+ var moveToLast = which === 38 || which === 37;
+
+ // select the first li that isn't an optgroup label / disabled
+ $next = $start.parent()[moveToLast ? 'prevAll' : 'nextAll']('li:not(.ui-multiselect-disabled, .ui-multiselect-optgroup-label)')[ moveToLast ? 'last' : 'first']();
+
+ // if at the first/last element
+ if(!$next.length) {
+ var $container = this.menu.find('ul').last();
+
+ // move to the first/last
+ this.menu.find('label')[ moveToLast ? 'last' : 'first' ]().trigger('mouseover');
+
+ // set scroll position
+ $container.scrollTop(moveToLast ? $container.height() : 0);
+
+ } else {
+ $next.find('label').trigger('mouseover');
+ }
+ },
+
+ // This is an internal function to toggle the checked property and
+ // other related attributes of a checkbox.
+ //
+ // The context of this function should be a checkbox; do not proxy it.
+ _toggleState: function(prop, flag) {
+ return function() {
+ if(!this.disabled) {
+ this[ prop ] = flag;
+ }
+
+ if(flag) {
+ this.setAttribute('aria-selected', true);
+ } else {
+ this.removeAttribute('aria-selected');
+ }
+ };
+ },
+
+ _toggleChecked: function(flag, group) {
+ var $inputs = (group && group.length) ? group : this.inputs;
+ var self = this;
+
+ // toggle state on inputs
+ $inputs.each(this._toggleState('checked', flag));
+
+ // give the first input focus
+ $inputs.eq(0).focus();
+
+ // update button text
+ this.update();
+
+ // gather an array of the values that actually changed
+ var values = $inputs.map(function() {
+ return this.value;
+ }).get();
+
+ // toggle state on original option tags
+ this.element
+ .find('option')
+ .each(function() {
+ if(!this.disabled && $.inArray(this.value, values) > -1) {
+ self._toggleState('selected', flag).call(this);
+ }
+ });
+
+ // trigger the change event on the select
+ if($inputs.length) {
+ this.element.trigger("change");
+ }
+ },
+
+ _toggleDisabled: function(flag) {
+ this.button.attr({ 'disabled':flag, 'aria-disabled':flag })[ flag ? 'addClass' : 'removeClass' ]('ui-state-disabled');
+
+ var inputs = this.menu.find('input');
+ var key = "ech-multiselect-disabled";
+
+ if(flag) {
+ // remember which elements this widget disabled (not pre-disabled)
+ // elements, so that they can be restored if the widget is re-enabled.
+ inputs = inputs.filter(':enabled').data(key, true)
+ } else {
+ inputs = inputs.filter(function() {
+ return $.data(this, key) === true;
+ }).removeData(key);
+ }
+
+ inputs
+ .attr({ 'disabled':flag, 'arial-disabled':flag })
+ .parent()[ flag ? 'addClass' : 'removeClass' ]('ui-state-disabled');
+
+ this.element.attr({
+ 'disabled':flag,
+ 'aria-disabled':flag
+ });
+ },
+
+ // open the menu
+ open: function(e) {
+ var self = this;
+ var button = this.button;
+ var menu = this.menu;
+ var speed = this.speed;
+ var o = this.options;
+ var args = [];
+
+ // bail if the multiselectopen event returns false, this widget is disabled, or is already open
+ if(this._trigger('beforeopen') === false || button.hasClass('ui-state-disabled') || this._isOpen) {
+ return;
+ }
+
+ var $container = menu.find('ul').last();
+ var effect = o.show;
+
+ // figure out opening effects/speeds
+ if($.isArray(o.show)) {
+ effect = o.show[0];
+ speed = o.show[1] || self.speed;
+ }
+
+ // if there's an effect, assume jQuery UI is in use
+ // build the arguments to pass to show()
+ if(effect) {
+ args = [ effect, speed ];
+ }
+
+ // set the scroll of the checkbox container
+ $container.scrollTop(0).height(o.height);
+
+ // positon
+ this.position();
+
+ // show the menu, maybe with a speed/effect combo
+ $.fn.show.apply(menu, args);
+
+ // select the first option
+ // triggering both mouseover and mouseover because 1.4.2+ has a bug where triggering mouseover
+ // will actually trigger mouseenter. the mouseenter trigger is there for when it's eventually fixed
+ this.labels.eq(0).trigger('mouseover').trigger('mouseenter').find('input').trigger('focus');
+
+ button.addClass('ui-state-active');
+ this._isOpen = true;
+ this._trigger('open');
+ },
+
+ // close the menu
+ close: function() {
+ if(this._trigger('beforeclose') === false) {
+ return;
+ }
+
+ var o = this.options;
+ var effect = o.hide;
+ var speed = this.speed;
+ var args = [];
+
+ // figure out opening effects/speeds
+ if($.isArray(o.hide)) {
+ effect = o.hide[0];
+ speed = o.hide[1] || this.speed;
+ }
+
+ if(effect) {
+ args = [ effect, speed ];
+ }
+
+ $.fn.hide.apply(this.menu, args);
+ this.button.removeClass('ui-state-active').trigger('blur').trigger('mouseleave');
+ this._isOpen = false;
+ this._trigger('close');
+ },
+
+ enable: function() {
+ this._toggleDisabled(false);
+ },
+
+ disable: function() {
+ this._toggleDisabled(true);
+ },
+
+ checkAll: function(e) {
+ this._toggleChecked(true);
+ this._trigger('checkAll');
+ },
+
+ uncheckAll: function() {
+ this._toggleChecked(false);
+ this._trigger('uncheckAll');
+ },
+
+ getChecked: function() {
+ return this.menu.find('input').filter(':checked');
+ },
+
+ destroy: function() {
+ // remove classes + data
+ $.Widget.prototype.destroy.call(this);
+
+ // unbind events
+ $doc.unbind(this._namespaceID);
+
+ this.button.remove();
+ this.menu.remove();
+ this.element.show();
+
+ return this;
+ },
+
+ isOpen: function() {
+ return this._isOpen;
+ },
+
+ widget: function() {
+ return this.menu;
+ },
+
+ getButton: function() {
+ return this.button;
+ },
+
+ position: function() {
+ var o = this.options;
+
+ // use the position utility if it exists and options are specifified
+ if($.ui.position && !$.isEmptyObject(o.position)) {
+ o.position.of = o.position.of || button;
+
+ this.menu
+ .show()
+ .position(o.position)
+ .hide();
+
+ // otherwise fallback to custom positioning
+ } else {
+ var pos = this.button.offset();
+
+ this.menu.css({
+ top: pos.top + this.button.outerHeight(),
+ left: pos.left
+ });
+ }
+ },
+
+ // react to option changes after initialization
+ _setOption: function(key, value) {
+ var menu = this.menu;
+
+ switch(key) {
+ case 'header':
+ menu.find('div.ui-multiselect-header')[value ? 'show' : 'hide']();
+ break;
+ case 'checkAllText':
+ menu.find('a.ui-multiselect-all span').eq(-1).text(value);
+ break;
+ case 'uncheckAllText':
+ menu.find('a.ui-multiselect-none span').eq(-1).text(value);
+ break;
+ case 'height':
+ menu.find('ul').last().height(parseInt(value, 10));
+ break;
+ case 'minWidth':
+ this.options[key] = parseInt(value, 10);
+ this._setButtonWidth();
+ this._setMenuWidth();
+ break;
+ case 'selectedText':
+ case 'selectedList':
+ case 'noneSelectedText':
+ this.options[key] = value; // these all needs to update immediately for the update() call
+ this.update();
+ break;
+ case 'classes':
+ menu.add(this.button).removeClass(this.options.classes).addClass(value);
+ break;
+ case 'multiple':
+ menu.toggleClass('ui-multiselect-single', !value);
+ this.options.multiple = value;
+ this.element[0].multiple = value;
+ this.refresh();
+ break;
+ case 'position':
+ this.position();
+ }
+
+ $.Widget.prototype._setOption.apply(this, arguments);
+ }
+ });
+
+})(jQuery);
diff --git a/SemanticResultFormats/resources/widgets/ext.srf.widgets.optionslist.js b/SemanticResultFormats/resources/widgets/ext.srf.widgets.optionslist.js
new file mode 100644
index 00000000..9355e4e2
--- /dev/null
+++ b/SemanticResultFormats/resources/widgets/ext.srf.widgets.optionslist.js
@@ -0,0 +1,157 @@
+/**
+ * SRF JavaScript srf.optionslist widget
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * Helper method
+ *
+ * @type object
+ */
+ var html = mw.html;
+
+ /**
+ * $.widget factory method
+ *
+ * @since 1.9
+ *
+ * @class
+ * @constructor
+ */
+ $.widget( 'srf.optionslist', {
+
+ /**
+ * Internal method that runs once during initialization
+ *
+ * @private
+ * @return {object}
+ */
+ _init: function() {
+ var self = this,
+ el = self.element;
+ return el;
+ },
+
+ /**
+ * Create checkbox elements from an array
+ *
+ * @return object
+ */
+ checklist: function( options ) {
+ var self = this,
+ el = self.element;
+
+ // Returns a list of elements
+ function checkList( list, checkListClass ) {
+ if ( list !== undefined ) {
+ var elements = [];
+ $.each( list, function( key, item ) {
+ if ( key !== '' ) {
+ key = $.type( item ) === 'object' ? item.key : key;
+ item = $.type( item ) === 'object' ? item.label : item;
+ elements.push(
+ html.element( 'input', {
+ 'type': 'checkbox',
+ 'checked': 'checked',
+ 'id': item,
+ 'name': item,
+ 'value': key
+ }, item )
+ );
+ }
+ } );
+ return '<ul><li class="' + checkListClass + '-item">'+ elements.join('</li><li class="' + checkListClass + '-item">') + '</li></ul>';
+ }
+
+ }
+
+ this.checkList = $( checkList( options.list, options['class'] ) ).appendTo( el );
+
+ // Create element and the bind click event
+ self.checkList = this.checkList
+ .on( 'click', ':checkbox', function( event ){
+ var that = $( this );
+ if ( $.isFunction( options.click ) ){
+ options.click( event, {
+ checked: that.is( ':checked' ),
+ value: that.attr( 'value' ),
+ name: that.attr( 'name' )
+ } )
+ }
+ } );
+
+ return options.show || options.show === undefined ? self.checkList.show() : self.checkList.hide();
+ },
+
+ /**
+ * Create select elements from an array
+ *
+ * @since 1.9
+ *
+ * @param {array} options
+ *
+ * @return object
+ */
+ selectlist: function( options ) {
+ var self = this,
+ el = self.element;
+
+ // Returns a list of elements
+ function selectList( list ) {
+ if ( list !== undefined ) {
+ var dropdown = '';
+ $.each( list, function( key, item ) {
+ key = $.type( item ) === 'object' ? item.key : key;
+ item = $.type( item ) === 'object' ? item.label : item;
+ dropdown = dropdown + html.element( 'option', {
+ 'value': key,
+ 'selected': options.selectedAll
+ },item );
+ } );
+
+ return html.element( 'select', {
+ 'id': options['class'],
+ 'class': options['class'],
+ 'multiple': options.multiple || false,
+ 'size': options.multiple ? ( list.length > 5 ? 5 : list.length ) : 1
+ }, new html.Raw( ( options.null ? html.element( 'option', { }, '' ) : '' ) + dropdown )
+ );
+ }
+ }
+
+ // Create element and bind the click event
+ this.selectList = $( selectList( options.list ) ).appendTo( el );
+ self.selectList = this.selectList
+ .on( 'change', function( event ){
+ var that = $( this );
+ if ( $.isFunction( options.change ) ){
+ options.change( event, {
+ selected: that.is( ':selected' ),
+ value: that.attr( 'value' )
+ } );
+ }
+ } );
+
+ return options.show || options.show === undefined ? self.selectList.show() : self.selectList.hide();
+ },
+
+ /**
+ * Remove objects
+ *
+ * @since 1.9
+ */
+ destroy: function() {
+ $.Widget.prototype.destroy.apply( this );
+ }
+ } );
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/widgets/ext.srf.widgets.panel.js b/SemanticResultFormats/resources/widgets/ext.srf.widgets.panel.js
new file mode 100644
index 00000000..52ca2047
--- /dev/null
+++ b/SemanticResultFormats/resources/widgets/ext.srf.widgets.panel.js
@@ -0,0 +1,107 @@
+/**
+ * SRF JavaScript srf.panel widget
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * Html element generation
+ *
+ * @type object
+ */
+ var html = mw.html;
+
+ /**
+ * $.widget factory method
+ *
+ * @since 1.9
+ */
+ $.widget( 'srf.panel', {
+
+ /**
+ * Create method which runs once (during initialization)
+ *
+ * @return object
+ */
+ _create: function() {
+ var self = this,
+ el = self.element;
+
+ this.panel = $(
+ html.element( 'div', { 'class': self.widgetBaseClass }, '' )
+ ).insertAfter( el );
+ return this.options.show ? this.panel.show() : this.panel.hide();
+ },
+
+ /**
+ * Returns the pane context
+ *
+ * @since 1.9
+ * @return object
+ */
+ getContext: function( ) {
+ return this.panel;
+ },
+
+ /**
+ * Adds a portlet
+ *
+ * @since 1.9
+ * @var options
+ */
+ portlet: function( options ) {
+ var self = this,
+ el = self.element;
+
+ // Specify the pane instance
+ this.panel = this.panel || $();
+
+ // Append
+ this.panelPortlet = $(
+ html.element( 'div', {
+ 'id': self.widgetBaseClass + '-' + options['class'],
+ 'class': options['class'] },
+ new html.Raw( ( options['fieldset'] ? html.element( 'fieldset', {},
+ new html.Raw( html.element( 'legend', { }, options['title'] ) ) ) : ''
+ )
+ )
+ )
+ ).appendTo( this.panel );
+
+ self.panelPortlet = this.panelPortlet;
+ return options.hide ? self.panelPortlet.hide() : self.panelPortlet.show() ;
+ },
+
+ /**
+ * Depending on its state toggle show/hide
+ *
+ * @since 1.9
+ */
+ toggle: function() {
+ return this.panel.css( 'display' ) === 'none' ? this.panel.fadeIn( 'slow' ): this.panel.hide();
+ },
+
+ /**
+ * Remove objects
+ *
+ * @since 1.9
+ * @var options
+ */
+ destroy: function( options ) {
+ if ( options['class'] ){
+ $( '.' + options['class'] , this.panel ).remove();
+ } else{
+ $.Widget.prototype.destroy.apply( this );
+ }
+ }
+ } );
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file
diff --git a/SemanticResultFormats/resources/widgets/ext.srf.widgets.parameters.js b/SemanticResultFormats/resources/widgets/ext.srf.widgets.parameters.js
new file mode 100644
index 00000000..f2ec074a
--- /dev/null
+++ b/SemanticResultFormats/resources/widgets/ext.srf.widgets.parameters.js
@@ -0,0 +1,128 @@
+/**
+ * SRF JavaScript for srf.parameters widget
+ *
+ * @since 1.9
+ * @release 0.1
+ *
+ * @file
+ * @ingroup SRF
+ *
+ * @licence GNU GPL v2 or later
+ * @author mwjames
+ */
+( function( $, mw, srf ) {
+ 'use strict';
+
+ /**
+ * Html element and utility objects
+ *
+ * @type object
+ */
+ var html = mw.html;
+
+ /**
+ * $.widget factory method
+ *
+ * @since 1.9
+ */
+ $.widget( 'srf.parameters', {
+
+ _init: function() {
+ var self = this,
+ el = self.element;
+ return el;
+ },
+
+ /**
+ * Limit parameter
+ *
+ * @since 1.9
+ */
+ limit: function( options ) {
+ var self = this,
+ el = self.element;
+
+ function element(){
+ return html.element( 'div', { 'class': 'limit-parameter' }, new html.Raw(
+ html.element( 'div', { 'class' : 'parameter-section' }, mw.msg( 'srf-ui-widgets-label-parameter-limit' ) ) +
+ html.element( 'span', { 'class': 'value' }, '' ) +
+ html.element( 'span', { 'class': 'count' }, '' ) + '<br/>' +
+ html.element( 'div', { 'class': 'slider' }, '' )
+ ) );
+ }
+
+ this.limitParameter = $( element() ).appendTo( el );
+
+ // Slider instance
+ this.limitParameter.find( '.slider' ).slider( {
+ range: 'min',
+ value: options.limit,
+ min: 1,
+ max: options.max,
+ step: options.step,
+ slide: function( event, ui ){
+ self._limitParameterUpdate( { limit: self._limitConstrain( ui.value, options.max ) } );
+ },
+ change: function( event, ui ){
+ if ( $.isFunction( options.change ) ){
+ options.change( event, { value : self._limitConstrain( ui.value, options.max ) } );
+ }
+ }
+ } );
+
+ // Show initial limit/count
+ this._limitParameterUpdate( { limit: options.limit, count: options.count } );
+ },
+
+ /**
+ * Limit/count value update
+ *
+ * @since 1.9
+ */
+ _limitParameterUpdate: function( options ){
+ var self = this,
+ el = self.element;
+
+ $( '.value', self.element ).text( options.limit );
+
+ if ( options.count ){
+ $( '.count', self.element ).text( '[ ' + options.count + ' ]' );
+ } else {
+ $( '.count', self.element ).text( '' );
+ }
+ },
+
+ _limitConstrain: function( value, max ){
+ return value > 1 ? value >= max ? max : value - 1 : value;
+ },
+
+ /**
+ * Change options
+ *
+ * @param name
+ * @param value
+ */
+ _setOption: function ( name, value ) {
+ switch( name ){
+ case 'limit':
+ this._limitParameterUpdate( value );
+ break;
+ }
+ $.Widget.prototype._setOption.apply( this, arguments );
+ },
+
+ /**
+ * Remove objects
+ *
+ * @since 1.9
+ * @var options
+ */
+ destroy: function( options ) {
+ if ( options['class'] ){
+ $( '.' + options['class'] , this.pane ).remove();
+ } else{
+ $.Widget.prototype.destroy.apply( this );
+ }
+ }
+ } );
+} )( jQuery, mediaWiki, semanticFormats ); \ No newline at end of file