goog.provide('M.Popup'); goog.require('M.utils'); goog.require('M.exception'); goog.require('M.facade.Base'); (function () { /** * @classdesc * Main constructor of the class. Creates a layer * with parameters specified by the user * * @constructor * @extends {M.facade.Base} * @api stable */ M.Popup = (function (options) { /** * TODO * @private * @type {Array<Number>} */ this.coord_ = null; /** * TODO * @private * @type {Array<M.Popup.Tab>} */ this.tabs_ = []; /** * TODO * @private * @type {HTMLElement} */ this.element_ = null; /** * TODO * @private * @type {string} */ this.status_ = M.Popup.status.COLLAPSED; var impl = new M.impl.Popup(options); // calls the super constructor goog.base(this, impl); }); goog.inherits(M.Popup, M.facade.Base); /** * TODO * @public * @function * @api stable */ M.Popup.prototype.getTabs = function () { return this.tabs_; }; /** * TODO * @public * @function * @api stable */ M.Popup.prototype.removeTab = function (tabToRemove) { this.tabs_ = this.tabs_.filter(function (tab) { return (tab.content !== tabToRemove.content); }); this.update(); }; /** * TODO * @public * @function * @api stable */ M.Popup.prototype.addTab = function (tabOptions) { var tab = tabOptions; if (!(tab instanceof M.Popup.Tab)) { tab = new M.Popup.Tab(tabOptions); } this.tabs_.push(tab); this.update(); }; /** * TODO * @public * @function * @api stable */ M.Popup.prototype.addTo = function (map, coordinate) { this.map_ = map; if (M.utils.isNullOrEmpty(this.element_)) { var this_ = this; M.template.compile(M.Popup.TEMPLATE, { 'jsonp': true, 'vars': { 'tabs': this.tabs_ } }).then(function (html) { this_.element_ = html; this_.addEvents(html); this_.getImpl().addTo(map, html); this_.show(coordinate); }); } else { this.getImpl().addTo(map, this.element_); this.show(coordinate); } }; /** * TODO * @public * @function * @api stable */ M.Popup.prototype.update = function () { if (!M.utils.isNullOrEmpty(this.map_)) { var this_ = this; M.template.compile(M.Popup.TEMPLATE, { 'jsonp': true, 'vars': { 'tabs': this.tabs_ } }).then(function (html) { this_.element_ = html; this_.addEvents(html); this_.getImpl().setContainer(html); this_.show(this_.coord_); }); } }; /** * TODO * @public * @function * @api stable */ M.Popup.prototype.show = function (coord) { this.coord_ = coord; this.getImpl().show(this.coord_, function () { this.fire(M.evt.SHOW); }.bind(this)); // this.setStatus_(M.Popup.status.COLLAPSED); }; /** * TODO * @public * @function * @api stable */ M.Popup.prototype.hide = function (evt) { if (!M.utils.isNullOrEmpty(evt)) { evt.preventDefault(); } this.getImpl().hide(); }; /** * TODO * @public * @function * @api stable */ M.Popup.prototype.switchTab = function (index) { if (this.tabs_.length > index) { var tab = this.tabs_[index]; this.setContent_(tab.content); this.show(this.coord_); } }; /** * TODO * @private * @function */ M.Popup.prototype.setContent_ = function (content) { this.getImpl().setContent(content); }; /** * TODO * @private * @function */ M.Popup.prototype.getContent = function () { return this.getImpl().getContent(); }; /** * TODO * @private * @function */ M.Popup.prototype.addEvents = function (html) { // adds tabs events var touchstartY; var tabs = html.querySelectorAll('div.m-tab'); Array.prototype.forEach.call(tabs, function (tab) { goog.events.listen(tab, [ goog.events.EventType.CLICK, goog.events.EventType.TOUCHEND ], function (evt) { evt.preventDefault(); // 5px tolerance var touchendY = evt.clientY; if ((evt.type === goog.events.EventType.CLICK) || (Math.abs(touchstartY - touchendY) < 5)) { // remove m-activated from all tabs Array.prototype.forEach.call(tabs, function (addedTab) { goog.dom.classlist.remove(addedTab, 'm-activated'); }); goog.dom.classlist.add(tab, 'm-activated'); var index = tab.getAttribute('data-index'); this.switchTab(index); } }, false, this); }, this); // adds close event var closeBtn = html.querySelector('a.m-popup-closer'); goog.events.listen(closeBtn, [ goog.events.EventType.CLICK, goog.events.EventType.TOUCHEND ], this.hide, false, this); // mobile events var headerElement = html.querySelector('div.m-tabs'); if (M.utils.isNullOrEmpty(headerElement)) { headerElement = html.querySelector('div.m-content > div.m-header'); } if (!M.utils.isNullOrEmpty(headerElement)) { var topPosition; goog.events.listen(headerElement, [ goog.events.EventType.TOUCHSTART ], function (evt) { evt.preventDefault(); touchstartY = evt.clientY; if (this.status_ === M.Popup.status.COLLAPSED) { topPosition = 0.9 * M.window.HEIGHT; } else if (this.status_ === M.Popup.status.DEFAULT) { topPosition = 0.45 * M.window.HEIGHT; } else if (this.status_ === M.Popup.status.FULL) { topPosition = 0; } goog.dom.classlist.add(html, 'm-no-animation'); }, false, this); goog.events.listen(headerElement, [ goog.events.EventType.TOUCHMOVE ], function (evt) { evt.preventDefault(); var touchY = evt.clientY; var translatedPixels = touchY - touchstartY; goog.style.setStyle(html, 'top', (topPosition + translatedPixels) + 'px'); }, false, this); goog.events.listen(headerElement, [ goog.events.EventType.TOUCHEND ], function (evt) { evt.preventDefault(); var touchendY = evt.clientY; this.manageCollapsiblePopup_(touchstartY, touchendY); }, false, this); // CLICK EVENTS goog.events.listen(headerElement, [ goog.events.EventType.MOUSEUP ], function (evt) { evt.preventDefault(); // COLLAPSED --> DEFAULT if (this.status_ === M.Popup.status.COLLAPSED) { this.setStatus_(M.Popup.status.DEFAULT); } // DEFAULT --> FULL else if (this.status_ === M.Popup.status.DEFAULT) { this.setStatus_(M.Popup.status.FULL); } else { this.setStatus_(M.Popup.status.COLLAPSED); } }, false, this); } }; /** * TODO * @private * @function */ M.Popup.prototype.setStatus_ = function (status) { if (status !== this.status_) { goog.dom.classlist.remove(this.element_, this.status_); this.status_ = status; goog.dom.classlist.add(this.element_, this.status_); goog.style.setStyle(this.element_, 'top', ''); goog.dom.classlist.remove(this.element_, 'm-no-animation'); // mobile center if (M.window.WIDTH <= M.config.MOBILE_WIDTH) { this.getImpl().centerByStatus(status, this.coord_); } } }; /** * TODO * @private * @function */ M.Popup.prototype.manageCollapsiblePopup_ = function (touchstartY, touchendY) { var touchPerc = (touchendY * 100) / M.window.HEIGHT; var distanceTouch = Math.abs(touchstartY - touchendY); var distanceTouchPerc = (distanceTouch * 100) / M.window.HEIGHT; // 10% tolerance if (distanceTouchPerc > 10) { /* * manages collapsing events depending on * the current position of the popup header and the direction * * These are the thresholds: * _____________ ____________ * | 0% | FULL * |-------------| * | | * | 45% | * | | 2 * |-------------| ------------ * | | 1 DEFAULT * | | * | | * |-------------| ------------ * | 85% | COLLAPSED * |_____________| * */ if (this.status_ === M.Popup.status.COLLAPSED) { // 2 if (touchPerc < 45) { this.setStatus_(M.Popup.status.FULL); } // 1 else if (touchPerc < 85) { this.setStatus_(M.Popup.status.DEFAULT); } else { this.setStatus_(M.Popup.status.COLLAPSED); } } else if (this.status_ === M.Popup.status.DEFAULT) { // 1 if (touchPerc > 45) { this.setStatus_(M.Popup.status.COLLAPSED); } // 2 else if (touchPerc < 45) { this.setStatus_(M.Popup.status.FULL); } else { this.setStatus_(M.Popup.status.DEFAULT); } } else if (this.status_ === M.Popup.status.FULL) { // 1 if (touchPerc > 45) { this.setStatus_(M.Popup.status.COLLAPSED); } // 2 else if (touchPerc > 0) { this.setStatus_(M.Popup.status.DEFAULT); } else { this.setStatus_(M.Popup.status.FULL); } } } else { this.setStatus_(this.status_); } }; /** * TODO * @public * @function * @api stable */ M.Popup.prototype.getCoordinate = function () { return this.coord_; }; /** * TODO * @public * @function * @api stable */ M.Popup.prototype.setCoordinate = function (coord) { this.coord_ = coord; if (!M.utils.isNullOrEmpty(this.element_)) { this.getImpl().show(coord); } }; /** * TODO * @public * @function * @api stable */ M.Popup.prototype.destroy = function () { this.tabs_.length = 0; this.coord_ = null; this.fire(M.evt.DESTROY); }; /** * Template for popup * @const * @type {string} * @public * @api stable */ M.Popup.TEMPLATE = 'popup.html'; /** * status of this popup * @const * @type {object} * @public * @api stable */ M.Popup.status = {}; /** * collapsed status of this popup * @const * @type {string} * @public * @api stable */ M.Popup.status.COLLAPSED = 'm-collapsed'; /** * default status of this popup * @const * @type {string} * @public * @api stable */ M.Popup.status.DEFAULT = 'm-default'; /** * full status of this popup * @const * @type {string} * @public * @api stable */ M.Popup.status.FULL = 'm-full'; /** * @classdesc * Main constructor of the class. Creates a layer * with parameters specified by the user * * @constructor */ M.Popup.Tab = (function (options) { options = (options || {}); /** * TODO * @public * @type {String} * @api stable * @expose */ this.icon = options.icon; /** * TODO * @public * @type {String} * @api stable * @expose */ this.title = options.title; /** * TODO * @public * @type {String} * @api stable * @expose */ this.content = options.content; }); })();