diff --git a/fabfile.py b/fabfile.py index ac773963..62b26cfd 100644 --- a/fabfile.py +++ b/fabfile.py @@ -244,7 +244,6 @@ def collect_remote_statics(): 'storage': 'git://github.com/yohanboniface/Leaflet.Storage.git@master', 'edit_in_osm': 'git://github.com/yohanboniface/Leaflet.EditInOSM.git@master', 'minimap': 'git://github.com/Norkart/Leaflet-MiniMap.git@master', - 'darline': 'git://github.com/yohanboniface/Darline.git@master', 'i18n': 'git://github.com/yohanboniface/Leaflet.i18n.git@master', 'csv2geojson': 'git://github.com/mapbox/csv2geojson.git@gh-pages', 'togeojson': 'git://github.com/mapbox/togeojson.git@gh-pages', diff --git a/umap/static/darline b/umap/static/darline deleted file mode 160000 index 987916f7..00000000 --- a/umap/static/darline +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 987916f72bf3601e4c70402a4434d53b951284ac diff --git a/umap/static/favicon.ico b/umap/static/favicon.ico index 8db4c81a..0aa459cc 100644 Binary files a/umap/static/favicon.ico and b/umap/static/favicon.ico differ diff --git a/umap/static/umap/js/autocomplete.js b/umap/static/umap/js/autocomplete.js new file mode 100644 index 00000000..df9e1a6d --- /dev/null +++ b/umap/static/umap/js/autocomplete.js @@ -0,0 +1,339 @@ + +L.S.autoComplete = function (el, options) { + + var API = { + options: { + placeholder: "Start typing...", + emptyMessage: "No result", + allowFree: true, + minChar: 2, + maxResults: 5 + }, + + CACHE: '', + RESULTS: [], + + _init: function (el, options) { + this.el = L.DomUtil.get(el); + this.options = L.Util.extend(this.options, options); + var CURRENT = null; + try { + Object.defineProperty(this, "CURRENT", { + get: function () { + return CURRENT; + }, + set: function (index) { + if (typeof index === "object") { + index = this.resultToIndex(index); + } + CURRENT = index; + } + }); + } catch (e) { + // Hello IE8 + } + return this; + }, + + createInput: function () { + this.input = L.DomUtil.element('input', { + type: 'text', + placeholder: this.options.placeholder, + autocomplete: "off" + }); + L.DomUtil.before(this.el, this.input); + L.DomEvent.on(this.input, "keydown", this.onKeyDown, this); + L.DomEvent.on(this.input, "keyup", this.onKeyUp, this); + L.DomEvent.on(this.input, "blur", this.onBlur, this); + }, + + createContainer: function () { + this.container = L.DomUtil.element('ul', {className: 'umap-autocomplete'}, document.querySelector('body')); + }, + + resizeContainer: function() + { + var l = this.getLeft(this.input); + var t = this.getTop(this.input) + this.input.offsetHeight; + this.container.style.left = l + 'px'; + this.container.style.top = t + 'px'; + var width = this.options.width ? this.options.width : this.input.offsetWidth - 2; + this.container.style.width = width + "px"; + }, + + onKeyDown: function (e) { + switch (e.keyCode) { + case L.S.Keys.TAB: + if(this.CURRENT !== null) + { + this.setChoice(); + } + L.DomEvent.stop(e); + break; + case L.S.Keys.RETURN: + L.DomEvent.stop(e); + this.setChoice(); + break; + case L.S.Keys.ESC: + L.DomEvent.stop(e); + this.hide(); + break; + case L.S.Keys.DOWN: + if(this.RESULTS.length > 0) { + if(this.CURRENT !== null && this.CURRENT < this.RESULTS.length - 1) { // what if one resutl? + this.CURRENT++; + this.highlight(); + } + else if(this.CURRENT === null) { + this.CURRENT = 0; + this.highlight(); + } + } + break; + case L.S.Keys.UP: + if(this.CURRENT !== null) { + L.DomEvent.stop(e); + } + if(this.RESULTS.length > 0) { + if(this.CURRENT > 0) { + this.CURRENT--; + this.highlight(); + } + else if(this.CURRENT === 0) { + this.CURRENT = null; + this.highlight(); + } + } + break; + } + }, + + onKeyUp: function (e) { + var special = [ + L.S.Keys.TAB, + L.S.Keys.RETURN, + L.S.Keys.LEFT, + L.S.Keys.RIGHT, + L.S.Keys.DOWN, + L.S.Keys.UP, + L.S.Keys.APPLE, + L.S.Keys.SHIFT, + L.S.Keys.ALT, + L.S.Keys.CTRL + ]; + if (special.indexOf(e.keyCode) === -1) + { + this.search(); + } + }, + + onBlur: function (e) { + var self = this; + setTimeout(function () { + self.hide(); + }, 100); + }, + + clear: function () { + this.RESULTS = []; + this.CURRENT = null; + this.CACHE = ''; + this.container.innerHTML = ''; + }, + + hide: function() { + this.clear(); + this.container.style.display = 'none'; + this.input.value = ""; + }, + + setChoice: function (choice) { + choice = choice || this.RESULTS[this.CURRENT]; + if (choice) { + this.input.value = choice.display; + this.select(choice); + this.displaySelected(choice); + this.hide(); + if (this.options.callback) { + L.Util.bind(this.options.callback, this)(choice); + } + } + }, + + search: function() { + var val = this.input.value; + if (val.length < this.options.minChar) { + this.clear(); + return; + } + if(!val) { + this.clear(); + return; + } + if( val + '' === this.CACHE + '') { + return; + } + else { + this.CACHE = val; + } + var results = this._do_search(val); + return this.handleResults(results); + }, + + createResult: function (item) { + var el = L.DomUtil.element('li', {}, this.container); + el.innerHTML = item.display; + var result = { + value: item.value, + display: item.display, + el: el + }; + L.DomEvent.on(el, 'mouseover', function (e) { + this.CURRENT = result; + this.highlight(); + }, this); + L.DomEvent.on(el, 'mousedown', function (e) { + this.setChoice(); + }, this); + return result; + }, + + resultToIndex: function (result) { + var out = null; + this.forEach(this.RESULTS, function (item, index) { + if (item.value == result.value) { + out = index; + return; + } + }); + return out; + }, + + handleResults: function(data) { + var self = this; + this.clear(); + this.container.style.display = "block"; + this.resizeContainer(); + this.forEach(data, function (item, index) { + self.RESULTS.push(self.createResult(item)); + }); + this.CURRENT = 0; + this.highlight(); + //TODO manage no results + }, + + highlight: function () { + var self = this; + this.forEach(this.RESULTS, function (item, index) { + if (index === self.CURRENT) { + L.DomUtil.addClass(item.el, 'on'); + } + else { + L.DomUtil.removeClass(item.el, 'on'); + } + }); + }, + + getLeft: function (el) { + var tmp = el.offsetLeft; + el = el.offsetParent; + while(el) { + tmp += el.offsetLeft; + el = el.offsetParent; + } + return tmp; + }, + + getTop: function (el) { + var tmp = el.offsetTop; + el = el.offsetParent; + while(el) { + tmp += el.offsetTop; + el = el.offsetParent; + } + return tmp; + }, + + forEach: function (els, callback) { + Array.prototype.forEach.call(els, callback); + } + + }; + + var MULTISELECT = { + + init: function (el, options) { + this._init(el, options); + if (!this.el) return this; + this.el.style.display = "none"; + this.createInput(); + this.createContainer(); + this.initSelectedContainer(); + }, + + initSelectedContainer: function (initial) { + this.selected_container = L.DomUtil.after(this.input, L.DomUtil.element('ul', {className: 'umap-multiresult'})); + var self = this; + this.forEach(this.el, function (option) { + if (option.selected) { + self.displaySelected(self.optionToResult(option)); + } + }); + }, + + optionToResult: function (option) { + return { + value: option.value, + display: option.innerHTML + }; + }, + + displaySelected: function (result) { + var result_el = L.DomUtil.element('li', {}, this.selected_container); + result_el.innerHTML = result.display; + var close = L.DomUtil.element('span', {className: 'close'}, result_el); + close.innerHTML = "×"; + L.DomEvent.on(close, 'click', function () { + this.selected_container.removeChild(result_el); + this.unselect(result); + }, this); + this.hide(); + }, + + _do_search: function (val) { + var results = [], + self = this, + count = 0; + this.forEach(this.el, function (item, index) { + if (item.innerHTML.toLowerCase().indexOf(val.toLowerCase()) !== -1 && !item.selected && count < self.options.maxResults) { + results.push(self.optionToResult(item)); + count++; + } + }); + return results; + }, + + select: function (option) { + this.forEach(this.el, function (item, index) { + if (item.value == option.value) { + item.selected = true; + } + }); + }, + + unselect: function (option) { + this.forEach(this.el, function (item, index) { + if (item.value == option.value) { + item.selected = false; + } + }); + } + + }; + + this.multiselect = function () { + return L.Util.extend(API, MULTISELECT).init(el, options); + }; + return this; + +}; \ No newline at end of file diff --git a/umap/static/umap/umap.css b/umap/static/umap/umap.css index 8143235b..54b69e59 100644 --- a/umap/static/umap/umap.css +++ b/umap/static/umap/umap.css @@ -552,6 +552,41 @@ a { } +/* **************************** */ +/* Autocomplete */ +/* **************************** */ +ul.umap-autocomplete { + position: absolute; + background-color: white; + z-index: 1000; + box-shadow: 0 4px 9px #999999; +} +.umap-autocomplete li { + height: 56px; + line-height: 28px; + padding: 14px; +} +.umap-autocomplete li.on { + background-color: SeaGreen; + cursor: pointer; +} +.umap-multiresult li { + width: 100%; + background-color: #e5e5e5; + border-radius: 2px; + padding: 7px; + color: #464646; +} +.umap-multiresult li + li { + margin-top: 7px; +} +.umap-multiresult li .close { + float: right; + cursor: pointer; +} + + + /* **************************** */ /* Override Leaflet.Storage */ /* **************************** */ diff --git a/umap/templates/base.html b/umap/templates/base.html index 6ac58a31..af4e8614 100644 --- a/umap/templates/base.html +++ b/umap/templates/base.html @@ -6,21 +6,18 @@ {% compress css %} - {% endcompress css %} - {% compress js %} - - - - {% endcompress js %} {% block extra_head %} {% endblock extra_head %} + {% compress js %} + + {% endcompress js %} @@ -37,8 +34,8 @@ {% block bottom_js %}