diff options
Diffstat (limited to 'public/js/vendor/easy-button.js')
-rw-r--r-- | public/js/vendor/easy-button.js | 379 |
1 files changed, 379 insertions, 0 deletions
diff --git a/public/js/vendor/easy-button.js b/public/js/vendor/easy-button.js new file mode 100644 index 0000000..f71e072 --- /dev/null +++ b/public/js/vendor/easy-button.js @@ -0,0 +1,379 @@ +(function(){ + +// This is for grouping buttons into a bar +// takes an array of `L.easyButton`s and +// then the usual `.addTo(map)` +L.Control.EasyBar = L.Control.extend({ + + options: { + position: 'topleft', // part of leaflet's defaults + id: null, // an id to tag the Bar with + leafletClasses: true // use leaflet classes? + }, + + + initialize: function(buttons, options){ + + if(options){ + L.Util.setOptions( this, options ); + } + + this._buildContainer(); + this._buttons = []; + + for(var i = 0; i < buttons.length; i++){ + buttons[i]._bar = this; + buttons[i]._container = buttons[i].button; + this._buttons.push(buttons[i]); + this.container.appendChild(buttons[i].button); + } + + }, + + + _buildContainer: function(){ + this._container = this.container = L.DomUtil.create('div', ''); + this.options.leafletClasses && L.DomUtil.addClass(this.container, 'leaflet-bar easy-button-container leaflet-control'); + this.options.id && (this.container.id = this.options.id); + }, + + + enable: function(){ + L.DomUtil.addClass(this.container, 'enabled'); + L.DomUtil.removeClass(this.container, 'disabled'); + this.container.setAttribute('aria-hidden', 'false'); + return this; + }, + + + disable: function(){ + L.DomUtil.addClass(this.container, 'disabled'); + L.DomUtil.removeClass(this.container, 'enabled'); + this.container.setAttribute('aria-hidden', 'true'); + return this; + }, + + + onAdd: function () { + return this.container; + }, + + addTo: function (map) { + this._map = map; + + for(var i = 0; i < this._buttons.length; i++){ + this._buttons[i]._map = map; + } + + var container = this._container = this.onAdd(map), + pos = this.getPosition(), + corner = map._controlCorners[pos]; + + L.DomUtil.addClass(container, 'leaflet-control'); + + if (pos.indexOf('bottom') !== -1) { + corner.insertBefore(container, corner.firstChild); + } else { + corner.appendChild(container); + } + + return this; + } + +}); + +L.easyBar = function(){ + var args = [L.Control.EasyBar]; + for(var i = 0; i < arguments.length; i++){ + args.push( arguments[i] ); + } + return new (Function.prototype.bind.apply(L.Control.EasyBar, args)); +}; + +// L.EasyButton is the actual buttons +// can be called without being grouped into a bar +L.Control.EasyButton = L.Control.extend({ + + options: { + position: 'topleft', // part of leaflet's defaults + + id: null, // an id to tag the button with + + type: 'replace', // [(replace|animate)] + // replace swaps out elements + // animate changes classes with all elements inserted + + states: [], // state names look like this + // { + // stateName: 'untracked', + // onClick: function(){ handle_nav_manually(); }; + // title: 'click to make inactive', + // icon: 'fa-circle', // wrapped with <a> + // } + + leafletClasses: true, // use leaflet styles for the button + tagName: 'button', + }, + + + + initialize: function(icon, onClick, title, id){ + + // clear the states manually + this.options.states = []; + + // add id to options + if(id != null){ + this.options.id = id; + } + + // storage between state functions + this.storage = {}; + + // is the last item an object? + if( typeof arguments[arguments.length-1] === 'object' ){ + + // if so, it should be the options + L.Util.setOptions( this, arguments[arguments.length-1] ); + } + + // if there aren't any states in options + // use the early params + if( this.options.states.length === 0 && + typeof icon === 'string' && + typeof onClick === 'function'){ + + // turn the options object into a state + this.options.states.push({ + icon: icon, + onClick: onClick, + title: typeof title === 'string' ? title : '' + }); + } + + // curate and move user's states into + // the _states for internal use + this._states = []; + + for(var i = 0; i < this.options.states.length; i++){ + this._states.push( new State(this.options.states[i], this) ); + } + + this._buildButton(); + + this._activateState(this._states[0]); + + }, + + _buildButton: function(){ + + this.button = L.DomUtil.create(this.options.tagName, ''); + + // the next three if statements should be collapsed into the options + // when it's time for breaking changes. + if (this.tagName === 'button') { + this.button.type = 'button'; + } + + if (this.options.id ){ + this.button.id = this.options.id; + } + + if (this.options.leafletClasses){ + L.DomUtil.addClass(this.button, 'easy-button-button leaflet-bar-part leaflet-interactive'); + } + + // don't let double clicks and mousedown get to the map + L.DomEvent.addListener(this.button, 'dblclick', L.DomEvent.stop); + L.DomEvent.addListener(this.button, 'mousedown', L.DomEvent.stop); + + // take care of normal clicks + L.DomEvent.addListener(this.button,'click', function(e){ + L.DomEvent.stop(e); + this._currentState.onClick(this, this._map ? this._map : null ); + this._map.getContainer().focus(); + }, this); + + // prep the contents of the control + if(this.options.type == 'replace'){ + this.button.appendChild(this._currentState.icon); + } else { + for(var i=0;i<this._states.length;i++){ + this.button.appendChild(this._states[i].icon); + } + } + }, + + + _currentState: { + // placeholder content + stateName: 'unnamed', + icon: (function(){ return document.createElement('span'); })() + }, + + + + _states: null, // populated on init + + + + state: function(newState){ + + // activate by name + if(typeof newState == 'string'){ + + this._activateStateNamed(newState); + + // activate by index + } else if (typeof newState == 'number'){ + + this._activateState(this._states[newState]); + } + + return this; + }, + + + _activateStateNamed: function(stateName){ + for(var i = 0; i < this._states.length; i++){ + if( this._states[i].stateName == stateName ){ + this._activateState( this._states[i] ); + } + } + }, + + _activateState: function(newState){ + + if( newState === this._currentState ){ + + // don't touch the dom if it'll just be the same after + return; + + } else { + + // swap out elements... if you're into that kind of thing + if( this.options.type == 'replace' ){ + this.button.appendChild(newState.icon); + this.button.removeChild(this._currentState.icon); + } + + if( newState.title ){ + this.button.title = newState.title; + } else { + this.button.removeAttribute('title'); + } + + // update classes for animations + for(var i=0;i<this._states.length;i++){ + L.DomUtil.removeClass(this._states[i].icon, this._currentState.stateName + '-active'); + L.DomUtil.addClass(this._states[i].icon, newState.stateName + '-active'); + } + + // update classes for animations + L.DomUtil.removeClass(this.button, this._currentState.stateName + '-active'); + L.DomUtil.addClass(this.button, newState.stateName + '-active'); + + // update the record + this._currentState = newState; + + } + }, + + + + enable: function(){ + L.DomUtil.addClass(this.button, 'enabled'); + L.DomUtil.removeClass(this.button, 'disabled'); + this.button.setAttribute('aria-hidden', 'false'); + return this; + }, + + + + disable: function(){ + L.DomUtil.addClass(this.button, 'disabled'); + L.DomUtil.removeClass(this.button, 'enabled'); + this.button.setAttribute('aria-hidden', 'true'); + return this; + }, + + + removeFrom: function (map) { + + this._container.parentNode.removeChild(this._container); + this._map = null; + + return this; + }, + + onAdd: function(){ + var containerObj = L.easyBar([this], { + position: this.options.position, + leafletClasses: this.options.leafletClasses + }); + this._container = containerObj.container; + return this._container; + } + + +}); + +L.easyButton = function(/* args will pass automatically */){ + var args = Array.prototype.concat.apply([L.Control.EasyButton],arguments); + return new (Function.prototype.bind.apply(L.Control.EasyButton, args)); +}; + +/************************* + * + * util functions + * + *************************/ + +// constructor for states so only curated +// states end up getting called +function State(template, easyButton){ + + this.title = template.title; + this.stateName = template.stateName ? template.stateName : 'unnamed-state'; + + // build the wrapper + this.icon = L.DomUtil.create('span', ''); + + L.DomUtil.addClass(this.icon, 'button-state state-' + this.stateName.replace(/(^\s*|\s*$)/g,'')); + this.icon.innerHTML = buildIcon(template.icon); + this.onClick = L.Util.bind(template.onClick?template.onClick:function(){}, easyButton); +} + +function buildIcon(ambiguousIconString) { + + var tmpIcon; + + // does this look like html? (i.e. not a class) + if( ambiguousIconString.match(/[&;=<>"']/) ){ + + // if so, the user should have put in html + // so move forward as such + tmpIcon = ambiguousIconString; + + // then it wasn't html, so + // it's a class list, figure out what kind + } else { + ambiguousIconString = ambiguousIconString.replace(/(^\s*|\s*$)/g,''); + tmpIcon = L.DomUtil.create('span', ''); + + if( ambiguousIconString.indexOf('fa-') === 0 ){ + L.DomUtil.addClass(tmpIcon, 'fa ' + ambiguousIconString) + } else if ( ambiguousIconString.indexOf('glyphicon-') === 0 ) { + L.DomUtil.addClass(tmpIcon, 'glyphicon ' + ambiguousIconString) + } else { + L.DomUtil.addClass(tmpIcon, /*rollwithit*/ ambiguousIconString) + } + + // make this a string so that it's easy to set innerHTML below + tmpIcon = tmpIcon.outerHTML; + } + + return tmpIcon; +} + +})(); |