diff options
Diffstat (limited to 'public/js/vendor/Leaflet.Modal.js')
-rw-r--r-- | public/js/vendor/Leaflet.Modal.js | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/public/js/vendor/Leaflet.Modal.js b/public/js/vendor/Leaflet.Modal.js new file mode 100644 index 0000000..0962269 --- /dev/null +++ b/public/js/vendor/Leaflet.Modal.js @@ -0,0 +1,361 @@ +/** + * Leaflet modal control + * + * @license MIT + * @author Alexander Milevski <info@w8r.name> + * @preserve + */ + +"use strict"; + +/** + * Modal handler + * @class {L.Map.Modal} + * @extends {L.Mixin.Events} + * @extends {L.Handler} + */ +L.Map.Modal = L.Handler.extend( /** @lends {L.Map.Hadler.prototype} */ { + + includes: L.Evented ? L.Evented.prototype : L.Mixin.Events, + + /** + * @static + * @type {Object} + */ + statics: { + BASE_CLS: 'leaflet-modal', + HIDE: 'modal.hide', + SHOW_START: 'modal.showStart', + SHOW: 'modal.show', + CHANGED: 'modal.changed', + /** + * "foo bar baz" -> ".foo.bar.baz" + * @param {String} classString + * @return {String} + */ + classNameToSelector: function(classString) { + return (' ' + classString).split(' ').join('.').replace(/^\s+|\s+$/g, ''); + } + }, + + /** + * @type {Object} + */ + options: { + OVERLAY_CLS: 'overlay', + MODAL_CLS: 'modal', + MODAL_CONTENT_CLS: 'modal-content', + INNER_CONTENT_CLS: 'modal-inner', + SHOW_CLS: 'show', + CLOSE_CLS: 'close', + + closeTitle: 'close', + zIndex: 10000, + transitionDuration: 300, + + wrapperTemplate: [ + '<div class="{OVERLAY_CLS}"></div>', + '<div class="{MODAL_CLS}"><div class="{MODAL_CONTENT_CLS}">', + '<span class="{CLOSE_CLS}" title="{closeTitle}">×</span>', + '<div class="{INNER_CONTENT_CLS}">{_content}</div>', + '</div></div>' + ].join(''), + + template: '{content}', + content: '' + + }, + + /** + * @constructor + * @param {L.Map} map + * @param {Object=} options + */ + initialize: function(map, options) { + L.Handler.prototype.initialize.call(this, map); + L.Util.setOptions(this, options); + + this._visible = false; + + var container = this._container = + L.DomUtil.create('div', L.Map.Modal.BASE_CLS, map._container); + container.style.zIndex = this.options.zIndex; + container.style.position = 'absolute'; + this._map._controlContainer.appendChild(container); + + L.DomEvent + .disableClickPropagation(container) + .disableScrollPropagation(container); + L.DomEvent.on(container, 'contextmenu', L.DomEvent.stopPropagation); + + this.enable(); + }, + + /** + * Add events and keyboard handlers + */ + addHooks: function() { + L.DomEvent.on(document, 'keydown', this._onKeyDown, this); + this._map.on({ + modal: this._show + }, this); + }, + + /** + * Disable handlers + */ + removeHooks: function() { + L.DomEvent.off(document, 'keydown', this._onKeyDown, this); + this._map.off({ + modal: this._show + }, this); + }, + + /** + * @return {L.Map.Modal} + */ + hide: function() { + this._hide(); + return this; + }, + + /** + * @return {Boolean} + */ + isVisible: function() { + return this._visible; + }, + + /** + * Show again, or just resize and re-position + * @param {Object=} options + */ + update: function(options) { + if (options) { + this._show(options); + } else { + this._updatePosition(); + } + }, + + /** + * @param {String} content + */ + setContent: function(content) { + this._getInnerContentContainer().innerHTML = content; + this.update(); + }, + + /** + * Update container position + */ + _updatePosition: function() { + var content = this._getContentContainer(); + var mapSize = this._map.getSize(); + + if (content.offsetHeight < mapSize.y) { + content.style.marginTop = ((mapSize.y - content.offsetHeight) / 2) + 'px'; + } else { + content.style.marginTop = ''; + } + }, + + /** + * @param {Object} options + */ + _show: function(options) { + if (this._visible) { + this._hide(); + } + options = L.Util.extend({}, this.options, options); + + this._render(options); + this._setContainerSize(options); + + this._updatePosition(); + + L.Util.requestAnimFrame(function() { + var contentContainer = this._getContentContainer(); + L.DomEvent.on(contentContainer, 'transitionend', this._onTransitionEnd, this); + L.DomEvent.disableClickPropagation(contentContainer); + L.DomUtil.addClass(this._container, this.options.SHOW_CLS); + + if (!L.Browser.any3d) { + L.Util.requestAnimFrame(this._onTransitionEnd, this); + } + }, this); + + var closeBtn = this._container.querySelector('.' + this.options.CLOSE_CLS); + if (closeBtn) { + L.DomEvent.on(closeBtn, 'click', this._onCloseClick, this); + } + + var modal = this._container.querySelector('.' + this.options.MODAL_CLS); + if (modal) { + L.DomEvent.on(modal, 'mousedown', this._onMouseDown, this); + } + + // callbacks + if (typeof options.onShow === 'function') { + this._map.once(L.Map.Modal.SHOW, options.onShow); + } + + if (typeof options.onHide === 'function') { + this._map.once(L.Map.Modal.HIDE, options.onHide); + } + + // fire event + this._map.fire(L.Map.Modal.SHOW_START, { + modal: this + }); + }, + + /** + * Show transition ended + * @param {TransitionEvent=} e + */ + _onTransitionEnd: function(e) { + var data = { + modal: this + }; + var map = this._map; + if (!this._visible) { + if (L.DomUtil.hasClass(this._container, this.options.SHOW_CLS)) { + this._visible = true; + map.fire(L.Map.Modal.SHOW, data); + } else { + map.fire(L.Map.Modal.HIDE, data); + } + } else { + map.fire(L.Map.Modal.CHANGED, data); + } + }, + + /** + * @param {L.MouseEvent} evt + */ + _onCloseClick: function(evt) { + L.DomEvent.stop(evt); + this._hide(); + }, + + /** + * Render template + * @param {Object} options + */ + _render: function(options) { + this._container.innerHTML = L.Util.template( + options.wrapperTemplate, + L.Util.extend({}, options, { + _content: L.Util.template(options.template, options) + }) + ); + if (options.element) { + var contentContainer = this._container.querySelector( + L.Map.Modal.classNameToSelector(this.options.MODAL_CONTENT_CLS)); + if (contentContainer) { + contentContainer.appendChild(options.element); + } + } + }, + + /** + * @return {Element} + */ + _getContentContainer: function() { + return this._container.querySelector( + L.Map.Modal.classNameToSelector(this.options.MODAL_CONTENT_CLS)); + }, + + /** + * Inner content, don't touch destroy button + * @return {Element} + */ + _getInnerContentContainer: function() { + return this._container.querySelector( + L.Map.Modal.classNameToSelector(this.options.INNER_CONTENT_CLS)) + }, + + /** + * @param {Object} options + * @param {Number} options.width + * @param {Number} options.height + */ + _setContainerSize: function(options) { + var content = this._getContentContainer(); + + if (options.width) { + content.style.width = options.width + 'px'; + } + + if (options.height) { + content.style.height = options.height + 'px'; + } + }, + + /** + * Hide blocks immediately + */ + _hideInternal: function() { + this._visible = false; + L.DomUtil.removeClass(this._container, this.options.SHOW_CLS); + }, + + /** + * Hide modal + */ + _hide: function() { + if (this._visible) { + this._hideInternal(); + + L.Util.requestAnimFrame(this._onTransitionEnd, this); + } + }, + + /** + * Mouse down on overlay + * @param {L.MouseEvent} evt + */ + _onMouseDown: function(evt) { + L.DomEvent.stop(evt); + var target = (evt.target || evt.srcElement); + if (L.DomUtil.hasClass(target, this.options.MODAL_CLS)) { + this._hide(); + } + }, + + /** + * Key stroke(escape) + * @param {KeyboardEvent} evt + */ + _onKeyDown: function(evt) { + var key = evt.keyCode || evt.which; + if (key === 27) { + this._hide(); + } + } + +}); + +// register hook +L.Map.addInitHook('addHandler', 'modal', L.Map.Modal); + +L.Map.include( /** @lends {L.Map.prototype} */ { + + /** + * @param {Object} options + * @return {L.Map} + */ + openModal: function(options) { + return this.fire('modal', options); + }, + + /** + * @return {L.Map} + */ + closeModal: function() { + this.modal.hide(); + return this; + } + +}); |