Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #186 from MapofLife/feature/new-feature-metadata

Feature/new feature metadata
  • Loading branch information...
commit 540adeb3ec13b7b35e1bad8b43f21f1b4fee7a34 2 parents 912ec9f + 51afd49
@jmalczyk jmalczyk authored
View
2  app/compile.sh
@@ -4,6 +4,6 @@ cd js
rm -rf ../static/js/mol.js
-cat mol.js mol.core.js mol.bus.js mol.mvp.js mol.services.js mol.services.cartodb.js mol.map.js mol.map.loading.js mol.map.layers.js mol.map.menu.js mol.map.results.js mol.map.search.js mol.map.tiles.js mol.map.dashboard.js mol.map.query.js mol.map.basemap.js mol.map.metadata.js mol.map.splash.js mol.map.help.js mol.map.status.js mol.map.styler.js mol.map.images.js mol.map.boot.js > ../static/js/mol.js
+cat mol.js mol.core.js mol.bus.js mol.mvp.js mol.services.js mol.services.cartodb.js mol.map.js mol.map.loading.js mol.map.layers.js mol.map.menu.js mol.map.results.js mol.map.search.js mol.map.tiles.js mol.map.dashboard.js mol.map.feature.js mol.map.query.js mol.map.basemap.js mol.map.metadata.js mol.map.splash.js mol.map.help.js mol.map.status.js mol.map.styler.js mol.map.images.js mol.map.boot.js > ../static/js/mol.js
cd ..
View
93 app/css/widgets.css
@@ -292,6 +292,25 @@ white-space: nowrap;
line-height: 25px;
}
+.mol-LayerControl-Layers .layers .layersHeader .title {
+ margin-left: 20px;
+}
+
+.mol-LayerControl-Layers .layers .layersHeader button.toggleBtn {
+ width:32px;
+ height: 22px;
+ color: #fff;
+ padding: 3px;
+}
+
+.mol-LayerControl-Layers .layers .layersHeader button.selected {
+ border: 3px solid rgba(255, 100, 88, .45);
+ border-radius:5px;
+ -moz-border-radius:5px;
+ -ms-border-radius:5px;
+ padding:0px;
+}
+
.mol-LayerControl-Layers .layers {
border-radius: 3px;
-moz-border-radius: 3px;
@@ -1545,3 +1564,77 @@ div.cartodb_infowindow div.top p {
max-height: 40px;
white-space: normal;
}
+
+/*
+ * New Feature Metadata
+ *
+ */
+
+div.mol-Map-FeatureDisplay.ui-dialog-content.ui-widget-content {
+ padding: 0.5em 0.5em;
+}
+
+.mol-Map-FeatureDisplay .ui-accordion .ui-accordion-header {
+ background: rgba(29, 43, 82, 0.75);
+}
+
+.mol-Map-FeatureDisplay .ui-accordion .ui-accordion-header .ui-icon{
+ left: 0em;
+}
+
+.mol-Map-FeatureDisplay .ui-accordion .ui-accordion-header a {
+ font-size: 0.7em;
+ padding: 0.2em 0.2em 0.2em 0.3em;
+ color: #FFF;
+ padding-left: 1.4em;
+}
+
+.mol-Map-FeatureDisplay .ui-accordion .ui-accordion-content {
+ font-size: 12px;
+ font-weight: normal;
+ font-style: normal;
+ padding: 0.4em 0.4em;
+ overflow-y: scroll;
+ max-height: 250px;
+}
+
+.mol-Map-FeatureDisplay .ui-accordion .ui-accordion-content p {
+ margin: 0.2em;
+}
+
+.mol-Map-FeatureDisplay .ui-accordion .ui-accordion-content div.itemPair {
+ margin-top: 1px;
+ maring-bottom: 1px;
+}
+
+.mol-Map-FeatureDisplay .ui-accordion .ui-accordion-content div.featureItem {
+ width: 49%;
+ float: left;
+ font-weight: bold;
+ text-align: right;
+ margin-right: 2px;
+}
+.mol-Map-FeatureDisplay .ui-accordion .ui-accordion-content div.featureData {
+ width: 50%;
+ float: left;
+ text-align: left;
+ min-height: 15px;
+}
+.mol-Map-FeatureDisplay .ui-accordion .ui-accordion-content div.featureData SUB,
+.mol-Map-FeatureDisplay .ui-accordion .ui-accordion-content div.featureData SUP {
+ line-height: 0;
+}
+
+.mol-Map-FeatureDisplay .ui-accordion-header button {
+ text-align: center;
+ width: 18px;
+ height: 18px;
+ padding: 0px;
+ padding-top: 1px;
+}
+
+.mol-Map-FeatureDisplay .ui-accordion-header a img{
+ width: 16px;
+ height: 16px;
+}
+
View
599 app/js/lib/cartodb-gmapsv3-new.js
@@ -1,599 +0,0 @@
-/**
- * @name cartodb-gmapsv3 for Google Maps V3 API
- * @version 0.2 [December 14, 2011]
- * @author: xavijam@gmail.com
- * @fileoverview <b>Author:</b> xavijam@gmail.com<br/> <b>Licence:</b>
- * Licensed under <a
- * href="http://opensource.org/licenses/mit-license.php">MIT</a>
- * license.<br/> This library lets you use CartoDB with google
- * maps v3.
- *
- */
-/**
- * @name google
- * @class The fundamental namespace for Google APIs
- */
-/**
- * @name google.maps
- * @class The fundamental namespace for Google Maps V3 API
- */
- /*
- * - Map style of cartodb
- * - Infowindow of cartodb
- * - Tiles style of cartodb
- */
-
-// Namespace
-var CartoDB = CartoDB || {};
-
-(function($) {
- if (typeof(google.maps.CartoDBLayer) === "undefined") {
- /**
- * @params {}
- * map_canvas - Gmapsv3 canvas id (necesary for showing the infowindow)
- * map - Your gmapsv3 map
- * user_name - CartoDB user name
- * table_name CartoDB table name
- * query If you want to apply any sql sentence to the table...
- * tile_style - If you want to add other style to the layer
- * map_style - If you want to see the map styles created on cartodb (opcional - default = false)
- * infowindow - If you want to see infowindows when click in a geometry (opcional - default = false)
- * auto_bound - Let cartodb auto-bound-zoom in the map (opcional - default = false)
- * debug - Do you want to debug the library? Set to true
- */
-
- google.maps.CartoDBLayer = function (params) {
-
- this.params = params;
- this.params.feature = params.infowindow;
-
- if (this.params.map_style) setCartoDBMapStyle(this.params); // Map style? ok, let's style.
- if (this.params.auto_bound) autoBound(this.params); // Bounds? CartoDB does it.
-
- //if (this.params.infowindow) {
- addWaxCartoDBTiles(this.params);
- //} else {
- // addSimpleCartoDBTiles(this.params); // Always add cartodb tiles, simple or with wax.
- //}
-
- this.params.visible = true;
- this.params.active = true;
-
- // Zoom to cartodb geometries
- function autoBound(params) {
- // Zoom to your geometries
- // If the table is private you can't auto zoom without being authenticated
- if (!params.map_key) {
- $.ajax({
- url:'http://'+params.user_name+'.cartodb.com/api/v2/sql/?q='+escape('select ST_Extent(the_geom) from '+ params.table_name),
- dataType: 'jsonp',
- timeout: 2000,
- callbackParameter: 'callback',
- success: function(result) {
- if (result.rows[0].st_extent!=null) {
- var coordinates = result.rows[0].st_extent.replace('BOX(','').replace(')','').split(',');
-
- var coor1 = coordinates[0].split(' ');
- var coor2 = coordinates[1].split(' ');
- var bounds = new google.maps.LatLngBounds();
-
- // Check bounds
- if (coor1[0] > 180 || coor1[0] < -180 || coor1[1] > 90 || coor1[1] < -90
- || coor2[0] > 180 || coor2[0] < -180 || coor2[1] > 90 || coor2[1] < -90) {
- coor1[0] = '-30';
- coor1[1] = '-50';
- coor2[0] = '110';
- coor2[1] = '80';
- }
-
- bounds.extend(new google.maps.LatLng(coor1[1],coor1[0]));
- bounds.extend(new google.maps.LatLng(coor2[1],coor2[0]));
-
- params.map.fitBounds(bounds);
- }
- },
- error: function(e,msg) {
- params.debug && console.debug('Error setting table bounds: ' + msg);
- }
- });
- }
- }
-
- // Set the map styles of your cartodb table/map
- function setCartoDBMapStyle(params) {
- $.ajax({
- url: 'http://' + params.user_name + '.cartodb.com/tiles/' + params.table_name + '/map_metadata?'+ 'map_key=' + (params.map_key || ''),
- dataType: 'jsonp',
- timeout: 2000,
- callbackParameter: 'callback',
- success: function(result) {
- var map_style = $.parseJSON(result.map_metadata);
-
- if (!map_style || map_style.google_maps_base_type=="roadmap") {
- params.map.setOptions({mapTypeId: google.maps.MapTypeId.ROADMAP});
- } else if (map_style.google_maps_base_type=="satellite") {
- params.map.setOptions({mapTypeId: google.maps.MapTypeId.SATELLITE});
- } else if (map_style.google_maps_base_type=="terrain") {
- params.map.setOptions({mapTypeId: google.maps.MapTypeId.TERRAIN});
- } else {
- var mapStyles = [ { stylers: [ { saturation: -65 }, { gamma: 1.52 } ] },{ featureType: "administrative", stylers: [ { saturation: -95 }, { gamma: 2.26 } ] },{ featureType: "water", elementType: "labels", stylers: [ { visibility: "off" } ] },{ featureType: "administrative.locality", stylers: [ { visibility: "off" } ] },{ featureType: "road", stylers: [ { visibility: "simplified" }, { saturation: -99 }, { gamma: 2.22 } ] },{ featureType: "poi", elementType: "labels", stylers: [ { visibility: "off" } ] },{ featureType: "road.arterial", stylers: [ { visibility: "off" } ] },{ featureType: "road.local", elementType: "labels", stylers: [ { visibility: "off" } ] },{ featureType: "transit", stylers: [ { visibility: "off" } ] },{ featureType: "road", elementType: "labels", stylers: [ { visibility: "off" } ] },{ featureType: "poi", stylers: [ { saturation: -55 } ] } ];
- map_style.google_maps_customization_style = mapStyles;
- params.map.setOptions({mapTypeId: google.maps.MapTypeId.ROADMAP});
- }
-
- // Custom tiles
- if (!map_style) {
- map_style = {google_maps_customization_style: []};
- }
- params.map.setOptions({styles: map_style.google_maps_customization_style});
- },
- error: function(e, msg) {
- params.debug && console.debug('Error setting map style: ' + msg);
- }
- });
- }
-
- // Add cartodb tiles to the map
- function addSimpleCartoDBTiles(params) {
- // Add the cartodb tiles
- var cartodb_layer = {
- getTileUrl: function(coord, zoom) {
- //return 'http://' + params.user_name +
- //'.cartodb.com/tiles/' + params.table_name +
- //'/'+zoom+'/'+coord.x+'/'+coord.y+'.png?sql='+params.query
- //+ '&map_key=' + (params.map_key || '') + '&style=' +
- //((params.tile_style)?encodeURIComponent(params.tile_style):'');
- return 'http://' + params.hostname+ '/tiles/' + params.table_name + '/'+zoom+'/'+coord.x+'/'+coord.y+'.png?sql='+params.query + '&map_key=' + (params.map_key || '') + '&style=' + ((params.tile_style)?encodeURIComponent(params.tile_style):'');
- },
- tileSize: new google.maps.Size(256, 256),
- name: params.tile_name,
- description: false
- };
-
- params.layer = new google.maps.ImageMapType(cartodb_layer);
- params.map.overlayMapTypes.insertAt(0,params.layer);
- }
-
- // Add cartodb tiles to the map
- function addWaxCartoDBTiles(params) {
- // interaction placeholder
- var currentCartoDbId;
-
- params.tilejson = generateTileJson(params);
- params.infowindow = new CartoDB.Infowindow(params);
- params.cache_buster = 0;
-
- params.waxOptions = {
- callbacks: {
- out: function(){
- params.map.setOptions({draggableCursor: 'default'});
- },
- over: function(feature, div, opt3, evt){
- params.map.setOptions({draggableCursor: 'pointer'});
- },
- click: function(feature, div, opt3, evt){
- // If there are more than one cartodb layer, close all possible infowindows
- params.infowindow.hideAll();
- params.infowindow.open(feature,evt.latLng);
- }
- },
- clickAction: 'full'
- };
-
- params.layer = new wax.g.connector(params.tilejson);
- params.layer.interaction = wax.g.interaction(params.map, params.tilejson, params.waxOptions);
-
- params.map.overlayMapTypes.insertAt(0,params.layer);
-
- }
-
- // Refresh wax interaction
- function refreshWax(params,sql) {
- if (params.infowindow) {
- params.cache_buster++;
- params.query = sql;
- params.tilejson = generateTileJson(params);
-
- // Remove old wax
- removeOldLayer(params.map,params.layer);
-
- // Setup new wax
- params.tilejson.grids = wax.util.addUrlData(params.tilejson.grids_base, 'cache_buster=' + params.cache_buster);
-
- // Add map tiles
- params.layer = new wax.g.connector(params.tilejson);
- params.map.overlayMapTypes.insertAt(0,params.layer);
-
- // Add interaction
- params.interaction.remove();
- params.interaction = wax.g.interaction(params.map, params.tilejson, params.waxOptions);
- }
- }
-
- // Refresh tiles
- function refreshTiles(params,sql) {
- // If you are not using interaction on the tiles... let's update your tiles
- if (!params.infowindow) {
-
- // First remove previous cartodb - tiles.
- removeOldLayer(params.map,params.layer);
-
- // Then add the cartodb tiles
- params.query = sql;
- var cartodb_layer = {
- getTileUrl: function(coord, zoom) {
- return 'http://' + params.hostname + '/tiles/' + params.table_name + '/'+zoom+'/'+coord.x+'/'+coord.y+'.png?sql='+params.query + '&map_key=' + (params.map_key || '') + '&style=' + (encodeURIComponent(params.tile_style) || '');
- },
- tileSize: new google.maps.Size(256, 256),
- name: params.tile_name,
- description: false
- };
-
- params.layer = new google.maps.ImageMapType(cartodb_layer);
- params.map.overlayMapTypes.insertAt(0,params.layer);
- }
- }
-
- function generateTileJson(params) {
- var core_url = 'http://' + params.hostname;
- var base_url = core_url + '/tiles/' + params.style_table_name + '/{z}/{x}/{y}';
- var tile_url = base_url + '.png?cache_buster=0';
- var grid_url = base_url + '.grid.json';
-
- // SQL?
- if (params.query) {
- var query = 'sql=' + params.query;
- tile_url = wax.util.addUrlData(tile_url, query);
- grid_url = wax.util.addUrlData(grid_url, 'sql=' + params.info_query);
- }
-
- // Map key ?
- if (params.map_key) {
- var map_key = 'map_key=' + params.map_key;
- tile_url = wax.util.addUrlData(tile_url,map_key);
- grid_url = wax.util.addUrlData(grid_url,map_key);
- }
-
- // Tiles style ?
- if (params.tile_style) {
- var style = 'style=' + encodeURIComponent(params.tile_style);
- tile_url = wax.util.addUrlData(tile_url,style);
- grid_url = wax.util.addUrlData(grid_url,style);
- }
-
- // Build up the tileJSON
- // TODO: make a blankImage a real 'empty tile' image
- return {
- blankImage: 'blank_tile.png',
- tilejson: '1.0.0',
- scheme: 'xyz',
- tiles: [tile_url],
- grids: [grid_url],
- tiles_base: tile_url,
- grids_base: grid_url,
- name: params.tile_name,
- description: true,
- opacity: params.opacity,
- formatter: function(options, data) {
- currentCartoDbId = data.cartodb_id;
- return data.cartodb_id;
- },
- cache_buster: function(){
- return params.cache_buster;
- }
- };
- }
-
- // Remove old cartodb layer added (wax or imagemaptype)
- function removeOldLayer(map,layer) {
- if (layer) {
- var pos = -1;
- map.overlayMapTypes.forEach(function(map_type,i){
- if (layer == map_type && map_type.name == layer.name && map_type.description == layer.description) {
- pos = i;
- }
- });
- if (pos!=-1)
- map.overlayMapTypes.removeAt(pos);
- layer = null;
- }
- }
-
-
- // Update tiles & interactivity layer;
- google.maps.CartoDBLayer.prototype.update = function(sql) {
- // Hide the infowindow
- if (this.params.infowindow)
- this.params.infowindow.hide();
- // Refresh wax
- refreshWax(this.params,sql);
- // Refresh tiles
- refreshTiles(this.params,sql);
-
- this.params.active = true;
- this.params.visible = true;
- };
-
- // Destroy layers from the map
- google.maps.CartoDBLayer.prototype.destroy = function() {
- // First remove previous cartodb - tiles.
- removeOldLayer(this.params.map,this.params.layer);
-
- if (this.params.infowindow) {
- // Remove wax interaction
- this.params.interaction.remove();
- this.params.infowindow.hide();
- }
-
- this.params.active = false;
- };
-
- // Hide layers from the map
- google.maps.CartoDBLayer.prototype.hide = function() {
- this.destroy();
- this.params.visible = false;
- };
-
- // Show layers from the map
- google.maps.CartoDBLayer.prototype.show = function() {
- if (!this.params.visible || !this.params.active) {
- this.update(this.params.query);
- this.params.visible = true;
- }
- };
-
- // CartoDB layer visible?
- google.maps.CartoDBLayer.prototype.isVisible = function() {
- return this.params.visible;
- };
- };
- }
-
- /**
- * CartoDB.Infowindow
- * @xavijam
- **/
- CartoDB.Infowindow = function (params) {
- this.latlng_ = new google.maps.LatLng(0,0);
- this.feature_;
- this.map_ = params.map;
- this.columns_;
- this.offsetHorizontal_ = -107;
- this.width_ = 214;
- this.setMap(params.map);
- this.params_ = params;
- };
-
- CartoDB.Infowindow.prototype = new google.maps.OverlayView();
-
- CartoDB.Infowindow.prototype.draw = function() {
- var me = this;
-
- var div = this.div_;
- if (!div) {
- div = this.div_ = document.createElement('DIV');
- div.className = "cartodb_infowindow";
-
- div.innerHTML = '<a href="#close" class="close">x</a>'+
- '<div class="outer_top">'+
- '<div class="top">'+
- '</div>'+
- '</div>'+
- '<div class="bottom">'+
- '</div>';
-
- $(div).find('a.close').click(function(ev){
- ev.preventDefault();
- ev.stopPropagation();
- me.hide();
- });
-
- google.maps.event.addDomListener(div,'click',function(ev){ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;});
- google.maps.event.addDomListener(div,'dblclick',function(ev){ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;});
- google.maps.event.addDomListener(div,'mousedown',function(ev){ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;});
- google.maps.event.addDomListener(div,'mouseup',function(ev){ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;});
- google.maps.event.addDomListener(div,'mousewheel',function(ev){ev.stopPropagation();});
- google.maps.event.addDomListener(div,'DOMMouseScroll',function(ev){ev.stopPropagation();});
-
- var panes = this.getPanes();
- panes.floatPane.appendChild(div);
-
- div.style.opacity = 0;
- }
-
- var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
- if (pixPosition) {
- div.style.width = this.width_ + 'px';
- div.style.left = (pixPosition.x - 49) + 'px';
- var actual_height = - $(div).height();
- div.style.top = (pixPosition.y + actual_height + 5) + 'px';
- }
- };
-
- CartoDB.Infowindow.prototype.setPosition = function() {
- if (this.div_) {
- var div = this.div_;
- var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
- if (pixPosition) {
- div.style.width = this.width_ + 'px';
- div.style.left = (pixPosition.x - 49) + 'px';
- var actual_height = - $(div).height();
- div.style.top = (pixPosition.y + actual_height + 10) + 'px';
- }
- this.show();
- }
- };
-
- CartoDB.Infowindow.prototype.open = function(feature,latlng){
- var that = this
- , infowindow_sql = 'SELECT contact, provider, scientificname, seasonality, type FROM ' + this.params_.table_name + ' WHERE cartodb_id=' + feature;
- that.feature_ = feature;
-
- if (this.params_.table_name == 'gbif_import') {
- infowindow_sql = "SELECT " +
- "'Point observation' AS \"Type\", " +
- "'GBIF' AS \"Source\", " +
- "scientificname AS \"Species name\", " +
- "CollectionID AS \"Collection\", " +
- "CONCAT('<a target=\"_gbif\" onclick=\"window.open(this.href)\" href=\"http://data.gbif.org/occurrences/',identifier,'\">',identifier, '</a>') as \"Source ID\", " +
- "identifier AS \"oid\", " +
- "SurveyStartDate as \"Observed on\" " +
- "FROM {0} WHERE cartodb_id={1}".format("gbif_import", feature);
- } else {
- infowindow_sql = "SELECT " +
- " p.scientificname AS \"Species name\", " +
- " pv.title AS \"Source\", " +
- " t.title AS \"Type\", " +
- " CASE WHEN p.seasonality = Null THEN 'unknown' ELSE TEXT(p.seasonality) END AS \"Seasonality\", " +
- " p.regionname AS \"Region\", " +
- " e.ecoregion_code AS \"Ecoregion Code\", " +
- " pv.pubdate as \"Date\" " +
- " FROM polygons p " +
- "LEFT JOIN types t " +
- " ON p.type=t.type " +
- "LEFT JOIN providers pv " +
- " ON p.provider = pv.provider " +
- "LEFT JOIN ecoregion_species e " +
- " ON p.ecoregion_list_id = e.id " +
- "WHERE p.cartodb_id={0}".format(feature);
- }
-
- // If the table is private, you can't run any api methods
- if (this.params_.feature!=true) {
- infowindow_sql = encodeURIComponent(this.params_.feature.replace('{{feature}}',feature));
- }
-
- if(this.params_.table_name != 'gbif_import') {
- $.post(
- 'cache/get',
- {sql: infowindow_sql, key: 'polygons-'+feature},
- function(result) {
- positionateInfowindow(result.rows[0],latlng);
- }
- );
- } else {
- $.post(
- 'cache/get',
- {sql: infowindow_sql, key: 'polygons-'+feature},
- function(result) {
- getGBIFOccurence(result.rows[0].oid, result, latlng);
- }
- );
- }
-
- function getGBIFOccurence(oid, cdb_result, latlng) {
- $.post (
- 'gbif/occurrence',
- {oid : oid},
- function(response) {
- var variables = [];
- _.each(
- data.rows,
- function(row) {
- variables.push(row);
- }
- )
- positionateWindow(variables, latlng);
- }
- )
- }
-
- function positionateInfowindow(variables,center) {
- if (that.div_) {
- var div = that.div_;
- // Get latlng position
- that.latlng_ = latlng;
-
- // Remove the unnecessary html
- $('div.cartodb_infowindow div.outer_top div.top').html('');
- $('div.cartodb_infowindow div.outer_top div.bottom label').html('');
-
- // List all the new variables
- for (p in variables) {
- if (p!='cartodb_id' && p!='cdb_centre' && p!='the_geom_webmercator' && variables[p]!=null && variables[p]!='') {
- $('div.cartodb_infowindow div.outer_top div.top').append('<label>'+p+'</label><p class="'+((variables[p]!=null && variables[p]!='')?'':'empty')+'">'+(variables[p] || 'empty')+'</p>');
- }
- }
-
- // Show cartodb_id?
- // if (variables['cartodb_id']) {
- // $('div.cartodb_infowindow div.bottom label').html('id: <strong>'+feature+'</strong>');
- // }
-
- that.moveMaptoOpen();
- that.setPosition();
- }
- }
- };
-
- CartoDB.Infowindow.prototype.hide = function() {
- if (this.div_) {
- var div = this.div_;
- $(div).animate({
- top: '+=' + 10 + 'px',
- opacity: 0},
- 100, 'swing',
- function () {
- div.style.visibility = "hidden";
- }
- );
- }
- };
-
- CartoDB.Infowindow.prototype.show = function() {
- if (this.div_) {
- var div = this.div_;
- div.style.opacity = 0;
- div.style.visibility = "visible";
- $(div).animate({
- top: '-=' + 10 + 'px',
- opacity: 1},
- 250
- );
- }
- };
-
- CartoDB.Infowindow.prototype.hideAll = function() {
- $('div.cartodb_infowindow').css('visibility','hidden');
- };
-
- CartoDB.Infowindow.prototype.isVisible = function(marker_id) {
- if (this.div_) {
- var div = this.div_;
- if (div.style.visibility == 'visible' && this.feature_!=null) {
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- };
-
- CartoDB.Infowindow.prototype.transformGeoJSON = function(str) {
- var json = $.parseJSON(str);
- return new google.maps.LatLng(json.coordinates[1],json.coordinates[0]);
- };
-
- CartoDB.Infowindow.prototype.moveMaptoOpen = function() {
- var left = 0;
- var top = 0;
- var div = this.div_;
- var pixPosition = this.getProjection().fromLatLngToContainerPixel(this.latlng_);
-
- if ((pixPosition.x + this.offsetHorizontal_) < 0) {
- left = (pixPosition.x + this.offsetHorizontal_ - 20);
- }
-
- if ((pixPosition.x + 180) >= ($('#'+this.params_.map_canvas).width())) {
- left = (pixPosition.x + 180 - $('#'+this.params_.map_canvas).width());
- }
-
- if ((pixPosition.y - $(div).height()) < 0) {
- top = (pixPosition.y - $(div).height() - 30);
- }
-
- this.map_.panBy(left,top);
- };
-
-})(jQuery);
View
549 app/js/lib/cartodb-gmapsv3.js
@@ -1,549 +0,0 @@
-/**
- * @name cartodb-gmapsv3 for Google Maps V3 API
- * @version 0.2 [December 14, 2011]
- * @author: xavijam@gmail.com
- * @fileoverview <b>Author:</b> xavijam@gmail.com<br/> <b>Licence:</b>
- * Licensed under <a
- * href="http://opensource.org/licenses/mit-license.php">MIT</a>
- * license.<br/> This library lets you use CartoDB with google
- * maps v3.
- *
- */
-/**
- * @name google
- * @class The fundamental namespace for Google APIs
- */
-/**
- * @name google.maps
- * @class The fundamental namespace for Google Maps V3 API
- */
- /*
- * - Map style of cartodb
- * - Infowindow of cartodb
- * - Tiles style of cartodb
- */
-
-// Namespace
-var CartoDB = CartoDB || {};
-
-(function($) {
- if (typeof(google.maps.CartoDBLayer) === "undefined") {
- /**
- * @params {}
- * map_canvas - Gmapsv3 canvas id (necesary for showing the infowindow)
- * map - Your gmapsv3 map
- * user_name - CartoDB user name
- * table_name CartoDB table name
- * query If you want to apply any sql sentence to the table...
- * tile_style - If you want to add other style to the layer
- * map_style - If you want to see the map styles created on cartodb (opcional - default = false)
- * infowindow - If you want to see infowindows when click in a geometry (opcional - default = false)
- * auto_bound - Let cartodb auto-bound-zoom in the map (opcional - default = false)
- * debug - Do you want to debug the library? Set to true
- */
-
- google.maps.CartoDBLayer = function (params) {
-
- this.params = params;
- this.params.feature = params.infowindow;
-
- if (this.params.map_style) setCartoDBMapStyle(this.params); // Map style? ok, let's style.
- if (this.params.auto_bound) autoBound(this.params); // Bounds? CartoDB does it.
-
- //if (this.params.infowindow) {
- addWaxCartoDBTiles(this.params);
- //} else {
- // addSimpleCartoDBTiles(this.params); // Always add cartodb tiles, simple or with wax.
- //}
-
- this.params.visible = true;
- this.params.active = true;
-
- // Zoom to cartodb geometries
- function autoBound(params) {
- // Zoom to your geometries
- // If the table is private you can't auto zoom without being authenticated
- if (!params.map_key) {
- $.ajax({
- url:'http://'+params.user_name+'.cartodb.com/api/v2/sql/?q='+escape('select ST_Extent(the_geom) from '+ params.table_name),
- dataType: 'jsonp',
- timeout: 2000,
- callbackParameter: 'callback',
- success: function(result) {
- if (result.rows[0].st_extent!=null) {
- var coordinates = result.rows[0].st_extent.replace('BOX(','').replace(')','').split(',');
-
- var coor1 = coordinates[0].split(' ');
- var coor2 = coordinates[1].split(' ');
- var bounds = new google.maps.LatLngBounds();
-
- // Check bounds
- if (coor1[0] > 180 || coor1[0] < -180 || coor1[1] > 90 || coor1[1] < -90
- || coor2[0] > 180 || coor2[0] < -180 || coor2[1] > 90 || coor2[1] < -90) {
- coor1[0] = '-30';
- coor1[1] = '-50';
- coor2[0] = '110';
- coor2[1] = '80';
- }
-
- bounds.extend(new google.maps.LatLng(coor1[1],coor1[0]));
- bounds.extend(new google.maps.LatLng(coor2[1],coor2[0]));
-
- params.map.fitBounds(bounds);
- }
- },
- error: function(e,msg) {
- params.debug && console.debug('Error setting table bounds: ' + msg);
- }
- });
- }
- }
-
- // Set the map styles of your cartodb table/map
- function setCartoDBMapStyle(params) {
- $.ajax({
- url: 'http://' + params.user_name + '.cartodb.com/tiles/' + params.table_name + '/map_metadata?'+ 'map_key=' + (params.map_key || ''),
- dataType: 'jsonp',
- timeout: 2000,
- callbackParameter: 'callback',
- success: function(result) {
- var map_style = $.parseJSON(result.map_metadata);
-
- if (!map_style || map_style.google_maps_base_type=="roadmap") {
- params.map.setOptions({mapTypeId: google.maps.MapTypeId.ROADMAP});
- } else if (map_style.google_maps_base_type=="satellite") {
- params.map.setOptions({mapTypeId: google.maps.MapTypeId.SATELLITE});
- } else if (map_style.google_maps_base_type=="terrain") {
- params.map.setOptions({mapTypeId: google.maps.MapTypeId.TERRAIN});
- } else {
- var mapStyles = [ { stylers: [ { saturation: -65 }, { gamma: 1.52 } ] },{ featureType: "administrative", stylers: [ { saturation: -95 }, { gamma: 2.26 } ] },{ featureType: "water", elementType: "labels", stylers: [ { visibility: "off" } ] },{ featureType: "administrative.locality", stylers: [ { visibility: "off" } ] },{ featureType: "road", stylers: [ { visibility: "simplified" }, { saturation: -99 }, { gamma: 2.22 } ] },{ featureType: "poi", elementType: "labels", stylers: [ { visibility: "off" } ] },{ featureType: "road.arterial", stylers: [ { visibility: "off" } ] },{ featureType: "road.local", elementType: "labels", stylers: [ { visibility: "off" } ] },{ featureType: "transit", stylers: [ { visibility: "off" } ] },{ featureType: "road", elementType: "labels", stylers: [ { visibility: "off" } ] },{ featureType: "poi", stylers: [ { saturation: -55 } ] } ];
- map_style.google_maps_customization_style = mapStyles;
- params.map.setOptions({mapTypeId: google.maps.MapTypeId.ROADMAP});
- }
-
- // Custom tiles
- if (!map_style) {
- map_style = {google_maps_customization_style: []};
- }
- params.map.setOptions({styles: map_style.google_maps_customization_style});
- },
- error: function(e, msg) {
- params.debug && console.debug('Error setting map style: ' + msg);
- }
- });
- }
-
- // Add cartodb tiles to the map
- function addSimpleCartoDBTiles(params) {
- // Add the cartodb tiles
- var cartodb_layer = {
- getTileUrl: function(coord, zoom) {
- //return 'http://' + params.user_name +
- //'.cartodb.com/tiles/' + params.table_name +
- //'/'+zoom+'/'+coord.x+'/'+coord.y+'.png?sql='+params.query
- //+ '&map_key=' + (params.map_key || '') + '&style=' +
- //((params.tile_style)?encodeURIComponent(params.tile_style):'');
- return 'http://' + params.hostname+ '/tiles/' + params.table_name + '/'+zoom+'/'+coord.x+'/'+coord.y+'.png?sql='+params.query + '&map_key=' + (params.map_key || '') + '&style=' + ((params.tile_style)?encodeURIComponent(params.tile_style):'');
- },
- tileSize: new google.maps.Size(256, 256),
- name: params.tile_name,
- description: false
- };
-
- params.layer = new google.maps.ImageMapType(cartodb_layer);
- params.map.overlayMapTypes.insertAt(0,params.layer);
- }
-
- // Add cartodb tiles to the map
- function addWaxCartoDBTiles(params) {
- // interaction placeholder
- var currentCartoDbId;
-
- params.tilejson = generateTileJson(params);
- params.infowindow = new CartoDB.Infowindow(params);
- params.cache_buster = 0;
-
- params.waxOptions = {
- callbacks: {
- out: function(){
- params.map.setOptions({draggableCursor: 'default'});
- },
- over: function(feature, div, opt3, evt){
- params.map.setOptions({draggableCursor: 'pointer'});
- },
- click: function(feature, div, opt3, evt){
- // If there are more than one cartodb layer, close all possible infowindows
- params.infowindow.hideAll();
- params.infowindow.open(feature,evt.latLng);
- }
- },
- clickAction: 'full'
- };
-
- params.layer = new wax.g.connector(params.tilejson);
- params.layer.interaction = wax.g.interaction(params.map, params.tilejson, params.waxOptions);
-
- params.map.overlayMapTypes.insertAt(0,params.layer);
-
- }
-
- // Refresh wax interaction
- function refreshWax(params,sql) {
- if (params.infowindow) {
- params.cache_buster++;
- params.query = sql;
- params.tilejson = generateTileJson(params);
-
- // Remove old wax
- removeOldLayer(params.map,params.layer);
-
- // Setup new wax
- params.tilejson.grids = wax.util.addUrlData(params.tilejson.grids_base, 'cache_buster=' + params.cache_buster);
-
- // Add map tiles
- params.layer = new wax.g.connector(params.tilejson);
- params.map.overlayMapTypes.insertAt(0,params.layer);
-
- // Add interaction
- params.interaction.remove();
- params.interaction = wax.g.interaction(params.map, params.tilejson, params.waxOptions);
- }
- }
-
- // Refresh tiles
- function refreshTiles(params,sql) {
- // If you are not using interaction on the tiles... let's update your tiles
- if (!params.infowindow) {
-
- // First remove previous cartodb - tiles.
- removeOldLayer(params.map,params.layer);
-
- // Then add the cartodb tiles
- params.query = sql;
- var cartodb_layer = {
- getTileUrl: function(coord, zoom) {
- return 'http://' + params.hostname + '/tiles/' + params.table_name + '/'+zoom+'/'+coord.x+'/'+coord.y+'.png?sql='+params.query + '&map_key=' + (params.map_key || '') + '&style=' + (encodeURIComponent(params.tile_style) || '');
- },
- tileSize: new google.maps.Size(256, 256),
- name: params.tile_name,
- description: false
- };
-
- params.layer = new google.maps.ImageMapType(cartodb_layer);
- params.map.overlayMapTypes.insertAt(0,params.layer);
- }
- }
-
- function generateTileJson(params) {
- var core_url = 'http://' + params.hostname;
- var base_url = core_url + '/tiles/' + params.style_table_name + '/{z}/{x}/{y}';
- var tile_url = base_url + '.png';
- var grid_url = base_url + '.grid.json';
-
- // SQL?
- if (params.query) {
- var query = 'sql=' + params.query;
- tile_url = wax.util.addUrlData(tile_url, query);
- grid_url = wax.util.addUrlData(grid_url, 'sql=' + params.info_query);
- }
-
- // Map key ?
- if (params.map_key) {
- var map_key = 'map_key=' + params.map_key;
- tile_url = wax.util.addUrlData(tile_url,map_key);
- grid_url = wax.util.addUrlData(grid_url,map_key);
- }
-
- // Tiles style ?
- if (params.tile_style) {
- var style = 'style=' + encodeURIComponent(params.tile_style);
- tile_url = wax.util.addUrlData(tile_url,style);
- grid_url = wax.util.addUrlData(grid_url,style);
- }
-
- // Build up the tileJSON
- // TODO: make a blankImage a real 'empty tile' image
- return {
- blankImage: 'blank_tile.png',
- tilejson: '1.0.0',
- scheme: 'xyz',
- tiles: [tile_url],
- grids: [grid_url],
- tiles_base: tile_url,
- grids_base: grid_url,
- name: params.tile_name,
- description: true,
- opacity: params.opacity,
- formatter: function(options, data) {
- currentCartoDbId = data.cartodb_id;
- return data.cartodb_id;
- },
- cache_buster: function(){
- return params.cache_buster;
- }
- };
- }
-
- // Remove old cartodb layer added (wax or imagemaptype)
- function removeOldLayer(map,layer) {
- if (layer) {
- var pos = -1;
- map.overlayMapTypes.forEach(function(map_type,i){
- if (layer == map_type && map_type.name == layer.name && map_type.description == layer.description) {
- pos = i;
- }
- });
- if (pos!=-1)
- map.overlayMapTypes.removeAt(pos);
- layer = null;
- }
- }
-
-
- // Update tiles & interactivity layer;
- google.maps.CartoDBLayer.prototype.update = function(sql) {
- // Hide the infowindow
- if (this.params.infowindow)
- this.params.infowindow.hide();
- // Refresh wax
- refreshWax(this.params,sql);
- // Refresh tiles
- refreshTiles(this.params,sql);
-
- this.params.active = true;
- this.params.visible = true;
- };
-
- // Destroy layers from the map
- google.maps.CartoDBLayer.prototype.destroy = function() {
- // First remove previous cartodb - tiles.
- removeOldLayer(this.params.map,this.params.layer);
-
- if (this.params.infowindow) {
- // Remove wax interaction
- this.params.interaction.remove();
- this.params.infowindow.hide();
- }
-
- this.params.active = false;
- };
-
- // Hide layers from the map
- google.maps.CartoDBLayer.prototype.hide = function() {
- this.destroy();
- this.params.visible = false;
- };
-
- // Show layers from the map
- google.maps.CartoDBLayer.prototype.show = function() {
- if (!this.params.visible || !this.params.active) {
- this.update(this.params.query);
- this.params.visible = true;
- }
- };
-
- // CartoDB layer visible?
- google.maps.CartoDBLayer.prototype.isVisible = function() {
- return this.params.visible;
- };
- };
- }
-
- /**
- * CartoDB.Infowindow
- * @xavijam
- **/
- CartoDB.Infowindow = function (params) {
- this.latlng_ = new google.maps.LatLng(0,0);
- this.feature_;
- this.map_ = params.map;
- this.columns_;
- this.offsetHorizontal_ = -107;
- this.width_ = 214;
- this.setMap(params.map);
- this.params_ = params;
- };
-
- CartoDB.Infowindow.prototype = new google.maps.OverlayView();
-
- CartoDB.Infowindow.prototype.draw = function() {
- var me = this;
-
- var div = this.div_;
- if (!div) {
- div = this.div_ = document.createElement('DIV');
- div.className = "cartodb_infowindow";
-
- div.innerHTML = '<a href="#close" class="close">x</a>'+
- '<div class="outer_top">'+
- '<div class="top">'+
- '</div>'+
- '</div>'+
- '<div class="bottom">'+
- '</div>';
-
- $(div).find('a.close').click(function(ev){
- ev.preventDefault();
- ev.stopPropagation();
- me.hide();
- });
-
- google.maps.event.addDomListener(div,'click',function(ev){ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;});
- google.maps.event.addDomListener(div,'dblclick',function(ev){ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;});
- google.maps.event.addDomListener(div,'mousedown',function(ev){ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;});
- google.maps.event.addDomListener(div,'mouseup',function(ev){ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;});
- google.maps.event.addDomListener(div,'mousewheel',function(ev){ev.stopPropagation();});
- google.maps.event.addDomListener(div,'DOMMouseScroll',function(ev){ev.stopPropagation();});
-
- var panes = this.getPanes();
- panes.floatPane.appendChild(div);
-
- div.style.opacity = 0;
- }
-
- var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
- if (pixPosition) {
- div.style.width = this.width_ + 'px';
- div.style.left = (pixPosition.x - 49) + 'px';
- var actual_height = - $(div).height();
- div.style.top = (pixPosition.y + actual_height + 5) + 'px';
- }
- };
-
- CartoDB.Infowindow.prototype.setPosition = function() {
- if (this.div_) {
- var div = this.div_;
- var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
- if (pixPosition) {
- div.style.width = this.width_ + 'px';
- div.style.left = (pixPosition.x - 49) + 'px';
- var actual_height = - $(div).height();
- div.style.top = (pixPosition.y + actual_height + 10) + 'px';
- }
- this.show();
- }
- };
-
- CartoDB.Infowindow.prototype.open = function(feature,latlng){
- var that = this
- , infowindow_sql = this.params_.meta_query.format(feature);
- that.feature_ = feature;
-
- // If the table is private, you can't run any api methods
- if (this.params_.feature!=true) {
- infowindow_sql = encodeURIComponent(this.params_.feature.replace('{{feature}}',feature));
- }
-
-
- $.getJSON(
- 'http://mol.cartodb.com/api/v2/sql?q={0}&callback=?'.format(infowindow_sql),
- function(result) {
- var content;
- if(!result.error) {
- content = $.parseJSON(
- result.rows[0]['get_feature_metadata']
- );
- positionateInfowindow(content, latlng);
- }
- }
- );
-
- function positionateInfowindow(variables,center) {
- if (that.div_) {
- var div = that.div_;
- // Get latlng position
- that.latlng_ = latlng;
-
- // Remove the unnecessary html
- $('div.cartodb_infowindow div.outer_top div.top').html('');
- $('div.cartodb_infowindow div.outer_top div.bottom label').html('');
-
- // List all the new variables
- for (p in variables) {
- if (p!='cartodb_id' && p!='cdb_centre' && p!='the_geom_webmercator' && variables[p]!=null && variables[p]!='') {
- $('div.cartodb_infowindow div.outer_top div.top').append('<label>'+p+'</label><p class="'+((variables[p]!=null && variables[p]!='')?'':'empty')+'">'+(variables[p] || 'empty')+'</p>');
- }
- }
-
- // Show cartodb_id?
- // if (variables['cartodb_id']) {
- // $('div.cartodb_infowindow div.bottom label').html('id: <strong>'+feature+'</strong>');
- // }
-
- that.moveMaptoOpen();
- that.setPosition();
- }
- }
- };
-
- CartoDB.Infowindow.prototype.hide = function() {
- if (this.div_) {
- var div = this.div_;
- $(div).animate({
- top: '+=' + 10 + 'px',
- opacity: 0},
- 100, 'swing',
- function () {
- div.style.visibility = "hidden";
- }
- );
- }
- };
-
- CartoDB.Infowindow.prototype.show = function() {
- if (this.div_) {
- var div = this.div_;
- div.style.opacity = 0;
- div.style.visibility = "visible";
- $(div).animate({
- top: '-=' + 10 + 'px',
- opacity: 1},
- 250
- );
- }
- };
-
- CartoDB.Infowindow.prototype.hideAll = function() {
- $('div.cartodb_infowindow').css('visibility','hidden');
- };
-
- CartoDB.Infowindow.prototype.isVisible = function(marker_id) {
- if (this.div_) {
- var div = this.div_;
- if (div.style.visibility == 'visible' && this.feature_!=null) {
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- };
-
- CartoDB.Infowindow.prototype.transformGeoJSON = function(str) {
- var json = $.parseJSON(str);
- return new google.maps.LatLng(json.coordinates[1],json.coordinates[0]);
- };
-
- CartoDB.Infowindow.prototype.moveMaptoOpen = function() {
- var left = 0;
- var top = 0;
- var div = this.div_;
- var pixPosition = this.getProjection().fromLatLngToContainerPixel(this.latlng_);
-
- if ((pixPosition.x + this.offsetHorizontal_) < 0) {
- left = (pixPosition.x + this.offsetHorizontal_ - 20);
- }
-
- if ((pixPosition.x + 180) >= ($('#'+this.params_.map_canvas).width())) {
- left = (pixPosition.x + 180 - $('#'+this.params_.map_canvas).width());
- }
-
- if ((pixPosition.y - $(div).height()) < 0) {
- top = (pixPosition.y - $(div).height() - 30);
- }
-
- this.map_.panBy(left,top);
- };
-
-})(jQuery);
View
2,804 app/js/lib/wax.g.js
@@ -1,2804 +0,0 @@
-/* wax - 4.1.3 - 1.0.4-477-gba3b176 */
-
-
-/*!
- * Reqwest! A general purpose XHR connection manager
- * copyright Dustin Diaz 2011
- * https://github.com/ded/reqwest
- * license MIT
- */
-!function(context,win){function serial(a){var b=a.name;if(a.disabled||!b)return"";b=enc(b);switch(a.tagName.toLowerCase()){case"input":switch(a.type){case"reset":case"button":case"image":case"file":return"";case"checkbox":case"radio":return a.checked?b+"="+(a.value?enc(a.value):!0)+"&":"";default:return b+"="+(a.value?enc(a.value):"")+"&"}break;case"textarea":return b+"="+enc(a.value)+"&";case"select":return b+"="+enc(a.options[a.selectedIndex].value)+"&"}return""}function enc(a){return encodeURIComponent(a)}function reqwest(a,b){return new Reqwest(a,b)}function init(o,fn){function error(a){o.error&&o.error(a),complete(a)}function success(resp){o.timeout&&clearTimeout(self.timeout)&&(self.timeout=null);var r=resp.responseText;if(r)switch(type){case"json":resp=win.JSON?win.JSON.parse(r):eval("("+r+")");break;case"js":resp=eval(r);break;case"html":resp=r}fn(resp),o.success&&o.success(resp),complete(resp)}function complete(a){o.complete&&o.complete(a)}this.url=typeof o=="string"?o:o.url,this.timeout=null;var type=o.type||setType(this.url),self=this;fn=fn||function(){},o.timeout&&(this.timeout=setTimeout(function(){self.abort(),error()},o.timeout)),this.request=getRequest(o,success,error)}function setType(a){if(/\.json$/.test(a))return"json";if(/\.jsonp$/.test(a))return"jsonp";if(/\.js$/.test(a))return"js";if(/\.html?$/.test(a))return"html";if(/\.xml$/.test(a))return"xml";return"js"}function Reqwest(a,b){this.o=a,this.fn=b,init.apply(this,arguments)}function getRequest(a,b,c){if(a.type!="jsonp"){var f=xhr();f.open(a.method||"GET",typeof a=="string"?a:a.url,!0),setHeaders(f,a),f.onreadystatechange=handleReadyState(f,b,c),a.before&&a.before(f),f.send(a.data||null);return f}var d=doc.createElement("script"),e=0;win[getCallbackName(a)]=generalCallback,d.type="text/javascript",d.src=a.url,d.async=!0,d.onload=d.onreadystatechange=function(){if(d[readyState]&&d[readyState]!=="complete"&&d[readyState]!=="loaded"||e)return!1;d.onload=d.onreadystatechange=null,a.success&&a.success(lastValue),lastValue=undefined,head.removeChild(d),e=1},head.appendChild(d)}function generalCallback(a){lastValue=a}function getCallbackName(a){var b=a.jsonpCallback||"callback";if(a.url.slice(-(b.length+2))==b+"=?"){var c="reqwest_"+uniqid++;a.url=a.url.substr(0,a.url.length-1)+c;return c}var d=new RegExp(b+"=([\\w]+)");return a.url.match(d)[1]}function setHeaders(a,b){var c=b.headers||{};c.Accept=c.Accept||"text/javascript, text/html, application/xml, text/xml, */*",b.crossOrigin||(c["X-Requested-With"]=c["X-Requested-With"]||"XMLHttpRequest"),c[contentType]=c[contentType]||"application/x-www-form-urlencoded";for(var d in c)c.hasOwnProperty(d)&&a.setRequestHeader(d,c[d],!1)}function handleReadyState(a,b,c){return function(){a&&a[readyState]==4&&(twoHundo.test(a.status)?b(a):c(a))}}var twoHundo=/^20\d$/,doc=document,byTag="getElementsByTagName",readyState="readyState",contentType="Content-Type",head=doc[byTag]("head")[0],uniqid=0,lastValue,xhr="XMLHttpRequest"in win?function(){return new XMLHttpRequest}:function(){return new ActiveXObject("Microsoft.XMLHTTP")};Reqwest.prototype={abort:function(){this.request.abort()},retry:function(){init.call(this,this.o,this.fn)}},reqwest.serialize=function(a){var b=[a[byTag]("input"),a[byTag]("select"),a[byTag]("textarea")],c=[],d,e;for(d=0,l=b.length;d<l;++d)for(e=0,l2=b[d].length;e<l2;++e)c.push(serial(b[d][e]));return c.join("").replace(/&$/,"")},reqwest.serializeArray=function(a){for(var b=this.serialize(a).split("&"),c=0,d=b.length,e=[],f;c<d;c++)b[c]&&(f=b[c].split("="))&&e.push({name:f[0],value:f[1]});return e};var old=context.reqwest;reqwest.noConflict=function(){context.reqwest=old;return this},typeof module!="undefined"?module.exports=reqwest:context.reqwest=reqwest}(this,window)// Copyright Google Inc.
-// Licensed under the Apache Licence Version 2.0
-// Autogenerated at Tue Oct 11 13:36:46 EDT 2011
-// @provides html4
-var html4 = {};
-html4.atype = {
- NONE: 0,
- URI: 1,
- URI_FRAGMENT: 11,
- SCRIPT: 2,
- STYLE: 3,
- ID: 4,
- IDREF: 5,
- IDREFS: 6,
- GLOBAL_NAME: 7,
- LOCAL_NAME: 8,
- CLASSES: 9,
- FRAME_TARGET: 10
-};
-html4.ATTRIBS = {
- '*::class': 9,
- '*::dir': 0,
- '*::id': 4,
- '*::lang': 0,
- '*::onclick': 2,
- '*::ondblclick': 2,
- '*::onkeydown': 2,
- '*::onkeypress': 2,
- '*::onkeyup': 2,
- '*::onload': 2,
- '*::onmousedown': 2,
- '*::onmousemove': 2,
- '*::onmouseout': 2,
- '*::onmouseover': 2,
- '*::onmouseup': 2,
- '*::style': 3,
- '*::title': 0,
- 'a::accesskey': 0,
- 'a::coords': 0,
- 'a::href': 1,
- 'a::hreflang': 0,
- 'a::name': 7,
- 'a::onblur': 2,
- 'a::onfocus': 2,
- 'a::rel': 0,
- 'a::rev': 0,
- 'a::shape': 0,
- 'a::tabindex': 0,
- 'a::target': 10,
- 'a::type': 0,
- 'area::accesskey': 0,
- 'area::alt': 0,
- 'area::coords': 0,
- 'area::href': 1,
- 'area::nohref': 0,
- 'area::onblur': 2,
- 'area::onfocus': 2,
- 'area::shape': 0,
- 'area::tabindex': 0,
- 'area::target': 10,
- 'bdo::dir': 0,
- 'blockquote::cite': 1,
- 'br::clear': 0,
- 'button::accesskey': 0,
- 'button::disabled': 0,
- 'button::name': 8,
- 'button::onblur': 2,
- 'button::onfocus': 2,
- 'button::tabindex': 0,
- 'button::type': 0,
- 'button::value': 0,
- 'canvas::height': 0,
- 'canvas::width': 0,
- 'caption::align': 0,
- 'col::align': 0,
- 'col::char': 0,
- 'col::charoff': 0,
- 'col::span': 0,
- 'col::valign': 0,
- 'col::width': 0,
- 'colgroup::align': 0,
- 'colgroup::char': 0,
- 'colgroup::charoff': 0,
- 'colgroup::span': 0,
- 'colgroup::valign': 0,
- 'colgroup::width': 0,
- 'del::cite': 1,
- 'del::datetime': 0,
- 'dir::compact': 0,
- 'div::align': 0,
- 'dl::compact': 0,
- 'font::color': 0,
- 'font::face': 0,
- 'font::size': 0,
- 'form::accept': 0,
- 'form::action': 1,
- 'form::autocomplete': 0,
- 'form::enctype': 0,
- 'form::method': 0,
- 'form::name': 7,
- 'form::onreset': 2,
- 'form::onsubmit': 2,
- 'form::target': 10,
- 'h1::align': 0,
- 'h2::align': 0,
- 'h3::align': 0,
- 'h4::align': 0,
- 'h5::align': 0,
- 'h6::align': 0,
- 'hr::align': 0,
- 'hr::noshade': 0,
- 'hr::size': 0,
- 'hr::width': 0,
- 'iframe::align': 0,
- 'iframe::frameborder': 0,
- 'iframe::height': 0,
- 'iframe::marginheight': 0,
- 'iframe::marginwidth': 0,
- 'iframe::width': 0,
- 'img::align': 0,
- 'img::alt': 0,
- 'img::border': 0,
- 'img::height': 0,
- 'img::hspace': 0,
- 'img::ismap': 0,
- 'img::name': 7,
- 'img::src': 1,
- 'img::usemap': 11,
- 'img::vspace': 0,
- 'img::width': 0,
- 'input::accept': 0,
- 'input::accesskey': 0,
- 'input::align': 0,
- 'input::alt': 0,
- 'input::autocomplete': 0,
- 'input::checked': 0,
- 'input::disabled': 0,
- 'input::ismap': 0,
- 'input::maxlength': 0,
- 'input::name': 8,
- 'input::onblur': 2,
- 'input::onchange': 2,
- 'input::onfocus': 2,
- 'input::onselect': 2,
- 'input::readonly': 0,
- 'input::size': 0,
- 'input::src': 1,
- 'input::tabindex': 0,
- 'input::type': 0,
- 'input::usemap': 11,
- 'input::value': 0,
- 'ins::cite': 1,
- 'ins::datetime': 0,
- 'label::accesskey': 0,
- 'label::for': 5,
- 'label::onblur': 2,
- 'label::onfocus': 2,
- 'legend::accesskey': 0,
- 'legend::align': 0,
- 'li::type': 0,
- 'li::value': 0,
- 'map::name': 7,
- 'menu::compact': 0,
- 'ol::compact': 0,
- 'ol::start': 0,
- 'ol::type': 0,
- 'optgroup::disabled': 0,
- 'optgroup::label': 0,
- 'option::disabled': 0,
- 'option::label': 0,
- 'option::selected': 0,
- 'option::value': 0,
- 'p::align': 0,
- 'pre::width': 0,
- 'q::cite': 1,
- 'select::disabled': 0,
- 'select::multiple': 0,
- 'select::name': 8,
- 'select::onblur': 2,
- 'select::onchange': 2,
- 'select::onfocus': 2,
- 'select::size': 0,
- 'select::tabindex': 0,
- 'table::align': 0,
- 'table::bgcolor': 0,
- 'table::border': 0,
- 'table::cellpadding': 0,
- 'table::cellspacing': 0,
- 'table::frame': 0,
- 'table::rules': 0,
- 'table::summary': 0,
- 'table::width': 0,
- 'tbody::align': 0,
- 'tbody::char': 0,
- 'tbody::charoff': 0,
- 'tbody::valign': 0,
- 'td::abbr': 0,
- 'td::align': 0,
- 'td::axis': 0,
- 'td::bgcolor': 0,
- 'td::char': 0,
- 'td::charoff': 0,
- 'td::colspan': 0,
- 'td::headers': 6,
- 'td::height': 0,
- 'td::nowrap': 0,
- 'td::rowspan': 0,
- 'td::scope': 0,
- 'td::valign': 0,
- 'td::width': 0,
- 'textarea::accesskey': 0,
- 'textarea::cols': 0,
- 'textarea::disabled': 0,
- 'textarea::name': 8,
- 'textarea::onblur': 2,
- 'textarea::onchange': 2,
- 'textarea::onfocus': 2,
- 'textarea::onselect': 2,
- 'textarea::readonly': 0,
- 'textarea::rows': 0,
- 'textarea::tabindex': 0,
- 'tfoot::align': 0,
- 'tfoot::char': 0,
- 'tfoot::charoff': 0,
- 'tfoot::valign': 0,
- 'th::abbr': 0,
- 'th::align': 0,
- 'th::axis': 0,
- 'th::bgcolor': 0,
- 'th::char': 0,
- 'th::charoff': 0,
- 'th::colspan': 0,
- 'th::headers': 6,
- 'th::height': 0,
- 'th::nowrap': 0,
- 'th::rowspan': 0,
- 'th::scope': 0,
- 'th::valign': 0,
- 'th::width': 0,
- 'thead::align': 0,
- 'thead::char': 0,
- 'thead::charoff': 0,
- 'thead::valign': 0,
- 'tr::align': 0,
- 'tr::bgcolor': 0,
- 'tr::char': 0,
- 'tr::charoff': 0,
- 'tr::valign': 0,
- 'ul::compact': 0,
- 'ul::type': 0
-};
-html4.eflags = {
- OPTIONAL_ENDTAG: 1,
- EMPTY: 2,
- CDATA: 4,
- RCDATA: 8,
- UNSAFE: 16,
- FOLDABLE: 32,
- SCRIPT: 64,
- STYLE: 128
-};
-html4.ELEMENTS = {
- 'a': 0,
- 'abbr': 0,
- 'acronym': 0,
- 'address': 0,
- 'applet': 16,
- 'area': 2,
- 'b': 0,
- 'base': 18,
- 'basefont': 18,
- 'bdo': 0,
- 'big': 0,
- 'blockquote': 0,
- 'body': 49,
- 'br': 2,
- 'button': 0,
- 'canvas': 0,
- 'caption': 0,
- 'center': 0,
- 'cite': 0,
- 'code': 0,
- 'col': 2,
- 'colgroup': 1,
- 'dd': 1,
- 'del': 0,
- 'dfn': 0,
- 'dir': 0,
- 'div': 0,
- 'dl': 0,
- 'dt': 1,
- 'em': 0,
- 'fieldset': 0,
- 'font': 0,
- 'form': 0,
- 'frame': 18,
- 'frameset': 16,
- 'h1': 0,
- 'h2': 0,
- 'h3': 0,
- 'h4': 0,
- 'h5': 0,
- 'h6': 0,
- 'head': 49,
- 'hr': 2,
- 'html': 49,
- 'i': 0,
- 'iframe': 4,
- 'img': 2,
- 'input': 2,
- 'ins': 0,
- 'isindex': 18,
- 'kbd': 0,
- 'label': 0,
- 'legend': 0,
- 'li': 1,
- 'link': 18,
- 'map': 0,
- 'menu': 0,
- 'meta': 18,
- 'nobr': 0,
- 'noembed': 4,
- 'noframes': 20,
- 'noscript': 20,
- 'object': 16,
- 'ol': 0,
- 'optgroup': 0,
- 'option': 1,
- 'p': 1,
- 'param': 18,
- 'pre': 0,
- 'q': 0,
- 's': 0,
- 'samp': 0,
- 'script': 84,
- 'select': 0,
- 'small': 0,
- 'span': 0,
- 'strike': 0,
- 'strong': 0,
- 'style': 148,
- 'sub': 0,
- 'sup': 0,
- 'table': 0,
- 'tbody': 1,
- 'td': 1,
- 'textarea': 8,
- 'tfoot': 1,
- 'th': 1,
- 'thead': 1,
- 'title': 24,
- 'tr': 1,
- 'tt': 0,
- 'u': 0,
- 'ul': 0,
- 'var': 0
-};
-html4.ueffects = {
- NOT_LOADED: 0,
- SAME_DOCUMENT: 1,
- NEW_DOCUMENT: 2
-};
-html4.URIEFFECTS = {
- 'a::href': 2,
- 'area::href': 2,
- 'blockquote::cite': 0,
- 'body::background': 1,
- 'del::cite': 0,
- 'form::action': 2,
- 'img::src': 1,
- 'input::src': 1,
- 'ins::cite': 0,
- 'q::cite': 0
-};
-html4.ltypes = {
- UNSANDBOXED: 2,
- SANDBOXED: 1,
- DATA: 0
-};
-html4.LOADERTYPES = {
- 'a::href': 2,
- 'area::href': 2,
- 'blockquote::cite': 2,
- 'body::background': 1,
- 'del::cite': 2,
- 'form::action': 2,
- 'img::src': 1,
- 'input::src': 1,
- 'ins::cite': 2,
- 'q::cite': 2
-};;
-// Copyright (C) 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.
-
-/**
- * @fileoverview
- * An HTML sanitizer that can satisfy a variety of security policies.
- *
- * <p>
- * The HTML sanitizer is built around a SAX parser and HTML element and
- * attributes schemas.
- *
- * @author mikesamuel@gmail.com
- * @requires html4
- * @overrides window
- * @provides html, html_sanitize
- */
-
-/**
- * @namespace
- */
-var html = (function (html4) {
- var lcase;
- // The below may not be true on browsers in the Turkish locale.
- if ('script' === 'SCRIPT'.toLowerCase()) {
- lcase = function (s) { return s.toLowerCase(); };
- } else {
- /**
- * {@updoc
- * $ lcase('SCRIPT')
- * # 'script'
- * $ lcase('script')
- * # 'script'
- * }
- */
- lcase = function (s) {
- return s.replace(
- /[A-Z]/g,
- function (ch) {
- return String.fromCharCode(ch.charCodeAt(0) | 32);
- });
- };
- }
-
- var ENTITIES = {
- lt : '<',
- gt : '>',
- amp : '&',
- nbsp : '\240',
- quot : '"',
- apos : '\''
- };
-
- // Schemes on which to defer to uripolicy. Urls with other schemes are denied
- var WHITELISTED_SCHEMES = /^(?:https?|mailto|data)$/i;
-
- var decimalEscapeRe = /^#(\d+)$/;
- var hexEscapeRe = /^#x([0-9A-Fa-f]+)$/;
- /**
- * Decodes an HTML entity.
- *
- * {@updoc
- * $ lookupEntity('lt')
- * # '<'
- * $ lookupEntity('GT')
- * # '>'
- * $ lookupEntity('amp')
- * # '&'
- * $ lookupEntity('nbsp')
- * # '\xA0'
- * $ lookupEntity('apos')
- * # "'"
- * $ lookupEntity('quot')
- * # '"'
- * $ lookupEntity('#xa')
- * # '\n'
- * $ lookupEntity('#10')
- * # '\n'
- * $ lookupEntity('#x0a')
- * # '\n'
- * $ lookupEntity('#010')
- * # '\n'
- * $ lookupEntity('#x00A')
- * # '\n'
- * $ lookupEntity('Pi') // Known failure
- * # '\u03A0'
- * $ lookupEntity('pi') // Known failure
- * # '\u03C0'
- * }
- *
- * @param name the content between the '&' and the ';'.
- * @return a single unicode code-point as a string.
- */
- function lookupEntity(name) {
- name = lcase(name); // TODO: &pi; is different from &Pi;
- if (ENTITIES.hasOwnProperty(name)) { return ENTITIES[name]; }
- var m = name.match(decimalEscapeRe);
- if (m) {
- return String.fromCharCode(parseInt(m[1], 10));
- } else if (!!(m = name.match(hexEscapeRe))) {
- return String.fromCharCode(parseInt(m[1], 16));
- }
- return '';
- }
-
- function decodeOneEntity(_, name) {
- return lookupEntity(name);
- }
-
- var nulRe = /\0/g;
- function stripNULs(s) {
- return s.replace(nulRe, '');
- }
-
- var entityRe = /&(#\d+|#x[0-9A-Fa-f]+|\w+);/g;
- /**
- * The plain text of a chunk of HTML CDATA which possibly containing.
- *
- * {@updoc
- * $ unescapeEntities('')
- * # ''
- * $ unescapeEntities('hello World!')
- * # 'hello World!'
- * $ unescapeEntities('1 &lt; 2 &amp;&AMP; 4 &gt; 3&#10;')
- * # '1 < 2 && 4 > 3\n'
- * $ unescapeEntities('&lt;&lt <- unfinished entity&gt;')
- * # '<&lt <- unfinished entity>'
- * $ unescapeEntities('/foo?bar=baz&copy=true') // & often unescaped in URLS
- * # '/foo?bar=baz&copy=true'
- * $ unescapeEntities('pi=&pi;&#x3c0;, Pi=&Pi;\u03A0') // FIXME: known failure
- * # 'pi=\u03C0\u03c0, Pi=\u03A0\u03A0'
- * }
- *
- * @param s a chunk of HTML CDATA. It must not start or end inside an HTML
- * entity.
- */
- function unescapeEntities(s) {
- return s.replace(entityRe, decodeOneEntity);
- }
-
- var ampRe = /&/g;
- var looseAmpRe = /&([^a-z#]|#(?:[^0-9x]|x(?:[^0-9a-f]|$)|$)|$)/gi;
- var ltRe = /</g;
- var gtRe = />/g;
- var quotRe = /\"/g;
- var eqRe = /\=/g; // Backslash required on JScript.net
-
- /**
- * Escapes HTML special characters in attribute values as HTML entities.
- *
- * {@updoc
- * $ escapeAttrib('')
- * # ''
- * $ escapeAttrib('"<<&==&>>"') // Do not just escape the first occurrence.
- * # '&#34;&lt;&lt;&amp;&#61;&#61;&amp;&gt;&gt;&#34;'
- * $ escapeAttrib('Hello <World>!')
- * # 'Hello &lt;World&gt;!'
- * }
- */
- function escapeAttrib(s) {
- // Escaping '=' defangs many UTF-7 and SGML short-tag attacks.
- return s.replace(ampRe, '&amp;').replace(ltRe, '&lt;').replace(gtRe, '&gt;')
- .replace(quotRe, '&#34;').replace(eqRe, '&#61;');
- }
-
- /**
- * Escape entities in RCDATA that can be escaped without changing the meaning.
- * {@updoc
- * $ normalizeRCData('1 < 2 &&amp; 3 > 4 &amp;& 5 &lt; 7&8')
- * # '1 &lt; 2 &amp;&amp; 3 &gt; 4 &amp;&amp; 5 &lt; 7&amp;8'
- * }
- */
- function normalizeRCData(rcdata) {
- return rcdata
- .replace(looseAmpRe, '&amp;$1')
- .replace(ltRe, '&lt;')
- .replace(gtRe, '&gt;');
- }
-
-
- // TODO(mikesamuel): validate sanitizer regexs against the HTML5 grammar at
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html
-
- /** token definitions. */
- var INSIDE_TAG_TOKEN = new RegExp(
- // Don't capture space.
- '^\\s*(?:'
- // Capture an attribute name in group 1, and value in group 3.
- // We capture the fact that there was an attribute in group 2, since
- // interpreters are inconsistent in whether a group that matches nothing
- // is null, undefined, or the empty string.
- + ('(?:'
- + '([a-z][a-z-]*)' // attribute name
- + ('(' // optionally followed
- + '\\s*=\\s*'
- + ('('
- // A double quoted string.
- + '\"[^\"]*\"'
- // A single quoted string.
- + '|\'[^\']*\''
- // The positive lookahead is used to make sure that in
- // <foo bar= baz=boo>, the value for bar is blank, not "baz=boo".
- + '|(?=[a-z][a-z-]*\\s*=)'
- // An unquoted value that is not an attribute name.
- // We know it is not an attribute name because the previous
- // zero-width match would've eliminated that possibility.
- + '|[^>\"\'\\s]*'
- + ')'
- )
- + ')'
- ) + '?'
- + ')'
- )
- // End of tag captured in group 3.
- + '|(\/?>)'
- // Don't capture cruft
- + '|[\\s\\S][^a-z\\s>]*)',
- 'i');
-
- var OUTSIDE_TAG_TOKEN = new RegExp(
- '^(?:'
- // Entity captured in group 1.
- + '&(\\#[0-9]+|\\#[x][0-9a-f]+|\\w+);'
- // Comment, doctypes, and processing instructions not captured.
- + '|<\!--[\\s\\S]*?--\>|<!\\w[^>]*>|<\\?[^>*]*>'
- // '/' captured in group 2 for close tags, and name captured in group 3.
- + '|<(\/)?([a-z][a-z0-9]*)'
- // Text captured in group 4.
- + '|([^<&>]+)'
- // Cruft captured in group 5.
- + '|([<&>]))',
- 'i');
-
- /**
- * Given a SAX-like event handler, produce a function that feeds those
- * events and a parameter to the event handler.
- *
- * The event handler has the form:{@code
- * {
- * // Name is an upper-case HTML tag name. Attribs is an array of
- * // alternating upper-case attribute names, and attribute values. The
- * // attribs array is reused by the parser. Param is the value passed to
- * // the saxParser.
- * startTag: function (name, attribs, param) { ... },
- * endTag: function (name, param) { ... },
- * pcdata: function (text, param) { ... },
- * rcdata: function (text, param) { ... },
- * cdata: function (text, param) { ... },
- * startDoc: function (param) { ... },
- * endDoc: function (param) { ... }
- * }}
- *
- * @param {Object} handler a record containing event handlers.
- * @return {Function} that takes a chunk of html and a parameter.
- * The parameter is passed on to the handler methods.
- */
- function makeSaxParser(handler) {
- return function parse(htmlText, param) {
- htmlText = String(htmlText);
- var htmlLower = null;
-
- var inTag = false; // True iff we're currently processing a tag.
- var attribs = []; // Accumulates attribute names and values.
- var tagName = void 0; // The name of the tag currently being processed.
- var eflags = void 0; // The element flags for the current tag.
- var openTag = void 0; // True if the current tag is an open tag.
-
- if (handler.startDoc) { handler.startDoc(param); }
-
- while (htmlText) {
- var m = htmlText.match(inTag ? INSIDE_TAG_TOKEN : OUTSIDE_TAG_TOKEN);
- htmlText = htmlText.substring(m[0].length);
-
- if (inTag) {
- if (m[1]) { // attribute
- // setAttribute with uppercase names doesn't work on IE6.
- var attribName = lcase(m[1]);
- var decodedValue;
- if (m[2]) {
- var encodedValue = m[3];
- switch (encodedValue.charCodeAt(0)) { // Strip quotes
- case 34: case 39:
- encodedValue = encodedValue.substring(
- 1, encodedValue.length - 1);
- break;
- }
- decodedValue = unescapeEntities(stripNULs(encodedValue));
- } else {
- // Use name as value for valueless attribs, so
- // <input type=checkbox checked>
- // gets attributes ['type', 'checkbox', 'checked', 'checked']
- decodedValue = attribName;
- }
- attribs.push(attribName, decodedValue);
- } else if (m[4]) {
- if (eflags !== void 0) { // False if not in whitelist.
- if (openTag) {
- if (handler.startTag) {
- handler.startTag(tagName, attribs, param);
- }
- } else {
- if (handler.endTag) {
- handler.endTag(tagName, param);
- }
- }
- }
-
- if (openTag
- && (eflags & (html4.eflags.CDATA | html4.eflags.RCDATA))) {
- if (htmlLower === null) {
- htmlLower = lcase(htmlText);
- } else {
- htmlLower = htmlLower.substring(
- htmlLower.length - htmlText.length);
- }
- var dataEnd = htmlLower.indexOf('</' + tagName);
- if (dataEnd < 0) { dataEnd = htmlText.length; }
- if (dataEnd) {
- if (eflags & html4.eflags.CDATA) {
- if (handler.cdata) {
- handler.cdata(htmlText.substring(0, dataEnd), param);
- }
- } else if (handler.rcdata) {
- handler.rcdata(
- normalizeRCData(htmlText.substring(0, dataEnd)), param);
- }
- htmlText = htmlText.substring(dataEnd);
- }
- }
-
- tagName = eflags = openTag = void 0;
- attribs.length = 0;
- inTag = false;
- }
- } else {
- if (m[1]) { // Entity
- if (handler.pcdata) { handler.pcdata(m[0], param); }
- } else if (m[3]) { // Tag
- openTag = !m[2];
- inTag = true;
- tagName = lcase(m[3]);
- eflags = html4.ELEMENTS.hasOwnProperty(tagName)
- ? html4.ELEMENTS[tagName] : void 0;
- } else if (m[4]) { // Text
- if (handler.pcdata) { handler.pcdata(m[4], param); }
- } else if (m[5]) { // Cruft
- if (handler.pcdata) {
- var ch = m[5];
- handler.pcdata(
- ch === '<' ? '&lt;' : ch === '>' ? '&gt;' : '&amp;',
- param);
- }
- }
- }
- }
-
- if (handler.endDoc) { handler.endDoc(param); }
- };
- }
-
- /**
- * Returns a function that strips unsafe tags and attributes from html.
- * @param {Function} sanitizeAttributes
- * maps from (tagName, attribs[]) to null or a sanitized attribute array.
- * The attribs array can be arbitrarily modified, but the same array
- * instance is reused, so should not be held.
- * @return {Function} from html to sanitized html
- */
- function makeHtmlSanitizer(sanitizeAttributes) {
- var stack;
- var ignoring;
- return makeSaxParser({
- startDoc: function (_) {
- stack = [];
- ignoring = false;
- },
- startTag: function (tagName, attribs, out) {
- if (ignoring) { return; }
- if (!html4.ELEMENTS.hasOwnProperty(tagName)) { return; }
- var eflags = html4.ELEMENTS[tagName];
- if (eflags & html4.eflags.FOLDABLE) {
- return;
- } else if (eflags & html4.eflags.UNSAFE) {
- ignoring = !(eflags & html4.eflags.EMPTY);
- return;
- }
- attribs = sanitizeAttributes(tagName, attribs);
- // TODO(mikesamuel): relying on sanitizeAttributes not to
- // insert unsafe attribute names.
- if (attribs) {
- if (!(eflags & html4.eflags.EMPTY)) {
- stack.push(tagName);
- }
-
- out.push('<', tagName);
- for (var i = 0, n = attribs.length; i < n; i += 2) {
- var attribName = attribs[i],
- value = attribs[i + 1];
- if (value !== null && value !== void 0) {
- out.push(' ', attribName, '="', escapeAttrib(value), '"');
- }
- }
- out.push('>');
- }
- },
- endTag: function (tagName, out) {
- if (ignoring) {
- ignoring = false;
- return;
- }
- if (!html4.ELEMENTS.hasOwnProperty(tagName)) { return; }
- var eflags = html4.ELEMENTS[tagName];
- if (!(eflags & (html4.eflags.UNSAFE | html4.eflags.EMPTY
- | html4.eflags.FOLDABLE))) {
- var index;
- if (eflags & html4.eflags.OPTIONAL_ENDTAG) {
- for (index = stack.length; --index >= 0;) {
- var stackEl = stack[index];
- if (stackEl === tagName) { break; }
- if (!(html4.ELEMENTS[stackEl]
- & html4.eflags.OPTIONAL_ENDTAG)) {
- // Don't pop non optional end tags looking for a match.
- return;
- }
- }
- } else {
- for (index = stack.length; --index >= 0;) {
- if (stack[index] === tagName) { break; }
- }
- }
- if (index < 0) { return; } // Not opened.
- for (var i = stack.length; --i > index;) {
- var stackEl = stack[i];
- if (!(html4.ELEMENTS[stackEl]
- & html4.eflags.OPTIONAL_ENDTAG)) {
- out.push('</', stackEl, '>');
- }
- }
- stack.length = index;
- out.push('</', tagName, '>');
- }
- },
- pcdata: function (text, out) {
- if (!ignoring) { out.push(text); }
- },
- rcdata: function (text, out) {
- if (!ignoring) { out.push(text); }
- },
- cdata: function (text, out) {
- if (!ignoring) { out.push(text); }
- },
- endDoc: function (out) {
- for (var i = stack.length; --i >= 0;) {
- out.push('</', stack[i], '>');
- }
- stack.length = 0;
- }
- });
- }
-
- // From RFC3986
- var URI_SCHEME_RE = new RegExp(
- "^" +
- "(?:" +
- "([^:\/?#]+)" + // scheme
- ":)?"
- );
-
- /**
- * Strips unsafe tags and attributes from html.
- * @param {string} htmlText to sanitize
- * @param {Function} opt_uriPolicy -- a transform to apply to uri/url
- * attribute values. If no opt_uriPolicy is provided, no uris
- * are allowed ie. the default uriPolicy rewrites all uris to null
- * @param {Function} opt_nmTokenPolicy : string -> string? -- a transform to
- * apply to names, ids, and classes. If no opt_nmTokenPolicy is provided,
- * all names, ids and classes are passed through ie. the default
- * nmTokenPolicy is an identity transform
- * @return {string} html
- */
- function sanitize(htmlText, opt_uriPolicy, opt_nmTokenPolicy) {
- var out = [];
- makeHtmlSanitizer(
- function sanitizeAttribs(tagName, attribs) {
- for (var i = 0; i < attribs.length; i += 2) {
- var attribName = attribs[i];
- var value = attribs[i + 1];
- var atype = null, attribKey;
- if ((attribKey = tagName + '::' + attribName,
- html4.ATTRIBS.hasOwnProperty(attribKey))
- || (attribKey = '*::' + attribName,
- html4.ATTRIBS.hasOwnProperty(attribKey))) {
- atype = html4.ATTRIBS[attribKey];
- }
- if (atype !== null) {
- switch (atype) {
- case html4.atype.NONE: break;
- case html4.atype.SCRIPT:
- case html4.atype.STYLE:
- value = null;
- break;
- case html4.atype.ID:
- case html4.atype.IDREF:
- case html4.atype.IDREFS:
- case html4.atype.GLOBAL_NAME:
- case html4.atype.LOCAL_NAME:
- case html4.atype.CLASSES:
- value = opt_nmTokenPolicy ? opt_nmTokenPolicy(value) : value;
- break;
- case html4.atype.URI:
- var parsedUri = ('' + value).match(URI_SCHEME_RE);
- if (!parsedUri) {
- value = null;
- } else if (!parsedUri[1] ||
- WHITELISTED_SCHEMES.test(parsedUri[1])) {
- value = opt_uriPolicy && opt_uriPolicy(value);
- } else {
- value = null;
- }
- break;
- case html4.atype.URI_FRAGMENT:
- if (value && '#' === value.charAt(0)) {
- value = opt_nmTokenPolicy ? opt_nmTokenPolicy(value) : value;
- if (value) { value = '#' + value; }
- } else {
- value = null;
- }
- break;
- default:
- value = null;
- break;
- }
- } else {
- value = null;
- }
- attribs[i + 1] = value;
- }
- return attribs;
- })(htmlText, out);
- return out.join('');
- }
-
- return {
- escapeAttrib: escapeAttrib,
- makeHtmlSanitizer: makeHtmlSanitizer,
- makeSaxParser: makeSaxParser,
- normalizeRCData: normalizeRCData,
- sanitize: sanitize,
- unescapeEntities: unescapeEntities
- };
-})(html4);
-
-var html_sanitize = html.sanitize;
-
-// Exports for closure compiler. Note this file is also cajoled
-// for domado and run in an environment without 'window'
-if (typeof window !== 'undefined') {
- window['html'] = html;
- window['html_sanitize'] = html_sanitize;
-}
-// Loosen restrictions of Caja's
-// html-sanitizer to allow for styling
-html4.ATTRIBS['*::style'] = 0;
-html4.ELEMENTS['style'] = 0;
-/*
- mustache.js — Logic-less templates in JavaScript
-
- See http://mustache.github.com/ for more info.
-*/
-
-var Mustache = function() {
- var regexCache = {};
- var Renderer = function() {};
-
- Renderer.prototype = {
- otag: "{{",
- ctag: "}}",
- pragmas: {},
- buffer: [],
- pragmas_implemented: {
- "IMPLICIT-ITERATOR": true
- },
- context: {},
-
- render: function(template, context, partials, in_recursion) {
- // reset buffer & set context
- if(!in_recursion) {
- this.context = context;
- this.buffer = []; // TODO: make this non-lazy
- }
-
- // fail fast
- if(!this.includes("", template)) {
- if(in_recursion) {
- return template;
- } else {
- this.send(template);
- return;
- }
- }
-
- // get the pragmas together
- template = this.render_pragmas(template);
-
- // render the template
- var html = this.render_section(template, context, partials);
-
- // render_section did not find any sections, we still need to render the tags
- if (html === false) {
- html = this.render_tags(template, context, partials, in_recursion);
- }
-
- if (in_recursion) {