Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Remove backbone dependency. Fall back on jquery + underscore instead,…

… to get better perfs
  • Loading branch information...
commit b3c5a44b5cd9f199efd7007f27754df645547113 1 parent 5ef8b5e
authored March 05, 2013
15  zivimap/static/css/main.css
@@ -50,6 +50,21 @@ a.nav-small:hover {
50 50
   height: 100%;
51 51
 }
52 52
 
  53
+#loading-inner {
  54
+  position: relative;
  55
+  left: -50%;
  56
+  z-index: 5;
  57
+  margin-top: 20px;
  58
+  background-color: #FFF;
  59
+  text-align: center;
  60
+  padding: 10px;
  61
+}
  62
+
  63
+#loading h3 {
  64
+  padding: 0;
  65
+  margin: 0;
  66
+}
  67
+
53 68
 #filters_overlay {
54 69
   position: absolute;
55 70
   left: 50px;
BIN  zivimap/static/img/ajax-loader.gif
42  zivimap/static/js/libs/backbone-min.js
... ...
@@ -1,42 +0,0 @@
1  
-// Backbone.js 0.9.9
2  
-
3  
-// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
4  
-// Backbone may be freely distributed under the MIT license.
5  
-// For all details and documentation:
6  
-// http://backbonejs.org
7  
-(function(){var k=this,y=k.Backbone,h=[],z=h.push,r=h.slice,A=h.splice,g;g="undefined"!==typeof exports?exports:k.Backbone={};g.VERSION="0.9.9";var e=k._;!e&&"undefined"!==typeof require&&(e=require("underscore"));g.$=k.jQuery||k.Zepto||k.ender;g.noConflict=function(){k.Backbone=y;return this};g.emulateHTTP=!1;g.emulateJSON=!1;var s=/\s+/,n=function(a,b,c,d){if(!c)return!0;if("object"===typeof c)for(var f in c)a[b].apply(a,[f,c[f]].concat(d));else if(s.test(c)){c=c.split(s);f=0;for(var e=c.length;f<
8  
-e;f++)a[b].apply(a,[c[f]].concat(d))}else return!0},t=function(a,b,c){var d,a=-1,f=b.length;switch(c.length){case 0:for(;++a<f;)(d=b[a]).callback.call(d.ctx);break;case 1:for(;++a<f;)(d=b[a]).callback.call(d.ctx,c[0]);break;case 2:for(;++a<f;)(d=b[a]).callback.call(d.ctx,c[0],c[1]);break;case 3:for(;++a<f;)(d=b[a]).callback.call(d.ctx,c[0],c[1],c[2]);break;default:for(;++a<f;)(d=b[a]).callback.apply(d.ctx,c)}},h=g.Events={on:function(a,b,c){if(!n(this,"on",a,[b,c])||!b)return this;this._events||(this._events=
9  
-{});(this._events[a]||(this._events[a]=[])).push({callback:b,context:c,ctx:c||this});return this},once:function(a,b,c){if(!n(this,"once",a,[b,c])||!b)return this;var d=this,f=e.once(function(){d.off(a,f);b.apply(this,arguments)});f._callback=b;this.on(a,f,c);return this},off:function(a,b,c){var d,f,l,g,i,m,h,j;if(!this._events||!n(this,"off",a,[b,c]))return this;if(!a&&!b&&!c)return this._events={},this;g=a?[a]:e.keys(this._events);i=0;for(m=g.length;i<m;i++)if(a=g[i],d=this._events[a]){l=[];if(b||
10  
-c){h=0;for(j=d.length;h<j;h++)f=d[h],(b&&b!==(f.callback._callback||f.callback)||c&&c!==f.context)&&l.push(f)}this._events[a]=l}return this},trigger:function(a){if(!this._events)return this;var b=r.call(arguments,1);if(!n(this,"trigger",a,b))return this;var c=this._events[a],d=this._events.all;c&&t(this,c,b);d&&t(this,d,arguments);return this},listenTo:function(a,b,c){var d=this._listeners||(this._listeners={}),f=a._listenerId||(a._listenerId=e.uniqueId("l"));d[f]=a;a.on(b,c||this,this);return this},
11  
-stopListening:function(a,b,c){var d=this._listeners;if(d){if(a)a.off(b,c,this),!b&&!c&&delete d[a._listenerId];else{for(var f in d)d[f].off(null,null,this);this._listeners={}}return this}}};h.bind=h.on;h.unbind=h.off;e.extend(g,h);var o=g.Model=function(a,b){var c,d=a||{};this.cid=e.uniqueId("c");this.changed={};this.attributes={};this._changes=[];b&&b.collection&&(this.collection=b.collection);b&&b.parse&&(d=this.parse(d));(c=e.result(this,"defaults"))&&e.defaults(d,c);this.set(d,{silent:!0});this._currentAttributes=
12  
-e.clone(this.attributes);this._previousAttributes=e.clone(this.attributes);this.initialize.apply(this,arguments)};e.extend(o.prototype,h,{changed:null,idAttribute:"id",initialize:function(){},toJSON:function(){return e.clone(this.attributes)},sync:function(){return g.sync.apply(this,arguments)},get:function(a){return this.attributes[a]},escape:function(a){return e.escape(this.get(a))},has:function(a){return null!=this.get(a)},set:function(a,b,c){var d,f;if(null==a)return this;e.isObject(a)?(f=a,c=
13  
-b):(f={})[a]=b;var a=c&&c.silent,l=c&&c.unset;if(!this._validate(f,c))return!1;this.idAttribute in f&&(this.id=f[this.idAttribute]);var g=this.attributes;for(d in f)b=f[d],l?delete g[d]:g[d]=b,this._changes.push(d,b);this._hasComputed=!1;a||this.change(c);return this},unset:function(a,b){return this.set(a,void 0,e.extend({},b,{unset:!0}))},clear:function(a){var b={},c;for(c in this.attributes)b[c]=void 0;return this.set(b,e.extend({},a,{unset:!0}))},fetch:function(a){a=a?e.clone(a):{};void 0===a.parse&&
14  
-(a.parse=!0);var b=this,c=a.success;a.success=function(d){if(!b.set(b.parse(d),a))return false;c&&c(b,d,a)};return this.sync("read",this,a)},save:function(a,b,c){var d,f,g;null==a||e.isObject(a)?(d=a,c=b):null!=a&&((d={})[a]=b);c=c?e.clone(c):{};if(c.wait){if(d&&!this._validate(d,c))return!1;f=e.clone(this.attributes)}a=e.extend({},c,{silent:!0});if(d&&!this.set(d,c.wait?a:c)||!d&&!this._validate(null,c))return!1;var q=this,i=c.success;c.success=function(a){g=true;var b=q.parse(a);c.wait&&(b=e.extend(d||
15  
-{},b));if(!q.set(b,c))return false;i&&i(q,a,c)};b=this.isNew()?"create":c.patch?"patch":"update";"patch"==b&&(c.attrs=d);b=this.sync(b,this,c);!g&&c.wait&&(this.clear(a),this.set(f,a));return b},destroy:function(a){var a=a?e.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};a.success=function(f){(a.wait||b.isNew())&&d();c&&c(b,f,a)};if(this.isNew())return a.success(),!1;var f=this.sync("delete",this,a);a.wait||d();return f},url:function(){var a=e.result(this,"urlRoot")||
16  
-e.result(this.collection,"url")||u();return this.isNew()?a:a+("/"===a.charAt(a.length-1)?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return null==this.id},change:function(a){var b=this._changing;this._changing=!0;var c=this._computeChanges(!0);this._pending=!!c.length;for(var d=c.length-2;0<=d;d-=2)this.trigger("change:"+c[d],this,c[d+1],a);if(b)return this;for(;this._pending;)this._pending=!1,this.trigger("change",
17  
-this,a),this._previousAttributes=e.clone(this.attributes);this._changing=!1;return this},hasChanged:function(a){this._hasComputed||this._computeChanges();return null==a?!e.isEmpty(this.changed):e.has(this.changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?e.clone(this.changed):!1;var b,c=!1,d=this._previousAttributes,f;for(f in a)if(!e.isEqual(d[f],b=a[f]))(c||(c={}))[f]=b;return c},_computeChanges:function(a){this.changed={};for(var b={},c=[],d=this._currentAttributes,f=this._changes,
18  
-e=f.length-2;0<=e;e-=2){var g=f[e],i=f[e+1];b[g]||(b[g]=!0,d[g]!==i&&(this.changed[g]=i,a&&(c.push(g,i),d[g]=i)))}a&&(this._changes=[]);this._hasComputed=!0;return c},previous:function(a){return null==a||!this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return e.clone(this._previousAttributes)},_validate:function(a,b){if(!this.validate)return!0;var a=e.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return!0;b&&b.error&&b.error(this,c,b);this.trigger("error",
19  
-this,c,b);return!1}});var p=g.Collection=function(a,b){b||(b={});b.model&&(this.model=b.model);void 0!==b.comparator&&(this.comparator=b.comparator);this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,e.extend({silent:!0},b))};e.extend(p.prototype,h,{model:o,initialize:function(){},toJSON:function(a){return this.map(function(b){return b.toJSON(a)})},sync:function(){return g.sync.apply(this,arguments)},add:function(a,b){var c,d,f,g,h=b&&b.at,i=null==(b&&b.sort)?!0:b.sort,a=e.isArray(a)?
20  
-a.slice():[a];for(c=a.length-1;0<=c;c--)(d=this._prepareModel(a[c],b))?(a[c]=d,(f=null!=d.id&&this._byId[d.id])||this._byCid[d.cid]?(b&&(b.merge&&f)&&(f.set(d.attributes,b),g=i),a.splice(c,1)):(d.on("all",this._onModelEvent,this),this._byCid[d.cid]=d,null!=d.id&&(this._byId[d.id]=d))):(this.trigger("error",this,a[c],b),a.splice(c,1));a.length&&(g=i);this.length+=a.length;c=[null!=h?h:this.models.length,0];z.apply(c,a);A.apply(this.models,c);g&&(this.comparator&&null==h)&&this.sort({silent:!0});if(b&&
21  
-b.silent)return this;for(;d=a.shift();)d.trigger("add",d,this,b);return this},remove:function(a,b){var c,d,f,g;b||(b={});a=e.isArray(a)?a.slice():[a];c=0;for(d=a.length;c<d;c++)if(g=this.get(a[c]))delete this._byId[g.id],delete this._byCid[g.cid],f=this.indexOf(g),this.models.splice(f,1),this.length--,b.silent||(b.index=f,g.trigger("remove",g,this,b)),this._removeReference(g);return this},push:function(a,b){a=this._prepareModel(a,b);this.add(a,e.extend({at:this.length},b));return a},pop:function(a){var b=
22  
-this.at(this.length-1);this.remove(b,a);return b},unshift:function(a,b){a=this._prepareModel(a,b);this.add(a,e.extend({at:0},b));return a},shift:function(a){var b=this.at(0);this.remove(b,a);return b},slice:function(a,b){return this.models.slice(a,b)},get:function(a){return null==a?void 0:this._byId[null!=a.id?a.id:a]||this._byCid[a.cid||a]},at:function(a){return this.models[a]},where:function(a){return e.isEmpty(a)?[]:this.filter(function(b){for(var c in a)if(a[c]!==b.get(c))return!1;return!0})},
23  
-sort:function(a){if(!this.comparator)throw Error("Cannot sort a set without a comparator");e.isString(this.comparator)||1===this.comparator.length?this.models=this.sortBy(this.comparator,this):this.models.sort(e.bind(this.comparator,this));(!a||!a.silent)&&this.trigger("sort",this,a);return this},pluck:function(a){return e.invoke(this.models,"get",a)},update:function(a,b){var c,d,f,g,h=[],i=[],m={},j=this.model.prototype.idAttribute,b=e.extend({add:!0,merge:!0,remove:!0},b);b.parse&&(a=this.parse(a));
24  
-e.isArray(a)||(a=a?[a]:[]);if(b.add&&!b.remove)return this.add(a,b);d=0;for(f=a.length;d<f;d++)c=a[d],g=this.get(c.id||c.cid||c[j]),b.remove&&g&&(m[g.cid]=!0),(b.add&&!g||b.merge&&g)&&h.push(c);if(b.remove){d=0;for(f=this.models.length;d<f;d++)c=this.models[d],m[c.cid]||i.push(c)}i.length&&this.remove(i,b);h.length&&this.add(h,b);return this},reset:function(a,b){b||(b={});b.parse&&(a=this.parse(a));for(var c=0,d=this.models.length;c<d;c++)this._removeReference(this.models[c]);b.previousModels=this.models;
25  
-this._reset();a&&this.add(a,e.extend({silent:!0},b));b.silent||this.trigger("reset",this,b);return this},fetch:function(a){a=a?e.clone(a):{};void 0===a.parse&&(a.parse=!0);var b=this,c=a.success;a.success=function(d){b[a.update?"update":"reset"](d,a);c&&c(b,d,a)};return this.sync("read",this,a)},create:function(a,b){var c=this,b=b?e.clone(b):{},a=this._prepareModel(a,b);if(!a)return!1;b.wait||c.add(a,b);var d=b.success;b.success=function(a,b,e){e.wait&&c.add(a,e);d&&d(a,b,e)};a.save(null,b);return a},
26  
-parse:function(a){return a},clone:function(){return new this.constructor(this.models)},chain:function(){return e(this.models).chain()},_reset:function(){this.length=0;this.models=[];this._byId={};this._byCid={}},_prepareModel:function(a,b){if(a instanceof o)return a.collection||(a.collection=this),a;b||(b={});b.collection=this;var c=new this.model(a,b);return!c._validate(a,b)?!1:c},_removeReference:function(a){this===a.collection&&delete a.collection;a.off("all",this._onModelEvent,this)},_onModelEvent:function(a,
27  
-b,c,d){("add"===a||"remove"===a)&&c!==this||("destroy"===a&&this.remove(b,d),b&&a==="change:"+b.idAttribute&&(delete this._byId[b.previous(b.idAttribute)],null!=b.id&&(this._byId[b.id]=b)),this.trigger.apply(this,arguments))}});e.each("forEach each map collect reduce foldl inject reduceRight foldr find detect filter select reject every all some any include contains invoke max min sortedIndex toArray size first head take initial rest tail last without indexOf shuffle lastIndexOf isEmpty".split(" "),
28  
-function(a){p.prototype[a]=function(){var b=r.call(arguments);b.unshift(this.models);return e[a].apply(e,b)}});e.each(["groupBy","countBy","sortBy"],function(a){p.prototype[a]=function(b,c){var d=e.isFunction(b)?b:function(a){return a.get(b)};return e[a](this.models,d,c)}});var v=g.Router=function(a){a||(a={});a.routes&&(this.routes=a.routes);this._bindRoutes();this.initialize.apply(this,arguments)},B=/\((.*?)\)/g,C=/:\w+/g,D=/\*\w+/g,E=/[\-{}\[\]+?.,\\\^$|#\s]/g;e.extend(v.prototype,h,{initialize:function(){},
29  
-route:function(a,b,c){e.isRegExp(a)||(a=this._routeToRegExp(a));c||(c=this[b]);g.history.route(a,e.bind(function(d){d=this._extractParameters(a,d);c&&c.apply(this,d);this.trigger.apply(this,["route:"+b].concat(d));g.history.trigger("route",this,b,d)},this));return this},navigate:function(a,b){g.history.navigate(a,b);return this},_bindRoutes:function(){if(this.routes)for(var a,b=e.keys(this.routes);null!=(a=b.pop());)this.route(a,this.routes[a])},_routeToRegExp:function(a){a=a.replace(E,"\\$&").replace(B,
30  
-"(?:$1)?").replace(C,"([^/]+)").replace(D,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,b){return a.exec(b).slice(1)}});var j=g.History=function(){this.handlers=[];e.bindAll(this,"checkUrl");"undefined"!==typeof window&&(this.location=window.location,this.history=window.history)},w=/^[#\/]|\s+$/g,F=/^\/+|\/+$/g,G=/msie [\w.]+/,H=/\/$/;j.started=!1;e.extend(j.prototype,h,{interval:50,getHash:function(a){return(a=(a||this).location.href.match(/#(.*)$/))?a[1]:""},getFragment:function(a,
31  
-b){if(null==a)if(this._hasPushState||!this._wantsHashChange||b){var a=this.location.pathname,c=this.root.replace(H,"");a.indexOf(c)||(a=a.substr(c.length))}else a=this.getHash();return a.replace(w,"")},start:function(a){if(j.started)throw Error("Backbone.history has already been started");j.started=!0;this.options=e.extend({},{root:"/"},this.options,a);this.root=this.options.root;this._wantsHashChange=!1!==this.options.hashChange;this._wantsPushState=!!this.options.pushState;this._hasPushState=!(!this.options.pushState||
32  
-!this.history||!this.history.pushState);var a=this.getFragment(),b=document.documentMode,b=G.exec(navigator.userAgent.toLowerCase())&&(!b||7>=b);this.root=("/"+this.root+"/").replace(F,"/");b&&this._wantsHashChange&&(this.iframe=g.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow,this.navigate(a));this._hasPushState?g.$(window).bind("popstate",this.checkUrl):this._wantsHashChange&&"onhashchange"in window&&!b?g.$(window).bind("hashchange",this.checkUrl):this._wantsHashChange&&
33  
-(this._checkUrlInterval=setInterval(this.checkUrl,this.interval));this.fragment=a;a=this.location;b=a.pathname.replace(/[^\/]$/,"$&/")===this.root;if(this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!b)return this.fragment=this.getFragment(null,!0),this.location.replace(this.root+this.location.search+"#"+this.fragment),!0;this._wantsPushState&&(this._hasPushState&&b&&a.hash)&&(this.fragment=this.getHash().replace(w,""),this.history.replaceState({},document.title,this.root+this.fragment+
34  
-a.search));if(!this.options.silent)return this.loadUrl()},stop:function(){g.$(window).unbind("popstate",this.checkUrl).unbind("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);j.started=!1},route:function(a,b){this.handlers.unshift({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();a===this.fragment&&this.iframe&&(a=this.getFragment(this.getHash(this.iframe)));if(a===this.fragment)return!1;this.iframe&&this.navigate(a);this.loadUrl()||this.loadUrl(this.getHash())},
35  
-loadUrl:function(a){var b=this.fragment=this.getFragment(a);return e.any(this.handlers,function(a){if(a.route.test(b))return a.callback(b),!0})},navigate:function(a,b){if(!j.started)return!1;if(!b||!0===b)b={trigger:b};a=this.getFragment(a||"");if(this.fragment!==a){this.fragment=a;var c=this.root+a;if(this._hasPushState)this.history[b.replace?"replaceState":"pushState"]({},document.title,c);else if(this._wantsHashChange)this._updateHash(this.location,a,b.replace),this.iframe&&a!==this.getFragment(this.getHash(this.iframe))&&
36  
-(b.replace||this.iframe.document.open().close(),this._updateHash(this.iframe.location,a,b.replace));else return this.location.assign(c);b.trigger&&this.loadUrl(a)}},_updateHash:function(a,b,c){c?(c=a.href.replace(/(javascript:|#).*$/,""),a.replace(c+"#"+b)):a.hash="#"+b}});g.history=new j;var x=g.View=function(a){this.cid=e.uniqueId("view");this._configure(a||{});this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()},I=/^(\S+)\s*(.*)$/,J="model collection el id attributes className tagName events".split(" ");
37  
-e.extend(x.prototype,h,{tagName:"div",$:function(a){return this.$el.find(a)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();this.stopListening();return this},make:function(a,b,c){a=document.createElement(a);b&&g.$(a).attr(b);null!=c&&g.$(a).html(c);return a},setElement:function(a,b){this.$el&&this.undelegateEvents();this.$el=a instanceof g.$?a:g.$(a);this.el=this.$el[0];!1!==b&&this.delegateEvents();return this},delegateEvents:function(a){if(a||(a=e.result(this,
38  
-"events"))){this.undelegateEvents();for(var b in a){var c=a[b];e.isFunction(c)||(c=this[a[b]]);if(!c)throw Error('Method "'+a[b]+'" does not exist');var d=b.match(I),f=d[1],d=d[2],c=e.bind(c,this),f=f+(".delegateEvents"+this.cid);""===d?this.$el.bind(f,c):this.$el.delegate(d,f,c)}}},undelegateEvents:function(){this.$el.unbind(".delegateEvents"+this.cid)},_configure:function(a){this.options&&(a=e.extend({},e.result(this,"options"),a));e.extend(this,e.pick(a,J));this.options=a},_ensureElement:function(){if(this.el)this.setElement(e.result(this,
39  
-"el"),!1);else{var a=e.extend({},e.result(this,"attributes"));this.id&&(a.id=e.result(this,"id"));this.className&&(a["class"]=e.result(this,"className"));this.setElement(this.make(e.result(this,"tagName"),a),!1)}}});var K={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};g.sync=function(a,b,c){var d=K[a];e.defaults(c||(c={}),{emulateHTTP:g.emulateHTTP,emulateJSON:g.emulateJSON});var f={type:d,dataType:"json"};c.url||(f.url=e.result(b,"url")||u());if(null==c.data&&b&&("create"===
40  
-a||"update"===a||"patch"===a))f.contentType="application/json",f.data=JSON.stringify(c.attrs||b.toJSON(c));c.emulateJSON&&(f.contentType="application/x-www-form-urlencoded",f.data=f.data?{model:f.data}:{});if(c.emulateHTTP&&("PUT"===d||"DELETE"===d||"PATCH"===d)){f.type="POST";c.emulateJSON&&(f.data._method=d);var h=c.beforeSend;c.beforeSend=function(a){a.setRequestHeader("X-HTTP-Method-Override",d);if(h)return h.apply(this,arguments)}}"GET"!==f.type&&!c.emulateJSON&&(f.processData=!1);var j=c.success;
41  
-c.success=function(a,d,e){j&&j(a,d,e);b.trigger("sync",b,a,c)};var i=c.error;c.error=function(a){i&&i(b,a,c);b.trigger("error",b,a,c)};a=g.ajax(e.extend(f,c));b.trigger("request",b,a,c);return a};g.ajax=function(){return g.$.ajax.apply(g.$,arguments)};o.extend=p.extend=v.extend=x.extend=j.extend=function(a,b){var c=this,d;d=a&&e.has(a,"constructor")?a.constructor:function(){c.apply(this,arguments)};e.extend(d,c,b);var f=function(){this.constructor=d};f.prototype=c.prototype;d.prototype=new f;a&&e.extend(d.prototype,
42  
-a);d.__super__=c.prototype;return d};var u=function(){throw Error('A "url" property or function must be specified');}}).call(this);
374  zivimap/static/js/map.js
@@ -5,7 +5,7 @@ function windowResized() {
5 5
     var mapheight = (h - offsetTop);
6 6
     $('#map_canvas').css('height', mapheight);
7 7
     // TODO: Need additional offset because of scrollbar. Not very clean
8  
-    $('#maplist').css('height', mapheight - 40);
  8
+    //$('#maplist').css('height', mapheight - 40);
9 9
 }
10 10
 
11 11
 
@@ -14,223 +14,179 @@ function url_from_phid(phid) {
14 14
     return ZIVI_WS_BASE + '&phid=' + phid;
15 15
 }
16 16
 
17  
-// N is the namespace to use for this app
18  
-function initMap(N) {
19  
-    N.WorkSpec = Backbone.Model.extend({
20  
-        urlRoot: SEARCH_API,
21  
-    });
22 17
 
23  
-    N.Address = Backbone.Model.extend({
24  
-        urlRoot: ADDRESS_API,
25  
-        // We don't use resource_uri for addresses
26  
-        idAttribute: 'id',
27  
-    });
  18
+// MapView prototype
  19
+MapView = function() {
  20
+  this.initialize.apply(this, arguments);
  21
+}
28 22
 
29  
-    N.WorkSpecList = Backbone.Collection.extend({
30  
-        urlRoot: SEARCH_API,
31  
-        model: N.WorkSpec,
32  
-    });
  23
+MapView.prototype.initialize = function(el, infowindow_template) {
  24
+  this.infowindow_template = infowindow_template;
  25
+  _.bindAll(this, 'onViewChanged', 'onMarkerClick', 'zoomToCluster', 'displayClusterInfo');
  26
+
  27
+  var mapOptions = {
  28
+      center: new google.maps.LatLng(46.815099,8.22876),
  29
+      zoom: 8,
  30
+      mapTypeId: google.maps.MapTypeId.ROADMAP
  31
+  };
  32
+  this.map = new google.maps.Map(el, mapOptions);
  33
+  this.infowindow = new google.maps.InfoWindow();
  34
+
  35
+  // We handle click events and maxZoom ourselves
  36
+  // - maxZoom is used to specify the maximum level at which to
  37
+  //   create clusters
  38
+  // - maxViewZoom is the max level at which we'll zoom when a
  39
+  //   user clicks on a cluster
  40
+  // We set maxZoom to null because we always want clusters. But
  41
+  // we set a reasonable maximum zoom level of 12 considering that
  42
+  // we mostly have city-level localization, going to road-level
  43
+  // is pretty meaningless
  44
+  var mcOptions = { maxZoom: null, zoomOnClick: false, minimumClusterSize: 1 };
  45
+  this.markerCluster = new MarkerClusterer(this.map, [], mcOptions);
  46
+  this.markerCluster.maxViewZoom = 12;
  47
+
  48
+  $(window).resize(windowResized).resize();
  49
+
  50
+  // -- Setup event listener
  51
+  var mapview = this;
  52
+  google.maps.event.addListener(this.markerCluster, 'click', function(cluster) {
  53
+      if (mapview.map.getZoom() >= mapview.markerCluster.maxViewZoom) {
  54
+          // If we're already at max zoom, show a popup with the
  55
+          // list of workspecs in the cluster
  56
+          console.log('Max zoom');
  57
+          mapview.displayClusterInfo(cluster);
  58
+      } else {
  59
+          mapview.zoomToCluster(cluster);
  60
+      }
  61
+  });
  62
+
  63
+  // Register for the idle event (fired after movement).
  64
+  // This is the basis for interactivity and it will trigger a sync()
  65
+  // of the workspecs and map/list markers update
  66
+  // http://code.google.com/p/gmaps-api-issues/issues/detail?id=1371
  67
+  google.maps.event.addListener(this.map, 'idle', this.onViewChanged);
  68
+}
33 69
 
34  
-    N.AddressList = Backbone.Collection.extend({
35  
-        urlRoot: ADDRESS_API,
36  
-        model: N.Address
37  
-    });
  70
+// Called to display the workspecs contained in the cluster in the
  71
+// infowindow
  72
+MapView.prototype.displayClusterInfo = function(cluster) {
  73
+  var markers = cluster.getMarkers();
  74
+  var lst = _.map(markers, function(m) {
  75
+      return '<li>' + this.infowindow_template(m.workspec) + '</li>';
  76
+  }, this);
  77
+  var html = _.reduceRight(lst, function(a, b) {
  78
+      return a.concat(b);
  79
+  }, "");
  80
+  this.infowindow.setContent('<ul>' + html + '</ul>');
  81
+  this.infowindow.open(this.map);
  82
+  this.infowindow.setPosition(cluster.getCenter());
  83
+}
38 84
 
39  
-    // Backbone.Pageable doesn't work well with Backbone-tastypie
40  
-    // TODO: Write a client-side pagination lib
41  
-
42  
-    N.WorkSpecView = Backbone.View.extend({
43  
-        tagName: "li",
44  
-        template: _.template($('#workspec_template').html()),
45  
-        initialize: function() {
46  
-            this.render();
47  
-        },
48  
-        render: function() {
49  
-            this.$el.html(this.template(this.model.toJSON()));
50  
-            return this;
51  
-        },
52  
-    });
  85
+MapView.prototype.zoomToCluster = function(cluster) {
  86
+  // Modified copy of default zoom function from markerClustererPlus
  87
+  // Zoom into the cluster.
  88
+  //mz = this.markerCluster.getMaxZoom();
  89
+  mz = this.markerCluster.maxViewZoom;
  90
+  theBounds = cluster.getBounds();
  91
+  this.map.fitBounds(theBounds);
  92
+  // There is a fix for Issue 170 here:
  93
+  var map = this.map;
  94
+  setTimeout(function () {
  95
+      map.fitBounds(theBounds);
  96
+      // Don't zoom beyond the max zoom level
  97
+      // Because fitBounds will zoom, this check we didn't zoom too
  98
+      // far
  99
+      if (mz !== null && (map.getZoom() > mz)) {
  100
+          map.setZoom(mz + 1);
  101
+      }
  102
+  }, 100);
  103
+}
53 104
 
54  
-    N.ListView = Backbone.View.extend({
55  
-        el: $("#maplist"),
56  
-        initialize: function() {
57  
-            this.collection.on('add', this.addOne, this);
58  
-            this.collection.on('reset', this.addAll, this);
59  
-            this.collection.on('all', this.render, this);
60  
-            //workspecs.fecth();
61  
-        },
62  
-
63  
-        addOne: function(workspec) {
64  
-            var view = new N.WorkSpecView({model: workspec});
65  
-            this.$("#workspec-list").append(view.render().el);
66  
-        },
67  
-
68  
-        addAll: function() {
69  
-            this.collection.each(this.addOne);
70  
-        },
71  
-    });
  105
+MapView.prototype.onMarkerClick = function(marker) {
  106
+  //this.infowindow.setContent(marker.desc);
  107
+  var html = this.infowindow_template(marker.model.toJSON());
  108
+  this.infowindow.setContent(html);
  109
+  this.infowindow.open(this.map, marker);
  110
+}
72 111
 
73  
-    N.MapView = Backbone.View.extend({
74  
-        el: $("#map_canvas"),
75  
-        infowindow_template : _.template($('#infowindow_template').html()),
76  
-        addresses: null,
77  
-
78  
-        initialize: function(options) {
79  
-            if (options.addresses) {
80  
-                this.addresses = options.addresses;
81  
-            }
82  
-
83  
-            _.bindAll(this, 'onViewChanged', 'onAdd', 'onRemove', 'onReset',
84  
-                      'onMarkerClick', 'zoomToCluster', 'displayClusterInfo');
85  
-
86  
-            var mapOptions = {
87  
-                center: new google.maps.LatLng(46.815099,8.22876),
88  
-                zoom: 8,
89  
-                mapTypeId: google.maps.MapTypeId.ROADMAP
90  
-            };
91  
-            this.map = new google.maps.Map(this.el, mapOptions);
92  
-            this.infowindow = new google.maps.InfoWindow();
93  
-
94  
-            // We handle click events and maxZoom ourselves
95  
-            // - maxZoom is used to specify the maximum level at which to
96  
-            //   create clusters
97  
-            // - maxViewZoom is the max level at which we'll zoom when a
98  
-            //   user clicks on a cluster
99  
-            // We set maxZoom to null because we always want clusters. But
100  
-            // we set a reasonable maximum zoom level of 12 considering that
101  
-            // we mostly have city-level localization, going to road-level
102  
-            // is pretty meaningless
103  
-            var mcOptions = { maxZoom: null, zoomOnClick: false, minimumClusterSize: 1 };
104  
-            this.markerCluster = new MarkerClusterer(this.map, [], mcOptions);
105  
-            this.markerCluster.maxViewZoom = 12;
106  
-
107  
-            $(window).resize(windowResized).resize();
108  
-
109  
-            // -- Setup event listener
110  
-            var mapview = this;
111  
-            google.maps.event.addListener(this.markerCluster, 'click', function(cluster) {
112  
-                if (mapview.map.getZoom() >= mapview.markerCluster.maxViewZoom) {
113  
-                    // If we're already at max zoom, show a popup with the
114  
-                    // list of workspecs in the cluster
115  
-                    console.log('Max zoom');
116  
-                    mapview.displayClusterInfo(cluster);
117  
-                } else {
118  
-                    mapview.zoomToCluster(cluster);
119  
-                }
120  
-            });
121  
-
122  
-            // Register for the idle event (fired after movement).
123  
-            // This is the basis for interactivity and it will trigger a sync()
124  
-            // of the workspecs and map/list markers update
125  
-            // http://code.google.com/p/gmaps-api-issues/issues/detail?id=1371
126  
-            google.maps.event.addListener(this.map, 'idle', this.onViewChanged);
127  
-
128  
-            this.collection.on('add', this.onAdd, this);
129  
-            this.collection.on('remove', this.onRemove, this);
130  
-            this.collection.on('reset', this.onReset, this);
131  
-        },
132  
-
133  
-        // Called to display the workspecs contained in the cluster in the
134  
-        // infowindow
135  
-        displayClusterInfo: function(cluster) {
136  
-            var markers = cluster.getMarkers();
137  
-            var lst = _.map(markers, function(m) {
138  
-                return '<li>' + this.infowindow_template(m.model.toJSON()) + '</li>';
139  
-            }, this);
140  
-            var html = _.reduceRight(lst, function(a, b) {
141  
-                return a.concat(b);
142  
-            }, "");
143  
-            this.infowindow.setContent('<ul>' + html + '</ul>');
144  
-            this.infowindow.open(this.map);
145  
-            this.infowindow.setPosition(cluster.getCenter());
146  
-        },
147  
-
148  
-        zoomToCluster: function(cluster) {
149  
-            // Modified copy of default zoom function from markerClustererPlus
150  
-            // Zoom into the cluster.
151  
-            //mz = this.markerCluster.getMaxZoom();
152  
-            mz = this.markerCluster.maxViewZoom;
153  
-            theBounds = cluster.getBounds();
154  
-            this.map.fitBounds(theBounds);
155  
-            // There is a fix for Issue 170 here:
156  
-            var map = this.map;
157  
-            setTimeout(function () {
158  
-                map.fitBounds(theBounds);
159  
-                // Don't zoom beyond the max zoom level
160  
-                // Because fitBounds will zoom, this check we didn't zoom too
161  
-                // far
162  
-                if (mz !== null && (map.getZoom() > mz)) {
163  
-                    map.setZoom(mz + 1);
164  
-                }
165  
-            }, 100);
166  
-        },
167  
-
168  
-        onReset: function() {
169  
-            this.collection.each(this.onAdd);
170  
-        },
171  
-
172  
-        // Called when a workspec is added to the collection
173  
-        onAdd: function(model, options) {
174  
-            var addrid = model.get("addrid");
175  
-            var address = this.addresses.get(addrid);
176  
-            var lat = address.get("latitude");
177  
-            var lng = address.get("longitude");
178  
-            var marker = new google.maps.Marker({
179  
-                position: new google.maps.LatLng(lat, lng),
180  
-                map: this.map
181  
-            });
182  
-            marker.model = model;
183  
-            this.markerCluster.addMarker(marker);
184  
-            model.marker = marker;
185  
-        },
186  
-
187  
-        onRemove: function(model) {
188  
-            this.markerCluster.removeMarker(model.marker);
189  
-            model.marker.setMap(null);
190  
-            model.marker = null;
191  
-        },
192  
-
193  
-        onMarkerClick: function(marker) {
194  
-            //this.infowindow.setContent(marker.desc);
195  
-            var html = this.infowindow_template(marker.model.toJSON());
196  
-            this.infowindow.setContent(html);
197  
-            this.infowindow.open(this.map, marker);
198  
-        },
199  
-
200  
-        // Called when map view is changed by the user
201  
-        onViewChanged: function() {
202  
-            // Update collection by querying markers within new view bounds
203  
-            var bounds = this.map.getBounds();
204  
-            var swlat = bounds.getSouthWest().lat();
205  
-            var swlng = bounds.getSouthWest().lng();
206  
-            var nelat = bounds.getNorthEast().lat();
207  
-            var nelng = bounds.getNorthEast().lng();
208  
-            var params = {'latlngbb' : swlat.toString() + ","
209  
-                + swlng.toString() + "," + nelat.toString() + ","
210  
-                + nelng.toString()};
211  
-            //console.log('onViewChanged => fetch')
212  
-            //this.collection.fetch({data: $.param(params), update:true});
213  
-        },
  112
+MapView.prototype.setAddresses = function(addresses) {
  113
+  this.addresses = addresses;
  114
+}
  115
+
  116
+MapView.prototype.createMarkersFromWorkSpecs = function(workspecs) {
  117
+  var markers = new Array();
  118
+  var length = workspecs.length;
  119
+  for (var i = 0; i < length; i++) {
  120
+    var ws = workspecs[i];
  121
+    var addrid = ws.addrid;
  122
+    var address = this.addresses[addrid];
  123
+    var lat = address.latitude;
  124
+    var lng = address.longitude;
  125
+    var marker = new google.maps.Marker({
  126
+        position: new google.maps.LatLng(lat, lng),
  127
+        map: this.map
214 128
     });
  129
+    marker.workspec = ws;
  130
+    ws.marker = marker;
  131
+    markers.push(marker);
  132
+  }
  133
+  this.markerCluster.addMarkers(markers);
  134
+}
215 135
 
216  
-    N.addresses = new N.AddressList();
217  
-    N.workspecs = new N.WorkSpecList();
  136
+// Called when map view is changed by the user
  137
+MapView.prototype.onViewChanged = function() {
  138
+  // Update collection by querying markers within new view bounds
  139
+  //var bounds = this.map.getBounds();
  140
+  //var swlat = bounds.getSouthWest().lat();
  141
+  //var swlng = bounds.getSouthWest().lng();
  142
+  //var nelat = bounds.getNorthEast().lat();
  143
+  //var nelng = bounds.getNorthEast().lng();
  144
+  //var params = {'latlngbb' : swlat.toString() + ","
  145
+      //+ swlng.toString() + "," + nelat.toString() + ","
  146
+      //+ nelng.toString()};
  147
+  //console.log('onViewChanged => fetch')
  148
+  //this.collection.fetch({data: $.param(params), update:true});
218 149
 
219  
-    //N.listview = new N.ListView({
220  
-        //collection: N.workspecs
221  
-    //});
  150
+}
222 151
 
223  
-    N.mapview = new N.MapView({
224  
-        collection: N.workspecs,
225  
-        addresses: N.addresses,
226  
-    });
227 152
 
228  
-    // Workspecs depends on all addresses being loaded (otherwise MapView will
229  
-    // fail). So chain them
230  
-    // TODO: Need to handle potential ajax errors
231  
-    N.addresses.fetch({success:
232  
-        function(collection, response) {
233  
-            N.workspecs.fetch();
234  
-        }
235  
-    });
  153
+
  154
+function newInitMap(N) {
  155
+  // Called on ajax errors
  156
+  N.onAjaxFail = function() {
  157
+    alert('Oops, something went wrong. Try reloading');
  158
+  }
  159
+
  160
+  // Called when addresses are received from API
  161
+  N.onAddresses = function(response) {
  162
+    N.addresses = {}
  163
+    var objs = response.objects;
  164
+    var length = objs.length;
  165
+    for (var i = 0; i < length; i++) {
  166
+      N.addresses[objs[i].id] = objs[i];
  167
+    }
  168
+    N.mapView.setAddresses(N.addresses);
  169
+  };
  170
+
  171
+  N.onWorkSpecs = function(response) {
  172
+    N.mapView.createMarkersFromWorkSpecs(response.objects);
  173
+  };
  174
+
  175
+  N.mapView = new MapView($("#map_canvas")[0],
  176
+                          _.template($('#infowindow_template').html()));
  177
+
  178
+
  179
+  // Chain address loading and then workspecs loading
  180
+  $('#loading').show();
  181
+  $.getJSON(ADDRESS_API)
  182
+    .done(function(response) {
  183
+      N.onAddresses(response);
  184
+      $.getJSON(SEARCH_API)
  185
+        .done(function(response) {
  186
+          N.onWorkSpecs(response);
  187
+          $('#loading').hide();
  188
+        })
  189
+        .fail(N.onAjaxFailed);
  190
+    })
  191
+    .fail(N.onAjaxFail)
236 192
 }
2  zivimap/templates/base.html
@@ -95,10 +95,8 @@
95 95
     {% js_lib 'markerclustererplus_compiled.js' %}
96 96
     {% js_lib 'bootstrap.min.js' %}
97 97
     {% js_lib 'underscore-min.js' %}
98  
-    {% js_lib 'backbone-min.js' %}
99 98
     {% js_lib 'date.js' %}
100 99
     {% js_lib 'daterangepicker.js' %}
101  
-    <script type="text/javascript" src="{{ STATIC_URL }}js/backbone-tastypie.js"></script>
102 100
 
103 101
     <!-- Google analytics -->
104 102
     <script type="text/javascript">
7  zivimap/templates/index.html
@@ -19,7 +19,8 @@
19 19
     SEARCH_API = "{{ workspec_search_url }}";
20 20
 
21 21
     var App = {};
22  
-    $(initMap(App));
  22
+    newInitMap(App);
  23
+    //$(initMap(App));
23 24
 </script>
24 25
 
25 26
 <!-- Social stuff -->
@@ -34,6 +35,10 @@
34 35
 {% endblock %}
35 36
 
36 37
 {% block content %}
  38
+<!-- horizontally centered loading -->
  39
+<div id="loading" style="position:absolute; left: 50%;">
  40
+  <div id="loading-inner"><h3><img src="{% static 'img/ajax-loader.gif' %}"> Loading</h3></div>
  41
+</div>
37 42
 
38 43
 <div id="map_canvas"></div>
39 44
 

0 notes on commit b3c5a44

Please sign in to comment.
Something went wrong with that request. Please try again.