module.exports =
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
__export(__webpack_require__(2));
__export(__webpack_require__(8));
__export(__webpack_require__(41));
__export(__webpack_require__(58));
__export(__webpack_require__(76));
__export(__webpack_require__(77));
__export(__webpack_require__(78));
__export(__webpack_require__(9));
__export(__webpack_require__(80));
__export(__webpack_require__(12));
__export(__webpack_require__(34));
__export(__webpack_require__(16));
__export(__webpack_require__(20));
__export(__webpack_require__(36));
__export(__webpack_require__(84));
// these modules don't export anything
__webpack_require__(85);
__webpack_require__(86);
__webpack_require__(87);
__webpack_require__(88);
__webpack_require__(89);
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
var core_1 = __webpack_require__(3);
var router_1 = __webpack_require__(4);
var http_1 = __webpack_require__(5);
var app_1 = __webpack_require__(6);
var config_1 = __webpack_require__(8);
var platform_1 = __webpack_require__(9);
var overlay_controller_1 = __webpack_require__(13);
var form_1 = __webpack_require__(15);
var keyboard_1 = __webpack_require__(16);
var action_sheet_1 = __webpack_require__(17);
var modal_1 = __webpack_require__(31);
var popup_1 = __webpack_require__(32);
var events_1 = __webpack_require__(34);
var nav_registry_1 = __webpack_require__(35);
var translate_1 = __webpack_require__(36);
var click_block_1 = __webpack_require__(12);
var feature_detect_1 = __webpack_require__(37);
var tap_click_1 = __webpack_require__(38);
var dom_1 = __webpack_require__(11);
/**
* @private
*/
function ionicProviders(args) {
if (args === void 0) { args = {}; }
var platform = new platform_1.Platform();
var navRegistry = new nav_registry_1.NavRegistry(args.pages);
var config = args.config;
if (!(config instanceof config_1.Config)) {
config = new config_1.Config(config);
}
platform.url(window.location.href);
platform.userAgent(window.navigator.userAgent);
platform.navigatorPlatform(window.navigator.platform);
platform.load();
config.setPlatform(platform);
var clickBlock = new click_block_1.ClickBlock(config.get('clickBlock'));
var events = new events_1.Events();
var featureDetect = new feature_detect_1.FeatureDetect();
setupDom(window, document, config, platform, clickBlock, featureDetect);
bindEvents(window, document, platform, events);
// prepare the ready promise to fire....when ready
platform.prepareReady(config);
return [
app_1.IonicApp,
core_1.provide(click_block_1.ClickBlock, { useValue: clickBlock }),
core_1.provide(config_1.Config, { useValue: config }),
core_1.provide(platform_1.Platform, { useValue: platform }),
core_1.provide(feature_detect_1.FeatureDetect, { useValue: featureDetect }),
core_1.provide(events_1.Events, { useValue: events }),
core_1.provide(nav_registry_1.NavRegistry, { useValue: navRegistry }),
tap_click_1.TapClick,
form_1.Form,
keyboard_1.Keyboard,
overlay_controller_1.OverlayController,
action_sheet_1.ActionSheet,
modal_1.Modal,
popup_1.Popup,
translate_1.Translate,
router_1.ROUTER_PROVIDERS,
core_1.provide(router_1.LocationStrategy, { useClass: router_1.HashLocationStrategy }),
http_1.HTTP_PROVIDERS,
];
}
exports.ionicProviders = ionicProviders;
function setupDom(window, document, config, platform, clickBlock, featureDetect) {
var bodyEle = document.body;
var mode = config.get('mode');
// if dynamic mode links have been added the fire up the correct one
var modeLinkAttr = mode + '-href';
var linkEle = document.head.querySelector('link[' + modeLinkAttr + ']');
if (linkEle) {
var href = linkEle.getAttribute(modeLinkAttr);
linkEle.removeAttribute(modeLinkAttr);
linkEle.href = href;
}
// set the mode class name
// ios/md
bodyEle.classList.add(mode);
var versions = platform.versions();
platform.platforms().forEach(function (platformName) {
// platform-ios
var platformClass = 'platform-' + platformName;
bodyEle.classList.add(platformClass);
var platformVersion = versions[platformName];
if (platformVersion) {
// platform-ios9
platformClass += platformVersion.major;
bodyEle.classList.add(platformClass);
// platform-ios9_3
bodyEle.classList.add(platformClass + '_' + platformVersion.minor);
}
});
// touch devices should not use :hover CSS pseudo
// enable :hover CSS when the "hoverCSS" setting is not false
if (config.get('hoverCSS') !== false) {
bodyEle.classList.add('enable-hover');
}
if (config.get('clickBlock')) {
clickBlock.enable();
}
// run feature detection tests
featureDetect.run(window, document);
}
/**
* Bind some global events and publish on the 'app' channel
*/
function bindEvents(window, document, platform, events) {
window.addEventListener('online', function (ev) {
events.publish('app:online', ev);
}, false);
window.addEventListener('offline', function (ev) {
events.publish('app:offline', ev);
}, false);
window.addEventListener('orientationchange', function (ev) {
events.publish('app:rotated', ev);
});
// When that status taps, we respond
window.addEventListener('statusTap', function (ev) {
// TODO: Make this more better
var el = document.elementFromPoint(platform.width() / 2, platform.height() / 2);
if (!el) {
return;
}
var content = dom_1.closest(el, 'scroll-content');
if (content) {
var scrollTo = new ScrollTo(content);
scrollTo.start(0, 0, 300, 0);
}
});
// start listening for resizes XXms after the app starts
setTimeout(function () {
window.addEventListener('resize', function () {
platform.windowResize();
});
}, 2000);
}
/***/ },
/* 3 */
/***/ function(module, exports) {
module.exports = require("angular2")["core"];
/***/ },
/* 4 */
/***/ function(module, exports) {
module.exports = require("angular2")["router"];
/***/ },
/* 5 */
/***/ function(module, exports) {
module.exports = require("angular2")["http"];
/***/ },
/* 6 */
/***/ function(module, exports, __webpack_require__) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1 = __webpack_require__(3);
var browser_1 = __webpack_require__(7);
var config_1 = __webpack_require__(8);
var click_block_1 = __webpack_require__(12);
var dom_1 = __webpack_require__(11);
/**
* @private
* Component registry service. For more information on registering
* components see the [IdRef API reference](../id/IdRef/).
*/
var IonicApp = (function () {
function IonicApp(config, clickBlock, zone) {
this._config = config;
this._zone = zone;
this._titleSrv = new browser_1.Title();
this._title = '';
this._disTime = 0;
this._clickBlock = clickBlock;
// Our component registry map
this.components = {};
}
/**
* @private
* Sets the document title.
* @param {string} val Value to set the document title to.
*/
IonicApp.prototype.setTitle = function (val) {
var self = this;
if (val !== self._title) {
self._title = val;
this._zone.runOutsideAngular(function () {
function setAppTitle() {
self._titleSrv.setTitle(self._title);
}
dom_1.rafFrames(4, setAppTitle);
});
}
};
/**
* @private
* Sets if the app is currently enabled or not, meaning if it's
* available to accept new user commands. For example, this is set to `false`
* while views transition, a modal slides up, an action-sheet
* slides up, etc. After the transition completes it is set back to `true`.
* @param {bool} isEnabled
* @param {bool} fallback When `isEnabled` is set to `false`, this argument
* is used to set the maximum number of milliseconds that app will wait until
* it will automatically enable the app again. It's basically a fallback incase
* something goes wrong during a transition and the app wasn't re-enabled correctly.
*/
IonicApp.prototype.setEnabled = function (isEnabled, duration) {
if (duration === void 0) { duration = 700; }
this._disTime = (isEnabled ? 0 : Date.now() + duration);
if (duration > 32 || isEnabled) {
// only do a click block if the duration is longer than XXms
this._clickBlock.show(!isEnabled, duration + 64);
}
};
/**
* @private
* Boolean if the app is actively enabled or not.
* @return {bool}
*/
IonicApp.prototype.isEnabled = function () {
return (this._disTime < Date.now());
};
/**
* @private
* Register a known component with a key, for easy lookups later.
* @param {TODO} id The id to use to register the component
* @param {TODO} component The component to register
*/
IonicApp.prototype.register = function (id, component) {
if (this.components[id] && this.components[id] !== component) {
}
this.components[id] = component;
};
/**
* @private
* Unregister a known component with a key.
* @param {TODO} id The id to use to unregister
*/
IonicApp.prototype.unregister = function (id) {
delete this.components[id];
};
/**
* @private
* Get a registered component with the given type (returns the first)
* @param {Object} cls the type to search for
* @return the matching component, or undefined if none was found
*/
IonicApp.prototype.getRegisteredComponent = function (cls) {
for (var _i = 0, _a = this.components; _i < _a.length; _i++) {
var component = _a[_i];
if (component instanceof cls) {
return component;
}
}
};
/**
* @private
* Get the component for the given key.
* @param {TODO} key TODO
* @return {TODO} TODO
*/
IonicApp.prototype.getComponent = function (id) {
return this.components[id];
};
IonicApp = __decorate([
core_1.Injectable(),
__metadata('design:paramtypes', [(typeof (_a = typeof config_1.Config !== 'undefined' && config_1.Config) === 'function' && _a) || Object, (typeof (_b = typeof click_block_1.ClickBlock !== 'undefined' && click_block_1.ClickBlock) === 'function' && _b) || Object, (typeof (_c = typeof core_1.NgZone !== 'undefined' && core_1.NgZone) === 'function' && _c) || Object])
], IonicApp);
return IonicApp;
var _a, _b, _c;
})();
exports.IonicApp = IonicApp;
/***/ },
/* 7 */
/***/ function(module, exports) {
module.exports = require("angular2")["platform"]["browser"];
/***/ },
/* 8 */
/***/ function(module, exports, __webpack_require__) {
/**
* @ngdoc service
* @name Config
* @module ionic
* @description
* Config allows you to set the modes of your components
*/
var platform_1 = __webpack_require__(9);
var util_1 = __webpack_require__(10);
/**
* @name Config
* @demo /docs/v2/demos/config/
* @description
* Config lets you change multiple or a single value in an apps mode configuration. Things such as tab placement, icon changes, and view animations can be set here.
*
* ```ts
* @App({
* template: ``
* config: {
* backButtonText: 'Go Back',
* iconMode: 'ios',
* modalEnter: 'modal-slide-in',
* modalLeave: 'modal-slide-out',
* tabbarPlacement: 'bottom',
* pageTransition: 'ios',
* }
* })
* ```
*
* Config can be overwritting at multiple levels, allowing deeper configuration. Taking the example from earlier, we can override any setting we want based on a platform.
* ```ts
* @App({
* template: ``
* config: {
* tabbarPlacement: 'bottom',
* platforms: {
* ios: {
* tabbarPlacement: 'top',
* }
* }
* }
* })
* ```
*
* We could also configure these values at a component level. Take `tabbarPlacement`, we can configure this as a property on our `ion-tabs`.
*
* ```html
*
*
*
* ```
*
* The property will override anything else set in the apps.
*
* The last way we could configure is through URL query strings. This is useful for testing while in the browser.
* Simply add `?ionic=` to the url.
*
* ```bash
* http://localhost:8100/?ionicTabbarPlacement=bottom
* ```
*
* Custom values can be added to config, and looked up at a later point in time.
*
* ``` javascript
* config.set('ios', 'favoriteColor', 'green');
* // from any page in your app:
* config.get('favoriteColor'); // 'green'
* ```
*
*
* A config value can come from anywhere and be anything, but there are a default set of values.
*
*
* | Config property | Default iOS Value | Default MD Value |
* |----------------------------|------------------------|---------------------------|
* | activator | highlight | ripple |
* | actionSheetEnter | action-sheet-slide-in | action-sheet-md-slide-in |
* | actionSheetLeave | action-sheet-slide-out | action-sheet-md-slide-out |
* | actionSheetCancelIcon | | ion-md-close |
* | actionSheetDestructiveIcon | | ion-md-trash |
* | backButtonText | Back | |
* | backButtonIcon | ion-ios-arrow-back | ion-md-arrow-back |
* | iconMode | ios | md |
* | menuType | reveal | overlay |
* | modalEnter | modal-slide-in | modal-md-slide-in |
* | modalLeave | modal-slide-out | modal-md-slide-out |
* | pageTransition | ios-transition | md-transition |
* | pageTransitionDelay | 16 | 120 |
* | popupEnter | popup-pop-in | popup-md-pop-in |
* | popupLeave | popup-pop-out | popup-md-pop-out |
* | tabbarPlacement | bottom | true |
* | tabbarHighlight | | top |
* | tabSubPage | | true |
*
**/
var Config = (function () {
function Config(config) {
this._s = config && util_1.isObject(config) && !util_1.isArray(config) ? config : {};
this._c = {}; // cached values
}
/**
* For setting and getting multiple config values
*/
/**
* @private
* @name settings()
* @description
*/
Config.prototype.settings = function () {
var args = arguments;
switch (args.length) {
case 0:
return this._s;
case 1:
// settings({...})
this._s = args[0];
this._c = {}; // clear cache
break;
case 2:
// settings('ios', {...})
this._s.platforms = this._s.platforms || {};
this._s.platforms[args[0]] = args[1];
this._c = {}; // clear cache
break;
}
return this;
};
/**
* @name set
* @description
* Sets a single config value.
*
* @param {String} [platform] - The platform (either 'ios' or 'android') that the config value should apply to. Leaving this blank will apply the config value to all platforms.
* @param {String} [key] - The key used to look up the value at a later point in time.
* @param {String} [value] - The config value being stored.
*/
Config.prototype.set = function () {
var args = arguments;
var arg0 = args[0];
var arg1 = args[1];
switch (args.length) {
case 2:
// set('key', 'value') = set key/value pair
// arg1 = value
this._s[arg0] = arg1;
delete this._c[arg0]; // clear cache
break;
case 3:
// setting('ios', 'key', 'value') = set key/value pair for platform
// arg0 = platform
// arg1 = key
// arg2 = value
this._s.platforms = this._s.platforms || {};
this._s.platforms[arg0] = this._s.platforms[arg0] || {};
this._s.platforms[arg0][arg1] = args[2];
delete this._c[arg1]; // clear cache
break;
}
return this;
};
/**
* @name get
* @description
* Returns a single config value, given a key.
*
* @param {String} [key] - the key for the config value
*/
Config.prototype.get = function (key) {
if (!util_1.isDefined(this._c[key])) {
// if the value was already set this will all be skipped
// if there was no user config then it'll check each of
// the user config's platforms, which already contains
// settings from default platform configs
var userPlatformValue = undefined;
var userDefaultValue = this._s[key];
var userPlatformModeValue = undefined;
var userDefaultModeValue = undefined;
var platformValue = undefined;
var platformModeValue = undefined;
var configObj = null;
if (this._platform) {
var queryStringValue = this._platform.query('ionic' + key.toLowerCase());
if (util_1.isDefined(queryStringValue)) {
return this._c[key] = (queryStringValue === 'true' ? true : queryStringValue === 'false' ? false : queryStringValue);
}
// check the platform settings object for this value
// loop though each of the active platforms
// array of active platforms, which also knows the hierarchy,
// with the last one the most important
var activePlatformKeys = this._platform.platforms();
// loop through all of the active platforms we're on
for (var i = 0, l = activePlatformKeys.length; i < l; i++) {
// get user defined platform values
if (this._s.platforms) {
configObj = this._s.platforms[activePlatformKeys[i]];
if (configObj) {
if (util_1.isDefined(configObj[key])) {
userPlatformValue = configObj[key];
}
configObj = Config.getModeConfig(configObj.mode);
if (configObj && util_1.isDefined(configObj[key])) {
userPlatformModeValue = configObj[key];
}
}
}
// get default platform's setting
configObj = platform_1.Platform.get(activePlatformKeys[i]);
if (configObj && configObj.settings) {
if (util_1.isDefined(configObj.settings[key])) {
// found a setting for this platform
platformValue = configObj.settings[key];
}
configObj = Config.getModeConfig(configObj.settings.mode);
if (configObj && util_1.isDefined(configObj[key])) {
// found setting for this platform's mode
platformModeValue = configObj[key];
}
}
}
}
configObj = Config.getModeConfig(this._s.mode);
if (configObj && util_1.isDefined(configObj[key])) {
userDefaultModeValue = configObj[key];
}
// cache the value
this._c[key] = util_1.isDefined(userPlatformValue) ? userPlatformValue :
util_1.isDefined(userDefaultValue) ? userDefaultValue :
util_1.isDefined(userPlatformModeValue) ? userPlatformModeValue :
util_1.isDefined(userDefaultModeValue) ? userDefaultModeValue :
util_1.isDefined(platformValue) ? platformValue :
util_1.isDefined(platformModeValue) ? platformModeValue :
null;
}
// return key's value
// either it came directly from the user config
// or it was from the users platform configs
// or it was from the default platform configs
// in that order
if (util_1.isFunction(this._c[key])) {
return this._c[key](this._platform);
}
return this._c[key];
};
/**
* @private
*/
Config.prototype.setPlatform = function (platform) {
this._platform = platform;
};
Config.setModeConfig = function (mode, config) {
modeConfigs[mode] = config;
};
Config.getModeConfig = function (mode) {
return modeConfigs[mode] || null;
};
return Config;
})();
exports.Config = Config;
var modeConfigs = {};
/***/ },
/* 9 */
/***/ function(module, exports, __webpack_require__) {
var util_1 = __webpack_require__(10);
var dom_1 = __webpack_require__(11);
/**
* @name Platform
* @description
* Platform returns the availble information about your current platform.
* Platforms in Ionic 2 are much more complex then in V1, returns not just a single platform,
* but a hierarchy of information, such as a devices OS, phone vs tablet, or mobile vs browser.
* With this information you can completely custimize your app to fit any device and platform.
*
* @usage
* ```ts
* import {Platform} 'ionic/ionic';
* export MyClass {
* constructor(platform: Platform){
* this.platform = platform;
* }
* }
* ```
* @demo /docs/v2/demos/platform/
*/
var Platform = (function () {
function Platform(platforms) {
var _this = this;
if (platforms === void 0) { platforms = []; }
this._platforms = platforms;
this._versions = {};
this._onResizes = [];
this._readyPromise = new Promise(function (res) { _this._readyResolve = res; });
}
// Methods
// **********************************************
/**
* @param {string} platformName
* @returns {bool} returns true/false based on platform you place
* @description
* Depending on the platform name, isPlatform will return true or flase
*
* ```
* import {Platform} 'ionic/ionic';
* export MyClass {
* constructor(platform: Platform){
* this.platform = platform;
* if(this.platform.is('ios'){
* // what ever you need to do for
* // if the platfomr is ios
* }
* }
* }
* ```
*/
Platform.prototype.is = function (platformName) {
return (this._platforms.indexOf(platformName) > -1);
};
/**
* @returns {array} the array of platforms
* @description
* Depending on what device you are on, `platforms` can return multiple values.
* Each possible value is a hierarchy of platforms. For example, on an iPhone,
* it would return mobile, ios, and iphone.
*
* ```
* import {Platform} 'ionic/ionic';
* export MyClass {
* constructor(platform: Platform){
* this.platform = platform;
* console.log(this.platform.platforms());
* // This will return an array of all the availble platforms
* // From if your on mobile, to mobile os, and device name
* }
* }
* ```
*/
Platform.prototype.platforms = function () {
// get the array of active platforms, which also knows the hierarchy,
// with the last one the most important
return this._platforms;
};
/**
* Returns an object containing information about the paltform
*
* ```
* import {Platform} 'ionic/ionic';
* export MyClass {
* constructor(platform: Platform){
* this.platform = platform;
* console.log(this.platform.versions());
* }
* }
* ```
* @param {string} [platformName] optional platformName
* @returns {object} An object with various platform info
*
*/
Platform.prototype.versions = function (platformName) {
if (arguments.length) {
// get a specific platform's version
return this._versions[platformName];
}
// get all the platforms that have a valid parsed version
return this._versions;
};
/**
* @private
*/
Platform.prototype.version = function () {
for (var platformName in this._versions) {
if (this._versions[platformName]) {
return this._versions[platformName];
}
}
return {};
};
/**
* Returns a promise when the platform is ready and native functionality can be called
*
* ```
* import {Platform} 'ionic/ionic';
* export MyClass {
* constructor(platform: Platform){
* this.platform = platform;
* this.platform.ready().then(() => {
* console.log('Platform ready');
* // The platform is now ready, execute any native code you want
* });
* }
* }
* ```
* @returns {promise} Returns a promsie when device ready has fired
*/
Platform.prototype.ready = function () {
return this._readyPromise;
};
/**
* @private
* @param {TODO} config TODO
* @returns {TODO} TODO
*/
Platform.prototype.prepareReady = function (config) {
var self = this;
function resolve() {
self._readyResolve(config);
}
if (this._engineReady) {
// the engine provide a ready promise, use this instead
this._engineReady(resolve);
}
else {
// there is no custom ready method from the engine
// use the default dom ready
dom_1.ready(resolve);
}
};
// Methods meant to be overridden by the engine
// **********************************************
// Provided NOOP methods so they do not error when
// called by engines (the browser) doesn't provide them
/**
* @private
*/
Platform.prototype.on = function () { };
/**
* @private
*/
Platform.prototype.onHardwareBackButton = function () { };
/**
* @private
*/
Platform.prototype.registerBackButtonAction = function () { };
/**
* @private
*/
Platform.prototype.exitApp = function () { };
/**
* @private
*/
Platform.prototype.fullScreen = function () { };
/**
* @private
*/
Platform.prototype.showStatusBar = function () { };
// Getter/Setter Methods
// **********************************************
/**
* @private
*/
Platform.prototype.url = function (val) {
if (arguments.length) {
this._url = val;
this._qs = util_1.getQuerystring(val);
}
return this._url;
};
/**
* @private
*/
Platform.prototype.query = function (key) {
return (this._qs || {})[key];
};
/**
* @private
*/
Platform.prototype.userAgent = function (val) {
if (arguments.length) {
this._ua = val;
}
return this._ua || '';
};
/**
* @private
*/
Platform.prototype.navigatorPlatform = function (val) {
if (arguments.length) {
this._bPlt = val;
}
return this._bPlt || '';
};
/**
* @private
*/
Platform.prototype.width = function () {
return dom_1.windowDimensions().width;
};
/**
* @private
*/
Platform.prototype.height = function () {
return dom_1.windowDimensions().height;
};
/**
* @private
*/
Platform.prototype.isPortrait = function () {
return this.width() < this.height();
};
/**
* @private
*/
Platform.prototype.isLandscape = function () {
return !this.isPortrait();
};
/**
* @private
*/
Platform.prototype.windowResize = function () {
var self = this;
clearTimeout(self._resizeTimer);
self._resizeTimer = setTimeout(function () {
dom_1.flushDimensionCache();
for (var i = 0; i < self._onResizes.length; i++) {
try {
self._onResizes[i]();
}
catch (e) {
console.error(e);
}
}
}, 500);
};
/**
* @private
*/
Platform.prototype.onResize = function (cb) {
this._onResizes.push(cb);
};
// Platform Registry
// **********************************************
/**
* @private
* @param {TODO} platformConfig TODO
*/
Platform.register = function (platformConfig) {
platformRegistry[platformConfig.name] = platformConfig;
};
/**
* @private
*/
Platform.registry = function () {
return platformRegistry;
};
/**
* @private
* @param {TODO} platformName TODO
* @returns {string} TODO
*/
Platform.get = function (platformName) {
return platformRegistry[platformName] || {};
};
Platform.setDefault = function (platformName) {
platformDefault = platformName;
};
/**
* @private
* @param {TODO} queryValue TODO
* @returns {boolean} TODO
*/
Platform.prototype.testQuery = function (queryValue, queryTestValue) {
var valueSplit = queryValue.toLowerCase().split(';');
return valueSplit.indexOf(queryTestValue) > -1;
};
/**
* @private
* @param {TODO} userAgentExpression TODO
* @returns {boolean} TODO
*/
Platform.prototype.testUserAgent = function (userAgentExpression) {
var rgx = new RegExp(userAgentExpression, 'i');
return rgx.test(this._ua || '');
};
/**
* @private
* @param {TODO} navigatorPlatformExpression TODO
* @returns {boolean} TODO
*/
Platform.prototype.testNavigatorPlatform = function (navigatorPlatformExpression) {
var rgx = new RegExp(navigatorPlatformExpression, 'i');
return rgx.test(this._bPlt);
};
/**
* @private
* @param {TODO} userAgentExpression TODO
* @returns {Object} TODO
*/
Platform.prototype.matchUserAgentVersion = function (userAgentExpression) {
if (this._ua && userAgentExpression) {
var val = this._ua.match(userAgentExpression);
if (val) {
return {
major: val[1],
minor: val[2]
};
}
}
};
/**
* @private
* @param {TODO} queryValue TODO
* @param {TODO} userAgentExpression TODO
* @returns {boolean} TODO
*/
Platform.prototype.isPlatform = function (queryTestValue, userAgentExpression) {
if (!userAgentExpression) {
userAgentExpression = queryTestValue;
}
var queryValue = this.query('ionicplatform');
if (queryValue) {
return this.testQuery(queryValue, queryTestValue);
}
return this.testUserAgent(userAgentExpression);
};
/**
* @private
* @param {TODO} config TODO
*/
Platform.prototype.load = function (platformOverride) {
var rootPlatformNode = null;
var engineNode = null;
var self = this;
this.platformOverride = platformOverride;
// figure out the most specific platform and active engine
var tmpPlatform = null;
for (var platformName in platformRegistry) {
tmpPlatform = this.matchPlatform(platformName);
if (tmpPlatform) {
// we found a platform match!
// check if its more specific than the one we already have
if (tmpPlatform.isEngine) {
// because it matched then this should be the active engine
// you cannot have more than one active engine
engineNode = tmpPlatform;
}
else if (!rootPlatformNode || tmpPlatform.depth > rootPlatformNode.depth) {
// only find the root node for platforms that are not engines
// set this node as the root since we either don't already
// have one, or this one is more specific that the current one
rootPlatformNode = tmpPlatform;
}
}
}
if (!rootPlatformNode) {
rootPlatformNode = new PlatformNode(platformDefault);
}
// build a Platform instance filled with the
// hierarchy of active platforms and settings
if (rootPlatformNode) {
// check if we found an engine node (cordova/node-webkit/etc)
if (engineNode) {
// add the engine to the first in the platform hierarchy
// the original rootPlatformNode now becomes a child
// of the engineNode, which is not the new root
engineNode.child(rootPlatformNode);
rootPlatformNode.parent(engineNode);
rootPlatformNode = engineNode;
// add any events which the engine would provide
// for example, Cordova provides its own ready event
var engineMethods = engineNode.methods();
engineMethods._engineReady = engineMethods.ready;
delete engineMethods.ready;
util_1.extend(this, engineMethods);
}
var platformNode = rootPlatformNode;
while (platformNode) {
insertSuperset(platformNode);
platformNode = platformNode.child();
}
// make sure the root noot is actually the root
// incase a node was inserted before the root
platformNode = rootPlatformNode.parent();
while (platformNode) {
rootPlatformNode = platformNode;
platformNode = platformNode.parent();
}
platformNode = rootPlatformNode;
while (platformNode) {
// set the array of active platforms with
// the last one in the array the most important
this._platforms.push(platformNode.name());
// get the platforms version if a version parser was provided
this._versions[platformNode.name()] = platformNode.version(this);
// go to the next platform child
platformNode = platformNode.child();
}
}
};
/**
* @private
* @param {TODO} platformName TODO
* @returns {TODO} TODO
*/
Platform.prototype.matchPlatform = function (platformName) {
// build a PlatformNode and assign config data to it
// use it's getRoot method to build up its hierarchy
// depending on which platforms match
var platformNode = new PlatformNode(platformName);
var rootNode = platformNode.getRoot(this, 0);
if (rootNode) {
rootNode.depth = 0;
var childPlatform = rootNode.child();
while (childPlatform) {
rootNode.depth++;
childPlatform = childPlatform.child();
}
}
return rootNode;
};
return Platform;
})();
exports.Platform = Platform;
function insertSuperset(platformNode) {
var supersetPlaformName = platformNode.superset();
if (supersetPlaformName) {
// add a platform in between two exist platforms
// so we can build the correct hierarchy of active platforms
var supersetPlatform = new PlatformNode(supersetPlaformName);
supersetPlatform.parent(platformNode.parent());
supersetPlatform.child(platformNode);
if (supersetPlatform.parent()) {
supersetPlatform.parent().child(supersetPlatform);
}
platformNode.parent(supersetPlatform);
}
}
var PlatformNode = (function () {
function PlatformNode(platformName) {
this.c = Platform.get(platformName);
this.isEngine = this.c.isEngine;
}
PlatformNode.prototype.name = function () {
return this.c.name;
};
PlatformNode.prototype.settings = function () {
return this.c.settings || {};
};
PlatformNode.prototype.superset = function () {
return this.c.superset;
};
PlatformNode.prototype.methods = function () {
return this.c.methods || {};
};
PlatformNode.prototype.parent = function (val) {
if (arguments.length) {
this._parent = val;
}
return this._parent;
};
PlatformNode.prototype.child = function (val) {
if (arguments.length) {
this._child = val;
}
return this._child;
};
PlatformNode.prototype.isMatch = function (p) {
if (p.platformOverride && !this.isEngine) {
return (p.platformOverride === this.c.name);
}
else if (!this.c.isMatch) {
return false;
}
return this.c.isMatch(p);
};
PlatformNode.prototype.version = function (p) {
if (this.c.versionParser) {
var v = this.c.versionParser(p);
if (v) {
var str = v.major + '.' + v.minor;
return {
str: str,
num: parseFloat(str),
major: parseInt(v.major, 10),
minor: parseInt(v.minor, 10)
};
}
}
};
PlatformNode.prototype.getRoot = function (p) {
if (this.isMatch(p)) {
var parents = this.getSubsetParents(this.name());
if (!parents.length) {
return this;
}
var platform = null;
var rootPlatform = null;
for (var i = 0; i < parents.length; i++) {
platform = new PlatformNode(parents[i]);
platform.child(this);
rootPlatform = platform.getRoot(p);
if (rootPlatform) {
this.parent(platform);
return rootPlatform;
}
}
}
return null;
};
PlatformNode.prototype.getSubsetParents = function (subsetPlatformName) {
var platformRegistry = Platform.registry();
var parentPlatformNames = [];
var platform = null;
for (var platformName in platformRegistry) {
platform = platformRegistry[platformName];
if (platform.subsets && platform.subsets.indexOf(subsetPlatformName) > -1) {
parentPlatformNames.push(platformName);
}
}
return parentPlatformNames;
};
return PlatformNode;
})();
var platformRegistry = {};
var platformDefault = null;
/***/ },
/* 10 */
/***/ function(module, exports) {
// Simple noop function
function noop() { }
exports.noop = noop;
;
/**
* Given a min and max, restrict the given number
* to the range.
* @param min the minimum
* @param n the value
* @param max the maximum
*/
function clamp(min, n, max) {
return Math.max(min, Math.min(n, max));
}
exports.clamp = clamp;
/**
* Extend the destination with an arbitrary number of other objects.
* @param dst the destination
* @param ... the param objects
*/
function extend(dst) {
return _baseExtend(dst, [].slice.call(arguments, 1), false);
}
exports.extend = extend;
/**
* Do a deep extend (merge).
* @param dst the destination
* @param ... the param objects
*/
function merge(dst) {
return _baseExtend(dst, [].slice.call(arguments, 1), true);
}
exports.merge = merge;
function _baseExtend(dst, objs, deep) {
for (var i = 0, ii = objs.length; i < ii; ++i) {
var obj = objs[i];
if (!obj || !exports.isObject(obj) && !exports.isFunction(obj))
continue;
var keys = Object.keys(obj);
for (var j = 0, jj = keys.length; j < jj; j++) {
var key = keys[j];
var src = obj[key];
if (deep && exports.isObject(src)) {
if (!exports.isObject(dst[key]))
dst[key] = exports.isArray(src) ? [] : {};
_baseExtend(dst[key], [src], true);
}
else {
dst[key] = src;
}
}
}
return dst;
}
function debounce(func, wait, immediate) {
var timeout, args, context, timestamp, result;
return function () {
context = this;
args = arguments;
timestamp = new Date();
var later = function () {
var last = (new Date()) - timestamp;
if (last < wait) {
timeout = setTimeout(later, wait - last);
}
else {
timeout = null;
if (!immediate)
result = func.apply(context, args);
}
};
var callNow = immediate && !timeout;
if (!timeout) {
timeout = setTimeout(later, wait);
}
if (callNow)
result = func.apply(context, args);
return result;
};
}
exports.debounce = debounce;
/**
* Apply default arguments if they don't exist in
* the first object.
* @param the destination to apply defaults to.
*/
function defaults(dest) {
for (var i = arguments.length - 1; i >= 1; i--) {
var source = arguments[i] || {};
for (var key in source) {
if (source.hasOwnProperty(key) && !dest.hasOwnProperty(key)) {
dest[key] = source[key];
}
}
}
return dest;
}
exports.defaults = defaults;
exports.isBoolean = function (val) { return typeof val === 'boolean'; };
exports.isString = function (val) { return typeof val === 'string'; };
exports.isNumber = function (val) { return typeof val === 'number'; };
exports.isFunction = function (val) { return typeof val === 'function'; };
exports.isDefined = function (val) { return typeof val !== 'undefined'; };
exports.isUndefined = function (val) { return typeof val === 'undefined'; };
exports.isBlank = function (val) { return val === undefined || val === null; };
exports.isObject = function (val) { return typeof val === 'object'; };
exports.isArray = Array.isArray;
exports.isTrueProperty = function (val) { return typeof val !== 'undefined' && val !== "false"; };
/**
* Convert a string in the format thisIsAString to a slug format this-is-a-string
*/
function pascalCaseToDashCase(str) {
if (str === void 0) { str = ''; }
return str.charAt(0).toLowerCase() + str.substring(1).replace(/[A-Z]/g, function (match) {
return '-' + match.toLowerCase();
});
}
exports.pascalCaseToDashCase = pascalCaseToDashCase;
var uid = 0;
function nextUid() {
return ++uid;
}
exports.nextUid = nextUid;
exports.array = {
find: function (arr, cb) {
for (var i = 0, ii = arr.length; i < ii; i++) {
if (cb(arr[i], i))
return arr[i];
}
},
remove: function (arr, itemOrIndex) {
var index = -1;
if (exports.isNumber(itemOrIndex)) {
index = itemOrIndex;
}
else {
index = arr.indexOf(itemOrIndex);
}
if (index < 0) {
return false;
}
arr.splice(index, 1);
return true;
}
};
/**
* Grab the query string param value for the given key.
* @param key the key to look for
*/
function getQuerystring(url, key) {
var queryParams = {};
if (url) {
var startIndex = url.indexOf('?');
if (startIndex !== -1) {
var queries = url.slice(startIndex + 1).split('&');
queries.forEach(function (param) {
var split = param.split('=');
queryParams[split[0].toLowerCase()] = split[1].split('#')[0];
});
}
if (key) {
return queryParams[key] || '';
}
}
return queryParams;
}
exports.getQuerystring = getQuerystring;
/**
* Throttle the given fun, only allowing it to be
* called at most every `wait` ms.
*/
function throttle(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
options || (options = {});
var later = function () {
previous = options.leading === false ? 0 : Date.now();
timeout = null;
result = func.apply(context, args);
};
return function () {
var now = Date.now();
if (!previous && options.leading === false)
previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
}
else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
}
exports.throttle = throttle;
/***/ },
/* 11 */
/***/ function(module, exports) {
var nativeRaf = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame;
var nativeCancelRaf = window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.webkitCancelRequestAnimationFrame;
function raf(callback) {
//console.log('raf', callback.toString().replace(/\s/g, '').replace('function', '').substring(0, 50));
//console.log('raf, isRootZone()', zone.isRootZone(), '$id', zone.$id);
_raf(callback);
}
exports.raf = raf;
var _raf = nativeRaf || function (callback) {
var timeCurrent = (new Date()).getTime(), timeDelta;
/* Dynamically set delay on a per-tick basis to match 60fps. */
/* Technique by Erik Moller. MIT license: https://gist.github.com/paulirish/1579671 */
timeDelta = Math.max(0, 16 - (timeCurrent - timeLast));
timeLast = timeCurrent + timeDelta;
return setTimeout(function () { callback(timeCurrent + timeDelta); }, timeDelta);
};
exports.rafCancel = nativeRaf ? nativeCancelRaf : function (id) {
return window.cancelTimeout(id);
};
function rafFrames(framesToWait, callback) {
framesToWait = Math.ceil(framesToWait);
if (framesToWait < 2) {
raf(callback);
}
else {
setTimeout(function () {
raf(callback);
}, (framesToWait - 1) * 17);
}
}
exports.rafFrames = rafFrames;
exports.CSS = {};
(function () {
// transform
var i, keys = ['webkitTransform', 'transform', '-webkit-transform', 'webkit-transform',
'-moz-transform', 'moz-transform', 'MozTransform', 'mozTransform', 'msTransform'];
for (i = 0; i < keys.length; i++) {
if (document.documentElement.style[keys[i]] !== undefined) {
exports.CSS.transform = keys[i];
break;
}
}
// transition
keys = ['webkitTransition', 'mozTransition', 'msTransition', 'transition'];
for (i = 0; i < keys.length; i++) {
if (document.documentElement.style[keys[i]] !== undefined) {
exports.CSS.transition = keys[i];
break;
}
}
// The only prefix we care about is webkit for transitions.
var isWebkit = exports.CSS.transition.indexOf('webkit') > -1;
exports.CSS.prefix = isWebkit ? '-webkit-' : '';
// transition duration
exports.CSS.transitionDuration = (isWebkit ? '-webkit-' : '') + 'transition-duration';
// To be sure transitionend works everywhere, include *both* the webkit and non-webkit events
exports.CSS.transitionEnd = (isWebkit ? 'webkitTransitionEnd ' : '') + 'transitionend';
})();
if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {
exports.CSS.animation = 'WebkitAnimation';
exports.CSS.animationStart = 'webkitAnimationStart animationstart';
exports.CSS.animationEnd = 'webkitAnimationEnd animationend';
}
else {
exports.CSS.animation = 'animation';
exports.CSS.animationStart = 'animationstart';
exports.CSS.animationEnd = 'animationend';
}
function transitionEnd(el) {
return cssPromise(el, exports.CSS.transitionEnd);
}
exports.transitionEnd = transitionEnd;
function animationStart(el, animationName) {
return cssPromise(el, exports.CSS.animationStart, animationName);
}
exports.animationStart = animationStart;
function animationEnd(el, animationName) {
return cssPromise(el, exports.CSS.animationEnd, animationName);
}
exports.animationEnd = animationEnd;
function cssPromise(el, eventNames, animationName) {
return new Promise(function (resolve) {
eventNames.split(' ').forEach(function (eventName) {
el.addEventListener(eventName, onEvent);
});
function onEvent(ev) {
if (ev.animationName && animationName) {
// do not resolve if a bubbled up ev.animationName
// is not the same as the passed in animationName arg
if (ev.animationName !== animationName) {
return;
}
}
else if (ev.target !== el) {
// do not resolve if the event's target element is not
// the same as the element the listener was added to
return;
}
ev.stopPropagation();
eventNames.split(' ').forEach(function (eventName) {
el.removeEventListener(eventName, onEvent);
});
resolve(ev);
}
});
}
function ready(callback) {
var promise = null;
if (!callback) {
// a callback wasn't provided, so let's return a promise instead
promise = new Promise(function (resolve) { callback = resolve; });
}
if (document.readyState === 'complete' || document.readyState === 'interactive') {
callback();
}
else {
function completed() {
document.removeEventListener('DOMContentLoaded', completed, false);
window.removeEventListener('load', completed, false);
callback();
}
document.addEventListener('DOMContentLoaded', completed, false);
window.addEventListener('load', completed, false);
}
return promise;
}
exports.ready = ready;
function windowLoad(callback) {
var promise = null;
if (!callback) {
// a callback wasn't provided, so let's return a promise instead
promise = new Promise(function (resolve) { callback = resolve; });
}
if (document.readyState === 'complete') {
callback();
}
else {
function completed() {
window.removeEventListener('load', completed, false);
callback();
}
window.addEventListener('load', completed, false);
}
return promise;
}
exports.windowLoad = windowLoad;
function pointerCoord(ev) {
// get coordinates for either a mouse click
// or a touch depending on the given event
var c = { x: 0, y: 0 };
if (ev) {
var touches = ev.touches && ev.touches.length ? ev.touches : [ev];
var e = (ev.changedTouches && ev.changedTouches[0]) || touches[0];
if (e) {
c.x = e.clientX || e.pageX || 0;
c.y = e.clientY || e.pageY || 0;
}
}
return c;
}
exports.pointerCoord = pointerCoord;
function hasPointerMoved(threshold, startCoord, endCoord) {
return startCoord && endCoord &&
(Math.abs(startCoord.x - endCoord.x) > threshold || Math.abs(startCoord.y - endCoord.y) > threshold);
}
exports.hasPointerMoved = hasPointerMoved;
function isActive(ele) {
return !!(ele && (document.activeElement === ele));
}
exports.isActive = isActive;
function hasFocus(ele) {
return isActive(ele) && (ele.parentElement.querySelector(':focus') === ele);
}
exports.hasFocus = hasFocus;
function isTextInput(ele) {
return !!ele &&
(ele.tagName == 'TEXTAREA' ||
ele.contentEditable === 'true' ||
(ele.tagName == 'INPUT' && !(/^(radio|checkbox|range|file|submit|reset|color|image|button)$/i).test(ele.type)));
}
exports.isTextInput = isTextInput;
function hasFocusedTextInput() {
var ele = document.activeElement;
if (isTextInput(ele)) {
return (ele.parentElement.querySelector(':focus') === ele);
}
return false;
}
exports.hasFocusedTextInput = hasFocusedTextInput;
var matchesFn;
['matches', 'webkitMatchesSelector', 'mozMatchesSelector', 'msMatchesSelector'].some(function (fn) {
if (typeof document.documentElement[fn] == 'function') {
matchesFn = fn;
}
});
function closest(ele, selector, checkSelf) {
if (ele && matchesFn) {
// traverse parents
ele = (checkSelf ? ele : ele.parentElement);
while (ele !== null) {
if (ele[matchesFn](selector)) {
return ele;
}
ele = ele.parentElement;
}
}
return null;
}
exports.closest = closest;
function removeElement(ele) {
ele && ele.parentNode && ele.parentNode.removeChild(ele);
}
exports.removeElement = removeElement;
/**
* Get the element offsetWidth and offsetHeight. Values are cached
* to reduce DOM reads. Cache is cleared on a window resize.
* @param {TODO} ele TODO
*/
function getDimensions(ion, ele) {
if (!ion._dimId) {
ion._dimId = ++dimensionIds;
if (ion._dimId % 1000 === 0) {
// periodically flush dimensions
flushDimensionCache();
}
}
var dimensions = dimensionCache[ion._dimId];
if (!dimensions) {
var ele_1 = ion.getNativeElement();
// make sure we got good values before caching
if (ele_1.offsetWidth && ele_1.offsetHeight) {
dimensions = dimensionCache[ion._dimId] = {
width: ele_1.offsetWidth,
height: ele_1.offsetHeight,
left: ele_1.offsetLeft,
top: ele_1.offsetTop
};
}
else {
// do not cache bad values
return { width: 0, height: 0, left: 0, top: 0 };
}
}
return dimensions;
}
exports.getDimensions = getDimensions;
function windowDimensions() {
if (!dimensionCache.win) {
// make sure we got good values before caching
if (window.innerWidth && window.innerHeight) {
dimensionCache.win = {
width: window.innerWidth,
height: window.innerHeight
};
}
else {
// do not cache bad values
return { width: 0, height: 0 };
}
}
return dimensionCache.win;
}
exports.windowDimensions = windowDimensions;
function flushDimensionCache() {
dimensionCache = {};
}
exports.flushDimensionCache = flushDimensionCache;
var dimensionCache = {};
var dimensionIds = 0;
function isStaticPositioned(element) {
return (element.style.position || 'static') === 'static';
}
/**
* returns the closest, non-statically positioned parentOffset of a given element
* @param element
*/
function parentOffsetEl(element) {
var offsetParent = element.offsetParent || document;
while (offsetParent && offsetParent !== document && isStaticPositioned(offsetParent)) {
offsetParent = offsetParent.offsetParent;
}
return offsetParent || document;
}
exports.parentOffsetEl = parentOffsetEl;
;
/**
* Get the current coordinates of the element, relative to the offset parent.
* Read-only equivalent of [jQuery's position function](http://api.jquery.com/position/).
* @param {element} element The element to get the position of.
* @returns {object} Returns an object containing the properties top, left, width and height.
*/
function position(element) {
var elBCR = offset(element);
var offsetParentBCR = { top: 0, left: 0 };
var offsetParentEl = parentOffsetEl(element);
if (offsetParentEl != document) {
offsetParentBCR = offset(offsetParentEl);
offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
}
var boundingClientRect = element.getBoundingClientRect();
return {
width: boundingClientRect.width || element.offsetWidth,
height: boundingClientRect.height || element.offsetHeight,
top: elBCR.top - offsetParentBCR.top,
left: elBCR.left - offsetParentBCR.left
};
}
exports.position = position;
/**
* Get the current coordinates of the element, relative to the document.
* Read-only equivalent of [jQuery's offset function](http://api.jquery.com/offset/).
* @param {element} element The element to get the offset of.
* @returns {object} Returns an object containing the properties top, left, width and height.
*/
function offset(element) {
var boundingClientRect = element.getBoundingClientRect();
return {
width: boundingClientRect.width || element.offsetWidth,
height: boundingClientRect.height || element.offsetHeight,
top: boundingClientRect.top + (window.pageYOffset || document.documentElement.scrollTop),
left: boundingClientRect.left + (window.pageXOffset || document.documentElement.scrollLeft)
};
}
exports.offset = offset;
/***/ },
/* 12 */
/***/ function(module, exports) {
var CSS_CLICK_BLOCK = 'click-block-active';
var DEFAULT_EXPIRE = 330;
var cbEle, fallbackTimerId;
var isShowing = false;
/**
* @private
*/
var ClickBlock = (function () {
function ClickBlock() {
}
ClickBlock.prototype.enable = function () {
cbEle = document.createElement('click-block');
document.body.appendChild(cbEle);
cbEle.addEventListener('touchmove', function (ev) {
ev.preventDefault();
ev.stopPropagation();
});
this._enabled = true;
};
ClickBlock.prototype.show = function (shouldShow, expire) {
if (this._enabled) {
if (shouldShow) {
show(expire);
}
else {
hide();
}
}
};
return ClickBlock;
})();
exports.ClickBlock = ClickBlock;
function show(expire) {
clearTimeout(fallbackTimerId);
fallbackTimerId = setTimeout(hide, expire || DEFAULT_EXPIRE);
if (!isShowing) {
cbEle.classList.add(CSS_CLICK_BLOCK);
isShowing = true;
}
}
function hide() {
clearTimeout(fallbackTimerId);
if (isShowing) {
cbEle.classList.remove(CSS_CLICK_BLOCK);
isShowing = false;
}
}
/***/ },
/* 13 */
/***/ function(module, exports, __webpack_require__) {
var util_1 = __webpack_require__(14);
/**
* @private
*/
var OverlayController = (function () {
function OverlayController() {
}
OverlayController.prototype.open = function (componentType, params, opts) {
var _this = this;
if (params === void 0) { params = {}; }
if (opts === void 0) { opts = {}; }
if (!this.nav) {
console.error(' required in root template (app.html) to use: ' + opts.pageType);
return Promise.reject();
}
var resolve, reject;
var promise = new Promise(function (res, rej) { resolve = res; reject = rej; });
opts.animation = opts.enterAnimation;
opts.animateFirst = true;
this.nav.push(componentType, params, opts).then(function (viewCtrl) {
if (viewCtrl && viewCtrl.instance) {
var self = _this;
function escape(ev) {
if (ev.keyCode == 27 && self.nav.last() === viewCtrl) {
viewCtrl.instance.close();
}
}
viewCtrl.instance.close = function (data, closeOpts) {
if (closeOpts === void 0) { closeOpts = {}; }
util_1.extend(opts, closeOpts);
opts.animation = opts.leaveAnimation;
viewCtrl.instance.onClose && viewCtrl.instance.onClose(data);
_this.nav.pop(opts);
document.removeEventListener('keyup', escape, true);
};
document.addEventListener('keyup', escape, true);
resolve(viewCtrl.instance);
}
else {
reject();
}
}, function (rejectReason) {
console.error(rejectReason);
});
return promise;
};
OverlayController.prototype.getByType = function (overlayType) {
var overlay = this.nav.getByType(overlayType);
return overlay && overlay.instance;
};
OverlayController.prototype.getByHandle = function (handle, overlayType) {
var overlay = this.nav.getByHandle(handle);
return overlay && overlay.instance;
};
return OverlayController;
})();
exports.OverlayController = OverlayController;
/***/ },
/* 14 */
/***/ function(module, exports, __webpack_require__) {
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
var domUtil = __webpack_require__(11);
exports.dom = domUtil;
__export(__webpack_require__(10));
/***/ },
/* 15 */
/***/ function(module, exports, __webpack_require__) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1 = __webpack_require__(3);
/**
* The Input component is used to focus text input elements.
*
* @usage
* ```html
*
* Name
*
*
* ```
*/
var Form = (function () {
function Form() {
this._inputs = [];
this._ids = -1;
this._focused = null;
this.focusCtrl(document);
}
Form.prototype.register = function (input) {
this._inputs.push(input);
};
Form.prototype.deregister = function (input) {
var index = this._inputs.indexOf(input);
if (index > -1) {
this._inputs.splice(index, 1);
}
if (input === this._focused) {
this._focused = null;
}
};
Form.prototype.focusCtrl = function (document) {
// raw DOM fun
var focusCtrl = document.createElement('focus-ctrl');
focusCtrl.setAttribute('aria-hidden', true);
this._blur = document.createElement('button');
this._blur.tabIndex = -1;
focusCtrl.appendChild(this._blur);
document.body.appendChild(focusCtrl);
};
Form.prototype.focusOut = function () {
console.debug('focusOut');
document.activeElement && document.activeElement.blur();
this._blur.focus();
};
Form.prototype.setAsFocused = function (input) {
this._focused = input;
};
/**
* Focuses the next input element, if it exists.
*/
Form.prototype.focusNext = function (currentInput) {
console.debug('focusNext');
var index = this._inputs.indexOf(currentInput);
if (index > -1 && (index + 1) < this._inputs.length) {
var nextInput = this._inputs[index + 1];
if (nextInput !== this._focused) {
return nextInput.initFocus();
}
}
index = this._inputs.indexOf(this._focused);
if (index > 0) {
var previousInput = this._inputs[index - 1];
if (previousInput) {
previousInput.initFocus();
}
}
};
Form.prototype.nextId = function () {
return ++this._ids;
};
Form = __decorate([
core_1.Injectable(),
__metadata('design:paramtypes', [])
], Form);
return Form;
})();
exports.Form = Form;
/***/ },
/* 16 */
/***/ function(module, exports, __webpack_require__) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1 = __webpack_require__(3);
var config_1 = __webpack_require__(8);
var form_1 = __webpack_require__(15);
var dom_1 = __webpack_require__(11);
/**
* @name Keyboard
* @description
* The `Keyboard` class allows you to work with the keyboard events provide by the Ionic keyboard plugin.
*
* @usage
* ```ts
* export class MyClass{
* constructor(keyboard: Keyboard){
* this.keyboard = keyboard;
* }
* }
*
* ```
*/
var Keyboard = (function () {
function Keyboard(config, form, zone) {
var _this = this;
this.form = form;
this.zone = zone;
zone.runOutsideAngular(function () {
_this.focusOutline(config.get('focusOutline'), document);
});
}
/**
* Chech to see if the keyboard is open or not.
*
* ```ts
* export class MyClass{
* constructor(keyboard: Keyboard){
* this.keyboard = keyboard;
* }
* keyboardCheck(){
* setTimeout(() => console.log('is the keyboard open ', this.keyboard.isOpen()));
* }
* }
*
* ```
*
* @return {Bool} returns a true or flase value if the keyboard is open or not
*/
Keyboard.prototype.isOpen = function () {
return dom_1.hasFocusedTextInput();
};
/**
* When the keyboard is closed, call any methods you want
*
* ```ts
* export class MyClass{
* constructor(keyboard: Keyboard){
* this.keyboard = keyboard;
* this.keyboard.onClose(this.closeCallback);
* }
* closeCallback(){
* // call what ever functionality you want on keyboard close
* console.log('Closing time");
* }
* }
*
* ```
* @param {Function} callback method you want to call when the keyboard has been closed
* @return {Function} returns a callback that gets fired when the keyboard is closed
*/
Keyboard.prototype.onClose = function (callback, pollingInternval) {
if (pollingInternval === void 0) { pollingInternval = KEYBOARD_CLOSE_POLLING; }
console.debug('keyboard onClose');
var self = this;
var checks = 0;
var promise = null;
if (!callback) {
// a callback wasn't provided, so let's return a promise instead
promise = new Promise(function (resolve) { callback = resolve; });
}
self.zone.runOutsideAngular(function () {
function checkKeyboard() {
console.debug('keyboard isOpen', self.isOpen(), checks);
if (!self.isOpen() || checks > 100) {
dom_1.rafFrames(30, function () {
self.zone.run(function () {
console.debug('keyboard closed');
callback();
});
});
}
else {
setTimeout(checkKeyboard, pollingInternval);
}
checks++;
}
setTimeout(checkKeyboard, pollingInternval);
});
return promise;
};
/**
* Progamatically close they keyboard
*
*/
Keyboard.prototype.close = function () {
var _this = this;
console.debug('keyboard close()');
dom_1.raf(function () {
if (dom_1.hasFocusedTextInput()) {
// only focus out when a text input has focus
_this.form.focusOut();
}
});
};
/**
* @private
*/
Keyboard.prototype.focusOutline = function (setting, document) {
/* Focus Outline
* --------------------------------------------------
* By default, when a keydown event happens from a tab key, then
* the 'focus-outline' css class is added to the body element
* so focusable elements have an outline. On a mousedown or
* touchstart event, then the 'focus-outline' css class is removed.
*
* Config default overrides:
* focusOutline: true - Always add the focus-outline
* focusOutline: false - Do not add the focus-outline
*/
var self = this;
var isKeyInputEnabled = false;
function cssClass() {
dom_1.raf(function () {
document.body.classList[isKeyInputEnabled ? 'add' : 'remove']('focus-outline');
});
}
if (setting === true) {
isKeyInputEnabled = true;
return cssClass();
}
else if (setting === false) {
return;
}
// default is to add the focus-outline when the tab key is used
function keyDown(ev) {
if (!isKeyInputEnabled && ev.keyCode == 9) {
isKeyInputEnabled = true;
enableKeyInput();
}
}
function pointerDown() {
isKeyInputEnabled = false;
enableKeyInput();
}
function enableKeyInput() {
cssClass();
self.zone.runOutsideAngular(function () {
document.removeEventListener('mousedown', pointerDown);
document.removeEventListener('touchstart', pointerDown);
if (isKeyInputEnabled) {
document.addEventListener('mousedown', pointerDown);
document.addEventListener('touchstart', pointerDown);
}
});
}
document.addEventListener('keydown', keyDown);
};
Keyboard = __decorate([
core_1.Injectable(),
__metadata('design:paramtypes', [(typeof (_a = typeof config_1.Config !== 'undefined' && config_1.Config) === 'function' && _a) || Object, (typeof (_b = typeof form_1.Form !== 'undefined' && form_1.Form) === 'function' && _b) || Object, (typeof (_c = typeof core_1.NgZone !== 'undefined' && core_1.NgZone) === 'function' && _c) || Object])
], Keyboard);
return Keyboard;
var _a, _b, _c;
})();
exports.Keyboard = Keyboard;
var KEYBOARD_CLOSE_POLLING = 150;
/***/ },
/* 17 */
/***/ function(module, exports, __webpack_require__) {
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1 = __webpack_require__(3);
var common_1 = __webpack_require__(18);
var overlay_controller_1 = __webpack_require__(13);
var config_1 = __webpack_require__(8);
var icon_1 = __webpack_require__(19);
var animation_1 = __webpack_require__(20);
var nav_controller_1 = __webpack_require__(21);
var util_1 = __webpack_require__(10);
var ActionSheetCmp = (function () {
function ActionSheetCmp(params, renderer) {
this.d = params.data;
if (this.d.cssClass) {
renderer.setElementClass(elementRef, this.d.cssClass, true);
}
}
ActionSheetCmp.prototype.cancel = function () {
this.d.cancel && this.d.cancel();
return this.close();
};
ActionSheetCmp.prototype.destructive = function () {
if (this.d.destructiveButtonClicked()) {
return this.close();
}
};
ActionSheetCmp.prototype.buttonClicked = function (index) {
if (this.d.buttonClicked(index)) {
return this.close();
}
};
ActionSheetCmp = __decorate([
core_1.Component({
selector: 'ion-action-sheet',
template: '' +
'
' +
'
' +
'
' +
'
{{d.titleText}}
' +
'' +
'' +
'
' +
'
' +
'' +
'
' +
'
' +
'
',
host: {
'role': 'dialog'
},
directives: [common_1.NgFor, common_1.NgIf, icon_1.Icon]
}),
__metadata('design:paramtypes', [(typeof (_a = typeof nav_controller_1.NavParams !== 'undefined' && nav_controller_1.NavParams) === 'function' && _a) || Object, (typeof (_b = typeof core_1.Renderer !== 'undefined' && core_1.Renderer) === 'function' && _b) || Object])
], ActionSheetCmp);
return ActionSheetCmp;
var _a, _b;
})();
/**
* @name ActionSheet
* @description
* The Action Sheet is a slide-up pane that lets the user choose from a set of options. Dangerous options are made obvious.
* There are easy ways to cancel out of the action sheet, such as tapping the backdrop or even hitting escape on the keyboard for desktop testing.
*
* @usage
* ```ts
* openMenu() {
*
* this.actionSheet.open({
* buttons: [
* { text: 'Share This' },
* { text: 'Move' }
* ],
* destructiveText: 'Delete',
* titleText: 'Modify your album',
* cancelText: 'Cancel',
* cancel: function() {
* console.log('Canceled');
* },
* destructiveButtonClicked: () => {
* console.log('Destructive clicked');
* },
* buttonClicked: function(index) {
* console.log('Button clicked', index);
* if(index == 1) { return false; }
* return true;
* }
*
* }).then(actionSheetRef => {
* this.actionSheetRef = actionSheetRef;
* });
*
* }
* ```
*
* @demo /docs/v2/demos/action-sheet/
* @see {@link /docs/v2/components#action-sheets ActionSheet Component Docs}
*/
var ActionSheet = (function () {
function ActionSheet(ctrl, config) {
this.ctrl = ctrl;
this.config = config;
}
/**
* Create and open a new Action Sheet. This is the
* public API, and most often you will only use ActionSheet.open()
*
* @param {Object} [opts={}] An object containing optional settings.
* - `[Object]` `buttons` Which buttons to show. Each button is an object with a `text` field.
* - `{string}` `titleText` The title to show on the action sheet.
* - `{string=}` `cancelText` the text for a 'cancel' button on the action sheet.
* - `{string=}` `destructiveText` The text for a 'danger' on the action sheet.
* - `{function=}` `cancel` Called if the cancel button is pressed, the backdrop is tapped or
* the hardware back button is pressed.
* - `{function=}` `buttonClicked` Called when one of the non-destructive buttons is clicked,
* with the index of the button that was clicked and the button object. Return true to close
* the action sheet, or false to keep it opened.
* - `{function=}` `destructiveButtonClicked` Called when the destructive button is clicked.
* Return true to close the action sheet, or false to keep it opened.
* - `{String}` `enterAnimation` The class used to animate an actionSheet that is entering.
* - `{String}` `leaveAnimation` The class used to animate an actionSheet that is leaving.
* @return {Promise} Promise that resolves when the action sheet is open.
*/
ActionSheet.prototype.open = function (opts) {
if (opts === void 0) { opts = {}; }
opts = util_1.extend({
pageType: OVERLAY_TYPE,
enterAnimation: this.config.get('actionSheetEnter'),
leaveAnimation: this.config.get('actionSheetLeave'),
cancelIcon: this.config.get('actionSheetCancelIcon'),
destructiveIcon: this.config.get('actionSheetDestructiveIcon')
}, opts);
return this.ctrl.open(ActionSheetCmp, opts, opts);
};
/**
* Retrieves an actionSheet instance.
*
* @param {String} [handle] The handle used to open the instance to be retrieved.
* @returns {ActionSheet} An actionSheet instance.
*/
ActionSheet.prototype.get = function (handle) {
if (handle) {
return this.ctrl.getByHandle(handle);
}
return this.ctrl.getByType(OVERLAY_TYPE);
};
ActionSheet = __decorate([
core_1.Injectable(),
__metadata('design:paramtypes', [(typeof (_a = typeof overlay_controller_1.OverlayController !== 'undefined' && overlay_controller_1.OverlayController) === 'function' && _a) || Object, (typeof (_b = typeof config_1.Config !== 'undefined' && config_1.Config) === 'function' && _b) || Object])
], ActionSheet);
return ActionSheet;
var _a, _b;
})();
exports.ActionSheet = ActionSheet;
var OVERLAY_TYPE = 'action-sheet';
var ActionSheetSlideIn = (function (_super) {
__extends(ActionSheetSlideIn, _super);
function ActionSheetSlideIn(enteringView, leavingView, opts) {
_super.call(this, null, opts);
var ele = enteringView.pageRef().nativeElement;
var backdrop = new animation_1.Animation(ele.querySelector('.backdrop'));
var wrapper = new animation_1.Animation(ele.querySelector('.action-sheet-wrapper'));
backdrop.fromTo('opacity', 0.01, 0.4);
wrapper.fromTo('translateY', '100%', '0%');
this.easing('cubic-bezier(.36,.66,.04,1)').duration(400).add([backdrop, wrapper]);
}
return ActionSheetSlideIn;
})(animation_1.Animation);
animation_1.Animation.register('action-sheet-slide-in', ActionSheetSlideIn);
var ActionSheetSlideOut = (function (_super) {
__extends(ActionSheetSlideOut, _super);
function ActionSheetSlideOut(enteringView, leavingView, opts) {
_super.call(this, null, opts);
var ele = leavingView.pageRef().nativeElement;
var backdrop = new animation_1.Animation(ele.querySelector('.backdrop'));
var wrapper = new animation_1.Animation(ele.querySelector('.action-sheet-wrapper'));
backdrop.fromTo('opacity', 0.4, 0);
wrapper.fromTo('translateY', '0%', '100%');
this.easing('cubic-bezier(.36,.66,.04,1)').duration(300).add([backdrop, wrapper]);
}
return ActionSheetSlideOut;
})(animation_1.Animation);
animation_1.Animation.register('action-sheet-slide-out', ActionSheetSlideOut);
var ActionSheetMdSlideIn = (function (_super) {
__extends(ActionSheetMdSlideIn, _super);
function ActionSheetMdSlideIn(enteringView, leavingView, opts) {
_super.call(this, null, opts);
var ele = enteringView.pageRef().nativeElement;
var backdrop = new animation_1.Animation(ele.querySelector('.backdrop'));
var wrapper = new animation_1.Animation(ele.querySelector('.action-sheet-wrapper'));
backdrop.fromTo('opacity', 0.01, 0.26);
wrapper.fromTo('translateY', '100%', '0%');
this.easing('cubic-bezier(.36,.66,.04,1)').duration(450).add([backdrop, wrapper]);
}
return ActionSheetMdSlideIn;
})(animation_1.Animation);
animation_1.Animation.register('action-sheet-md-slide-in', ActionSheetMdSlideIn);
var ActionSheetMdSlideOut = (function (_super) {
__extends(ActionSheetMdSlideOut, _super);
function ActionSheetMdSlideOut(enteringView, leavingView, opts) {
_super.call(this, null, opts);
var ele = leavingView.pageRef().nativeElement;
var backdrop = new animation_1.Animation(ele.querySelector('.backdrop'));
var wrapper = new animation_1.Animation(ele.querySelector('.action-sheet-wrapper'));
backdrop.fromTo('opacity', 0.26, 0);
wrapper.fromTo('translateY', '0%', '100%');
this.easing('cubic-bezier(.36,.66,.04,1)').duration(450).add([backdrop, wrapper]);
}
return ActionSheetMdSlideOut;
})(animation_1.Animation);
animation_1.Animation.register('action-sheet-md-slide-out', ActionSheetMdSlideOut);
/***/ },
/* 18 */
/***/ function(module, exports) {
module.exports = require("angular2")["common"];
/***/ },
/* 19 */
/***/ function(module, exports, __webpack_require__) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1 = __webpack_require__(3);
var config_1 = __webpack_require__(8);
/**
* @name Icon
* @description
* Icons can be used on their own, or inside of a number of Ionic components. For a full list of available icons,
* check out the [Ionicons resource docs](../../../../resources/ionicons).
*
* @usage
* ```html
*
*
*
*
*
* ```
*
* @property {boolean} [isActive] - Whether or not the icon is active. Icons that are not active will use an outlined version of the icon.
* If there is not an outlined version for the particular icon, it will use the default (full) version.
* @property {string} [ios] - Explicitly set the icon to use on iOS.
* @property {string} [md] - Explicitly set the icon to use on Android.
* @see {@link /docs/v2/components#icons Icon Component Docs}
*
*/
var Icon = (function () {
function Icon(_elementRef, config, _renderer) {
this._elementRef = _elementRef;
this._renderer = _renderer;
this.config = config;
this.mode = config.get('iconMode');
}
/**
* @private
*/
Icon.prototype.ngOnInit = function () {
var ele = this._elementRef.nativeElement;
if (this.mode == 'ios' && this.ios) {
this.name = this.ios;
}
else if (this.mode == 'md' && this.md) {
this.name = this.md;
}
else if (!this.name) {
// looping through native dom attributes, eww
// https://github.com/angular/angular/issues/1818
for (var i = 0, l = ele.attributes.length; i < l; i++) {
if (ele.attributes[i].value === '' && /_|item-|isActive|large|small|class/.test(ele.attributes[i].name) !== true) {
this.name = ele.attributes[i].name;
break;
}
}
}
if (!this.name)
return;
if (!(/^ion-/.test(this.name))) {
// not an exact icon being used
// add mode specific prefix
this.name = 'ion-' + this.mode + '-' + this.name;
}
this.update();
};
Object.defineProperty(Icon.prototype, "isActive", {
get: function () {
return (this._isActive === undefined || this._isActive === true || this._isActive === 'true');
},
/**
* @private
*/
set: function (val) {
this._isActive = val;
this.update();
},
enumerable: true,
configurable: true
});
/**
* @private
*/
Icon.prototype.update = function () {
if (this.name && this.mode == 'ios') {
if (this.isActive) {
if (/-outline/.test(this.name)) {
this.name = this.name.replace('-outline', '');
}
}
else if (!(/-outline/.test(this.name))) {
this.name += '-outline';
}
}
if (this._name !== this.name) {
if (this._name) {
this._renderer.setElementClass(this._elementRef, this._name, false);
}
this._name = this.name;
this._renderer.setElementClass(this._elementRef, this.name, true);
this._renderer.setElementAttribute(this._elementRef, 'aria-label', this.name.replace('ion-', '').replace('ios-', '').replace('md-', '').replace('-', ' '));
}
};
Icon = __decorate([
core_1.Directive({
selector: 'icon',
inputs: [
'name',
'ios',
'md',
'isActive'
],
host: {
'role': 'img'
}
}),
__metadata('design:paramtypes', [(typeof (_a = typeof core_1.ElementRef !== 'undefined' && core_1.ElementRef) === 'function' && _a) || Object, (typeof (_b = typeof config_1.Config !== 'undefined' && config_1.Config) === 'function' && _b) || Object, (typeof (_c = typeof core_1.Renderer !== 'undefined' && core_1.Renderer) === 'function' && _c) || Object])
], Icon);
return Icon;
var _a, _b, _c;
})();
exports.Icon = Icon;
/***/ },
/* 20 */
/***/ function(module, exports, __webpack_require__) {
var dom_1 = __webpack_require__(11);
var util_1 = __webpack_require__(10);
/**
Animation Steps/Process
-----------------------
- Construct animation (doesn't start)
- Client play()'s animation, returns promise
- Add before classes to elements
- Remove before classes from elements
- Elements staged in "from" effect w/ inline styles
- Call onReady()
- Wait for RENDER_DELAY milliseconds (give browser time to render)
- Call onPlay()
- Run from/to animation on elements
- Animations finish async
- Set inline styles w/ the "to" effects on elements
- Add after classes to elements
- Remove after classes from elements
- Call onFinish()
- Resolve play()'s promise
**/
/**
* @private
**/
var Animation = (function () {
function Animation(ele, opts) {
if (opts === void 0) { opts = {}; }
this.reset();
this._opts = util_1.extend({
renderDelay: 16
}, opts);
this.elements(ele);
if (!document.documentElement.animate) {
console.error('Web Animations polyfill missing');
}
}
Animation.prototype.reset = function () {
this._el = [];
this._chld = [];
this._ani = [];
this._bfAdd = [];
this._bfSty = {};
this._bfRmv = [];
this._afAdd = [];
this._afRmv = [];
this._readys = [];
this._plays = [];
this._finishes = [];
};
Animation.prototype.elements = function (ele) {
if (ele) {
if (typeof ele === 'string') {
// string query selector
ele = document.querySelectorAll(ele);
}
if (ele.length) {
// array of elements
for (var i = 0; i < ele.length; i++) {
this.addElement(ele[i]);
}
}
else {
// single element
this.addElement(ele);
}
}
return this;
};
Animation.prototype.addElement = function (ele) {
// ensure only HTML Element nodes
if (ele) {
if (ele.nativeElement) {
// angular ElementRef
ele = ele.nativeElement;
}
if (ele.nodeType === 1) {
this._el.push(ele);
}
}
};
Animation.prototype.parent = function (parentAnimation) {
this._parent = parentAnimation;
return this;
};
Animation.prototype.add = function (childAnimations) {
var _childAnimations = Array.isArray(childAnimations) ? childAnimations : arguments;
for (var i = 0; i < _childAnimations.length; i++) {
_childAnimations[i].parent(this);
this._chld.push(_childAnimations[i]);
}
return this;
};
Animation.prototype.duration = function (value) {
if (arguments.length) {
this._duration = value;
return this;
}
return this._duration || (this._parent && this._parent.duration()) || 0;
};
Animation.prototype.clearDuration = function () {
this._duration = null;
for (var i = 0, l = this._chld.length; i < l; i++) {
this._chld[i].clearDuration();
}
};
Animation.prototype.easing = function (name, opts) {
if (arguments.length) {
this._easing = {
name: name,
opts: opts
};
return this;
}
return this._easing || (this._parent && this._parent.easing());
};
Animation.prototype.playbackRate = function (value) {
if (arguments.length) {
this._rate = value;
var i;
for (i = 0; i < this._chld.length; i++) {
this._chld[i].playbackRate(value);
}
for (i = 0; i < this._ani.length; i++) {
this._ani[i].playbackRate(value);
}
return this;
}
return (typeof this._rate !== 'undefined' ? this._rate : this._parent && this._parent.playbackRate());
};
Animation.prototype.reverse = function () {
return this.playbackRate(-1);
};
Animation.prototype.forward = function () {
return this.playbackRate(1);
};
Animation.prototype.from = function (property, value) {
if (!this._from) {
this._from = {};
}
this._from[property] = value;
return this;
};
Animation.prototype.to = function (property, value) {
if (!this._to) {
this._to = {};
}
this._to[property] = value;
return this;
};
Animation.prototype.fromTo = function (property, from, to) {
return this.from(property, from).to(property, to);
};
Animation.prototype.fadeIn = function () {
return this.fromTo('opacity', 0.001, 1);
};
Animation.prototype.fadeOut = function () {
return this.fromTo('opacity', 0.999, 0);
};
Object.defineProperty(Animation.prototype, "before", {
get: function () {
var _this = this;
return {
addClass: function (className) {
_this._bfAdd.push(className);
return _this;
},
removeClass: function (className) {
_this._bfRmv.push(className);
return _this;
},
setStyles: function (styles) {
_this._bfSty = styles;
return _this;
}
};
},
enumerable: true,
configurable: true
});
Object.defineProperty(Animation.prototype, "after", {
get: function () {
var _this = this;
return {
addClass: function (className) {
_this._afAdd.push(className);
return _this;
},
removeClass: function (className) {
_this._afRmv.push(className);
return _this;
}
};
},
enumerable: true,
configurable: true
});
Animation.prototype.play = function (done) {
var self = this;
// the actual play() method which may or may not start async
function beginPlay(beginPlayDone) {
var tasks = [];
self._chld.forEach(function (childAnimation) {
tasks.push(function (taskDone) {
childAnimation.play(taskDone);
});
});
self._ani.forEach(function (animation) {
tasks.push(function (taskDone) {
animation.play(taskDone);
});
});
parallel(tasks, beginPlayDone);
}
if (!self._parent) {
// this is the top level animation and is in full control
// of when the async play() should actually kick off
// stage all animations and child animations at their starting point
self.stage();
var promise;
if (!done) {
promise = new Promise(function (res) { done = res; });
}
function kickoff() {
// synchronously call all onPlay()'s before play()
self._onPlay();
beginPlay(function () {
self._onFinish();
done();
});
}
if (self._duration > 16 && self._opts.renderDelay > 0) {
// begin each animation when everything is rendered in their starting point
// give the browser some time to render everything in place before starting
dom_1.rafFrames(self._opts.renderDelay / 16, kickoff);
}
else {
// no need to render everything in there place before animating in
// just kick it off immediately to render them in their "to" locations
kickoff();
}
return promise;
}
// this is a child animation, it is told exactly when to
// start by the top level animation
beginPlay(done);
};
Animation.prototype.stage = function () {
// before the RENDER_DELAY
// before the animations have started
if (!this._isStaged) {
this._isStaged = true;
var i, p, l, j, ele, animation;
for (i = 0, l = this._chld.length; i < l; i++) {
this._chld[i].stage();
}
for (i = 0; i < this._el.length; i++) {
ele = this._el[i];
for (j = 0; j < this._bfAdd.length; j++) {
ele.classList.add(this._bfAdd[j]);
}
for (p in this._bfSty) {
ele.style[p] = this._bfSty[p];
}
for (j = 0; j < this._bfRmv.length; j++) {
ele.classList.remove(this._bfRmv[j]);
}
}
if (this._to) {
// only animate the elements if there are defined "to" effects
for (i = 0; i < this._el.length; i++) {
animation = new Animate(this._el[i], this._from, this._to, this.duration(), this.easing(), this.playbackRate());
if (animation.shouldAnimate) {
this._ani.push(animation);
}
}
}
for (i = 0; i < this._readys.length; i++) {
this._readys[i](this);
}
}
};
Animation.prototype._onPlay = function () {
// after the RENDER_DELAY
// before the animations have started
var i;
this._isFinished = false;
for (i = 0; i < this._chld.length; i++) {
this._chld[i]._onPlay();
}
for (i = 0; i < this._plays.length; i++) {
this._plays[i](this);
}
};
Animation.prototype._onFinish = function () {
// after the animations have finished
if (!this._isFinished && !this.isProgress) {
this._isFinished = true;
var i, j, ele;
for (i = 0; i < this._chld.length; i++) {
this._chld[i]._onFinish();
}
if (this.playbackRate() < 0) {
// reverse direction
for (i = 0; i < this._el.length; i++) {
ele = this._el[i];
for (j = 0; j < this._bfAdd.length; j++) {
ele.classList.remove(this._bfAdd[j]);
}
for (j = 0; j < this._bfRmv.length; j++) {
ele.classList.add(this._bfRmv[j]);
}
}
}
else {
// normal direction
for (i = 0; i < this._el.length; i++) {
ele = this._el[i];
for (j = 0; j < this._afAdd.length; j++) {
ele.classList.add(this._afAdd[j]);
}
for (j = 0; j < this._afRmv.length; j++) {
ele.classList.remove(this._afRmv[j]);
}
}
}
for (i = 0; i < this._finishes.length; i++) {
this._finishes[i](this);
}
}
};
Animation.prototype.pause = function () {
var i;
for (i = 0; i < this._chld.length; i++) {
this._chld[i].pause();
}
for (i = 0; i < this._ani.length; i++) {
this._ani[i].pause();
}
};
Animation.prototype.progressStart = function () {
this.isProgress = true;
for (var i = 0; i < this._chld.length; i++) {
this._chld[i].progressStart();
}
this.duration(1000);
this.play();
this.pause();
};
Animation.prototype.progress = function (value) {
value = Math.min(1, Math.max(0, value));
this.isProgress = true;
var i;
for (i = 0; i < this._chld.length; i++) {
this._chld[i].progress(value);
}
for (i = 0; i < this._ani.length; i++) {
this._ani[i].progress(value);
}
};
/**
* Get the current time of the first animation
* in the list. To get a specific time of an animation, call
* subAnimationInstance.getCurrentTime()
*/
Animation.prototype.getCurrentTime = function () {
if (this._chld.length > 0) {
return this._chld[0].getCurrentTime();
}
if (this._ani.length > 0) {
return this._ani[0].getCurrentTime();
}
return 0;
};
Animation.prototype.progressEnd = function (shouldComplete, rate) {
if (rate === void 0) { rate = 3; }
var promises = [];
this.isProgress = false;
for (var i = 0; i < this._chld.length; i++) {
promises.push(this._chld[i].progressEnd(shouldComplete));
}
this._ani.forEach(function (animation) {
if (shouldComplete) {
animation.playbackRate(rate);
}
else {
animation.playbackRate(rate * -1);
}
promises.push(new Promise(function (resolve) {
animation.play(resolve);
}));
});
return Promise.all(promises);
};
Animation.prototype.onReady = function (fn, clear) {
if (clear) {
this._readys = [];
}
this._readys.push(fn);
return this;
};
Animation.prototype.onPlay = function (fn, clear) {
if (clear) {
this._plays = [];
}
this._plays.push(fn);
return this;
};
Animation.prototype.onFinish = function (fn, clear) {
if (clear) {
this._finishes = [];
}
this._finishes.push(fn);
return this;
};
Animation.prototype.clone = function () {
function copy(dest, src) {
// undo what stage() may have already done
util_1.extend(dest, src);
dest._isFinished = dest._isStaged = dest.isProgress = false;
dest._chld = [];
dest._ani = [];
for (var i = 0; i < src._chld.length; i++) {
dest.add(copy(new Animation(), src._chld[i]));
}
return dest;
}
return copy(new Animation(), this);
};
Animation.prototype.dispose = function (removeElement) {
var i;
for (i = 0; i < this._chld.length; i++) {
this._chld[i].dispose(removeElement);
}
for (i = 0; i < this._ani.length; i++) {
this._ani[i].dispose(removeElement);
}
if (removeElement) {
for (i = 0; i < this._el.length; i++) {
this._el[i].parentNode && this._el[i].parentNode.removeChild(this._el[i]);
}
}
this.reset();
};
/*
STATIC CLASSES
*/
Animation.create = function (element, name) {
var AnimationClass = AnimationRegistry[name];
if (!AnimationClass) {
// couldn't find an animation by the given name
// fallback to just the base Animation class
AnimationClass = Animation;
}
return new AnimationClass(element);
};
Animation.createTransition = function (enteringView, leavingView, opts) {
if (opts === void 0) { opts = {}; }
var TransitionClass = AnimationRegistry[opts.animation];
if (!TransitionClass) {
// didn't find a transition animation, default to ios-transition
TransitionClass = AnimationRegistry['ios-transition'];
}
return new TransitionClass(enteringView, leavingView, opts);
};
Animation.register = function (name, AnimationClass) {
AnimationRegistry[name] = AnimationClass;
};
return Animation;
})();
exports.Animation = Animation;
/**
* @private
**/
var Animate = (function () {
function Animate(ele, fromEffect, toEffect, duration, easingConfig, playbackRate) {
// https://w3c.github.io/web-animations/
// not using the direct API methods because they're still in flux
// however, element.animate() seems locked in and uses the latest
// and correct API methods under the hood, so really doesn't matter
if (!fromEffect) {
return console.error(ele.tagName, 'animation fromEffect required, toEffect:', toEffect);
}
this.toEffect = parseEffect(toEffect);
this.shouldAnimate = (duration > 32);
if (!this.shouldAnimate) {
return inlineStyle(ele, this.toEffect);
}
this.ele = ele;
// stage where the element will start from
this.fromEffect = parseEffect(fromEffect);
inlineStyle(ele, this.fromEffect);
this.duration = duration;
this.rate = (typeof playbackRate !== 'undefined' ? playbackRate : 1);
this.easing = easingConfig && easingConfig.name || 'linear';
this.effects = [convertProperties(this.fromEffect)];
if (this.easing in EASING_FN) {
insertEffects(this.effects, this.fromEffect, this.toEffect, easingConfig);
}
else if (this.easing in CUBIC_BEZIERS) {
this.easing = 'cubic-bezier(' + CUBIC_BEZIERS[this.easing] + ')';
}
this.effects.push(convertProperties(this.toEffect));
}
Animate.prototype.play = function (done) {
var self = this;
if (self.ani) {
self.ani.play();
}
else {
// https://developers.google.com/web/updates/2014/05/Web-Animations---element-animate-is-now-in-Chrome-36
// https://w3c.github.io/web-animations/
// Future versions will use "new window.Animation" rather than "element.animate()"
self.ani = self.ele.animate(self.effects, {
duration: self.duration || 0,
easing: self.easing,
playbackRate: self.rate // old way of setting playbackRate, but still necessary
});
self.ani.playbackRate = self.rate;
}
self.ani.onfinish = function () {
// lock in where the element will stop at
// if the playbackRate is negative then it needs to return
// to its "from" effects
if (self.ani) {
inlineStyle(self.ele, self.rate < 0 ? self.fromEffect : self.toEffect);
self.ani = self.ani.onfinish = null;
done && done();
}
};
};
Animate.prototype.pause = function () {
this.ani && this.ani.pause();
};
Animate.prototype.progress = function (value) {
if (this.ani) {
// passed a number between 0 and 1
if (this.ani.playState !== 'paused') {
this.ani.pause();
}
// don't let the progress finish the animation
// leave it off JUST before it's finished
value = Math.min(0.999, Math.max(0.001, value));
this.ani.currentTime = (this.duration * value);
}
};
Animate.prototype.getCurrentTime = function () {
return (this.ani && this.ani.currentTime) || 0;
};
Animate.prototype.playbackRate = function (value) {
this.rate = value;
if (this.ani) {
this.ani.playbackRate = value;
}
};
Animate.prototype.dispose = function () {
this.ele = this.ani = this.effects = this.toEffect = null;
};
return Animate;
})();
function insertEffects(effects, fromEffect, toEffect, easingConfig) {
easingConfig.opts = easingConfig.opts || {};
var increment = easingConfig.opts.increment || 0.04;
var easingFn = EASING_FN[easingConfig.name];
var pos, tweenEffect, addEffect, property, toProperty, fromValue, diffValue;
for (pos = increment; pos <= (1 - increment); pos += increment) {
tweenEffect = {};
addEffect = false;
for (property in toEffect) {
toProperty = toEffect[property];
if (toProperty.tween) {
fromValue = fromEffect[property].num;
diffValue = toProperty.num - fromValue;
tweenEffect[property] = {
value: roundValue((easingFn(pos, easingConfig.opts) * diffValue) + fromValue) + toProperty.unit
};
addEffect = true;
}
}
if (addEffect) {
effects.push(convertProperties(tweenEffect));
}
}
}
function parseEffect(inputEffect) {
var val, r, num, property;
var outputEffect = {};
for (property in inputEffect) {
val = inputEffect[property];
r = val.toString().match(/(^-?\d*\.?\d*)(.*)/);
num = parseFloat(r[1]);
outputEffect[property] = {
value: val,
num: num,
unit: (r[0] != r[2] ? r[2] : ''),
tween: !isNaN(num) && (ANIMATE_PROPERTIES.indexOf(property) > -1)
};
}
return outputEffect;
}
function convertProperties(inputEffect) {
var outputEffect = {};
var transforms = [];
var value, property;
for (property in inputEffect) {
value = inputEffect[property].value;
if (TRANSFORMS.indexOf(property) > -1) {
transforms.push(property + '(' + value + ')');
}
else {
outputEffect[property] = value;
}
}
if (transforms.length) {
transforms.push('translateZ(0px)');
outputEffect.transform = transforms.join(' ');
}
return outputEffect;
}
function inlineStyle(ele, effect) {
if (ele && effect) {
var transforms = [];
var value, property;
for (property in effect) {
value = effect[property].value;
if (TRANSFORMS.indexOf(property) > -1) {
transforms.push(property + '(' + value + ')');
}
else {
ele.style[property] = value;
}
}
if (transforms.length) {
transforms.push('translateZ(0px)');
ele.style[dom_1.CSS.transform] = transforms.join(' ');
}
else {
ele.style[dom_1.CSS.transform] = 'translateZ(0px)';
}
}
}
function roundValue(val) {
return Math.round(val * 10000) / 10000;
}
var TRANSFORMS = ['translateX', 'translateY', 'translateZ', 'scale', 'scaleX', 'scaleY', 'scaleZ',
'rotate', 'rotateX', 'rotateY', 'rotateZ', 'skewX', 'skewY', 'perspective'];
var ANIMATE_PROPERTIES = TRANSFORMS.concat('opacity');
// Robert Penner's Easing Functions
// http://robertpenner.com/easing/
var CUBIC_BEZIERS = {
// default browser suppored easing
// ease
// ease-in
// ease-out
// ease-in-out
// Cubic
'ease-in-cubic': '0.55,0.055,0.675,0.19',
'ease-out-cubic': '0.215,0.61,0.355,1',
'ease-in-Out-cubic': '0.645,0.045,0.355,1',
// Circ
'ease-in-circ': '0.6,0.04,0.98,0.335',
'ease-out-circ': '0.075,0.82,0.165,1',
'ease-in-out-circ': '0.785,0.135,0.15,0.86',
// Expo
'ease-in-expo': '0.95,0.05,0.795,0.035',
'ease-out-expo': '0.19,1,0.22,1',
'ease-in-out-expo': '1,0,0,1',
// Quad
'ease-in-quad': '0.55,0.085,0.68,0.53',
'ease-out-quad': '0.25,0.46,0.45,0.94',
'ease-in-out-quad': '0.455,0.03,0.515,0.955',
// Quart
'ease-in-quart': '0.895,0.03,0.685,0.22',
'ease-out-quart': '0.165,0.84,0.44,1',
'ease-in-out-quart': '0.77,0,0.175,1',
// Quint
'ease-in-quint': '0.755,0.05,0.855,0.06',
'ease-out-quint': '0.23,1,0.32,1',
'ease-in-out-quint': '0.86,0,0.07,1',
// Sine
'ease-in-sine': '0.47,0,0.745,0.715',
'ease-out-sine': '0.39,0.575,0.565,1',
'ease-in-out-sine': '0.445,0.05,0.55,0.95',
// Back
'ease-in-back': '0.6,-0.28,0.735,0.045',
'ease-out-back': '0.175,0.885,0.32,1.275',
'ease-in-out-back': '0.68,-0.55,0.265,1.55',
};
var EASING_FN = {
'elastic': function (pos) {
return -1 * Math.pow(4, -8 * pos) * Math.sin((pos * 6 - 1) * (2 * Math.PI) / 2) + 1;
},
'swing-from-to': function (pos, opts) {
var s = opts.s || 1.70158;
return ((pos /= 0.5) < 1) ? 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s)) :
0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2);
},
'swing-from': function (pos, opts) {
var s = opts.s || 1.70158;
return pos * pos * ((s + 1) * pos - s);
},
'swing-to': function (pos, opts) {
var s = opts.s || 1.70158;
return (pos -= 1) * pos * ((s + 1) * pos + s) + 1;
},
'bounce': function (pos) {
if (pos < (1 / 2.75)) {
return (7.5625 * pos * pos);
}
else if (pos < (2 / 2.75)) {
return (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75);
}
else if (pos < (2.5 / 2.75)) {
return (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375);
}
return (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375);
},
'bounce-past': function (pos) {
if (pos < (1 / 2.75)) {
return (7.5625 * pos * pos);
}
else if (pos < (2 / 2.75)) {
return 2 - (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75);
}
else if (pos < (2.5 / 2.75)) {
return 2 - (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375);
}
return 2 - (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375);
},
'ease-out-bounce': function (pos) {
if ((pos) < (1 / 2.75)) {
return (7.5625 * pos * pos);
}
else if (pos < (2 / 2.75)) {
return (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75);
}
else if (pos < (2.5 / 2.75)) {
return (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375);
}
return (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375);
},
'ease-from-to': function (pos) {
if ((pos /= 0.5) < 1)
return 0.5 * Math.pow(pos, 4);
return -0.5 * ((pos -= 2) * Math.pow(pos, 3) - 2);
},
'ease-from': function (pos, opts) {
return Math.pow(pos, opts.s || 4);
},
'ease-to': function (pos, opts) {
return Math.pow(pos, opts.s || 0.25);
},
/*
* scripty2, Thomas Fuchs (MIT Licence)
* https://raw.github.com/madrobby/scripty2/master/src/effects/transitions/transitions.js
*/
'spring': function (pos, opts) {
var damping = opts.damping || 4.5;
var elasticity = opts.elasticity || 6;
return 1 - (Math.cos(pos * damping * Math.PI) * Math.exp(-pos * elasticity));
},
'sinusoidal': function (pos) {
return (-Math.cos(pos * Math.PI) / 2) + 0.5;
}
};
var AnimationRegistry = {};
function parallel(tasks, done) {
var l = tasks.length;
if (!l) {
done && done();
return;
}
var completed = 0;
function taskCompleted() {
completed++;
if (completed === l) {
done && done();
}
}
for (var i = 0; i < l; i++) {
tasks[i](taskCompleted);
}
}
/***/ },
/* 21 */
/***/ function(module, exports, __webpack_require__) {
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var core_1 = __webpack_require__(3);
var instrumentation_1 = __webpack_require__(22);
var ion_1 = __webpack_require__(23);
var view_controller_1 = __webpack_require__(24);
var animation_1 = __webpack_require__(20);
var swipe_back_1 = __webpack_require__(25);
var util_1 = __webpack_require__(10);
var dom_1 = __webpack_require__(11);
/**
* _For examples on the basic usage of NavController, check out the
* [Navigation section](../../../../components/#navigation) of the Component
* docs._
*
* NavController is the base class for navigation controller components like
* [`Nav`](../Nav/) and [`Tab`](../../Tabs/Tab/). You use navigation controllers
* to navigate to [pages](#creating_pages) in your app. At a basic level, a
* navigation controller is an array of pages representing a particular history
* (of a Tab for example). This array can be manipulated to navigate throughout
* an app by pushing and popping pages or inserting and removing them at
* arbitrary locations in history.
*
* The current page is the last one in the array, or the top of the stack if we
* think of it that way. [Pushing](#push) a new page onto the top of the
* navigation stack causes the new page to be animated in, while [popping](#pop)
* the current page will navigate to the previous page in the stack.
*
* Unless you are using a directive like [NavPush](../NavPush/), or need a
* specific NavController, most times you will inject and use a reference to the
* nearest NavController to manipulate the navigation stack.
*
*
Injecting NavController
* Injecting NavController will always get you an instance of the nearest
* NavController, regardless of whether it is a Tab or a Nav.
*
* Behind the scenes, when Ionic instantiates a new NavController, it creates an
* injector with NavController bound to that instance (usually either a Nav or
* Tab) and adds the injector to its own providers. For more information on
* providers and dependency injection, see [Providers and DI]().
*
* Instead, you can inject NavController and know that it is the correct
* navigation controller for most situations (for more advanced situations, see
* [Menu](../../Menu/Menu/) and [Tab](../../Tab/Tab/)).
*
* ```ts
* class MyComponent {
* constructor(nav: NavController) {
* this.nav = nav;
* }
* }
* ```
*
*
Page creation
* _For more information on the `@Page` decorator see the [@Page API
* reference](../../../decorators/Page/)._
*
* Pages are created when they are added to the navigation stack. For methods
* like [push()](#push), the NavController takes any component class that is
* decorated with `@Page` as its first argument. The NavController then
* compiles that component, adds it to the app and animates it into view.
*
* By default, pages are cached and left in the DOM if they are navigated away
* from but still in the navigation stack (the exiting page on a `push()` for
* example). They are destroyed when removed from the navigation stack (on
* [pop()](#pop) or [setRoot()](#setRoot)).
*
*
*
Lifecycle events
* Lifecycle events are fired during various stages of navigation. They can be
* defined in any `@Page` decorated component class.
*
* ```ts
* @Page({
* template: 'Hello World'
* })
* class HelloWorld {
* onPageLoaded() {
* console.log("I'm alive!");
* }
* onPageWillLeave() {
* console.log("Looks like I'm about to leave :(");
* }
* }
* ```
*
*
*
* - `onPageLoaded` - Runs when the page has loaded. This event only happens once per page being created and added to the DOM. If a page leaves but is cached, then this event will not fire again on a subsequent viewing. The `onPageLoaded` event is good place to put your setup code for the page.
* - `onPageWillEnter` - Runs when the page is about to enter and become the active page.
* - `onPageDidEnter` - Runs when the page has fully entered and is now the active page. This event will fire, whether it was the first load or a cached page.
* - `onPageWillLeave` - Runs when the page is about to leave and no longer be the active page.
* - `onPageDidLeave` - Runs when the page has finished leaving and is no longer the active page.
* - `onPageWillUnload` - Runs when the page is about to be destroyed and have its elements removed.
* - `onPageDidUnload` - Runs after the page has been destroyed and its elements have been removed.
*
* @see {@link /docs/v2/components#navigation Navigation Component Docs}
*/
var NavController = (function (_super) {
__extends(NavController, _super);
function NavController(parentnavCtrl, app, config, keyboard, elementRef, anchorName, compiler, viewManager, zone, renderer, cd) {
_super.call(this, elementRef, config);
this.parent = parentnavCtrl;
this.app = app;
this.config = config;
this.keyboard = keyboard;
this._anchorName = anchorName;
this._compiler = compiler;
this._viewManager = viewManager;
this._zone = zone;
this._renderer = renderer;
this._cd = cd;
this._views = [];
this._trnsTime = 0;
this._trnsDelay = config.get('pageTransitionDelay');
this._sbTrans = null;
this._sbEnabled = config.get('swipeBackEnabled') || false;
this._sbThreshold = config.get('swipeBackThreshold') || 40;
this.initZIndex = 10;
this.id = ++ctrlIds;
this._ids = -1;
// build a new injector for child ViewControllers to use
this.providers = core_1.Injector.resolve([
core_1.provide(NavController, { useValue: this })
]);
}
/**
* Boolean if the nav controller is actively transitioning or not.
* @private
* @return {bool}
*/
NavController.prototype.isTransitioning = function () {
return (this._trnsTime > Date.now());
};
/**
* Boolean if the nav controller is actively transitioning or not.
* @private
* @return {bool}
*/
NavController.prototype.setTransitioning = function (isTransitioning, fallback) {
if (fallback === void 0) { fallback = 700; }
this._trnsTime = (isTransitioning ? Date.now() + fallback : 0);
};
/**
* Push is how we can pass components and navigate to them. We push the component we want to navigate to on to the navigation stack.
*
* ```typescript
* class MyClass{
* constructor(nav:NavController){
* this.nav = nav;
* }
*
* pushPage(){
* this.nav.push(SecondView);
* }
* }
* ```
*
* We can also pass along parameters to the next view, such as data that we have on the current view. This is a similar concept to to V1 apps with `$stateParams`.
*
* ```typescript
* class MyClass{
* constructor(nav:NavController){
* this.nav = nav;
* }
*
* pushPage(user){
* this.nav.push(SecondView,{
* // user is an object we have in our view
* // typically this comes from an ngFor or some array
* // here we can create an object with a property of
* // paramUser, and set it's value to the user object we passed in
* paramUser: user
* });
* }
* }
* ```
*
* We'll look at how we can access that data in the `SecondView` in the navParam docs
*
* We can also pass any options to the transtion from that same method
*
* ```typescript
* class MyClass{
* constructor(nav:NavController){
* this.nav = nav;
* }
*
* pushPage(user){
* this.nav.push(SecondView,{
* // user is an object we have in our view
* // typically this comes from an ngFor or some array
* // here we can create an object with a property of
* // paramUser, and set it's value to the user object we passed in
* paramUser: user
* },{
* // here we can configure things like the animations direction or
* // or if the view should animate at all.
* direction: back
* });
* }
* }
* ```
* @param {Any} component The name of the component you want to push on the navigation stack
* @param {Object} [params={}] Any nav-params you want to pass along to the next view
* @param {Object} [opts={}] Any options you want to use pass to transtion
* @returns {Promise} Returns a promise when the transition is completed
*/
NavController.prototype.push = function (componentType, params, opts, callback) {
if (params === void 0) { params = {}; }
if (opts === void 0) { opts = {}; }
if (!componentType) {
var errMsg = 'invalid componentType to push';
console.error(errMsg);
return Promise.reject(errMsg);
}
if (typeof componentType !== 'function') {
throw 'Loading component must be a component class, not "' + componentType.toString() + '"';
}
if (this.isTransitioning()) {
return Promise.reject('nav controller actively transitioning');
}
this.setTransitioning(true, 500);
var promise = null;
if (!callback) {
promise = new Promise(function (res) { callback = res; });
}
// do not animate if this is the first in the stack
if (!this._views.length && !opts.animateFirst) {
opts.animate = false;
}
// default the direction to "forward"
opts.direction = opts.direction || 'forward';
// the active view is going to be the leaving one (if one exists)
var leavingView = this.getActive() || new view_controller_1.ViewController();
leavingView.shouldCache = (util_1.isBoolean(opts.cacheLeavingView) ? opts.cacheLeavingView : true);
leavingView.shouldDestroy = !leavingView.shouldCache;
if (leavingView.shouldDestroy) {
leavingView.willUnload();
}
// create a new ViewController
var enteringView = new view_controller_1.ViewController(this, componentType, params);
enteringView.shouldDestroy = false;
enteringView.shouldCache = false;
enteringView.pageType = opts.pageType;
enteringView.handle = opts.handle || null;
// add the view to the stack
this._add(enteringView);
if (this.router) {
// notify router of the state change
this.router.stateChange('push', enteringView, params);
}
// start the transition
this._transition(enteringView, leavingView, opts, callback);
return promise;
};
/**
* If you wanted to navigate back from a current view, you can use the back-button or programatically call `pop()`
* Similar to `push()`, you can pass animation options.
*
* ```typescript
* class SecondView{
* constructor(nav:NavController){
* this.nav = nav;
* }
* goBack(){
* this.nav.pop();
* }
* }
* ```
*
* @param {Object} [opts={}] Any options you want to use pass to transtion
* @returns {Promise} Returns a promise when the transition is completed
*/
NavController.prototype.pop = function (opts) {
if (opts === void 0) { opts = {}; }
if (!opts.animateFirst && !this.canGoBack()) {
return Promise.reject('pop cannot go back');
}
if (this.isTransitioning()) {
return Promise.reject('nav controller actively transitioning');
}
this.setTransitioning(true, 500);
var resolve = null;
var promise = new Promise(function (res) { resolve = res; });
// default the direction to "back"
opts.direction = opts.direction || 'back';
// get the active view and set that it is staged to be leaving
// was probably the one popped from the stack
var leavingView = this.getActive() || new view_controller_1.ViewController();
leavingView.shouldCache = (util_1.isBoolean(opts.cacheLeavingView) ? opts.cacheLeavingView : false);
leavingView.shouldDestroy = !leavingView.shouldCache;
if (leavingView.shouldDestroy) {
leavingView.willUnload();
}
// the entering view is now the new last view
// Note: we might not have an entering view if this is the
// only view on the history stack.
var enteringView = this.getPrevious(leavingView);
if (this.router) {
// notify router of the state change
this.router.stateChange('pop', enteringView);
}
// start the transition
this._transition(enteringView, leavingView, opts, resolve);
return promise;
};
/**
* @private
* Pop to a specific view in the history stack
* @param view {ViewController} to pop to
* @param {Object} [opts={}] Any options you want to use pass to transtion
*/
NavController.prototype.popTo = function (viewCtrl, opts) {
if (opts === void 0) { opts = {}; }
// Get the target index of the view to pop to
var viewIndex = this._views.indexOf(viewCtrl);
var targetIndex = viewIndex + 1;
// Don't pop to the view if it wasn't found, or the target is beyond the view list
if (viewIndex < 0 || targetIndex > this._views.length - 1) {
return Promise.resolve();
}
// ensure the entering view is shown
this._cachePage(viewCtrl, true);
var resolve = null;
var promise = new Promise(function (res) { resolve = res; });
opts.direction = opts.direction || 'back';
var leavingView = this.getActive() || new view_controller_1.ViewController();
// get the views to auto remove without having to do a transiton for each
// the last view (the currently active one) will do a normal transition out
if (this._views.length > 1) {
var autoRemoveItems = this._views.slice(targetIndex, this._views.length);
var popView;
for (var i = 0; i < autoRemoveItems.length; i++) {
popView = autoRemoveItems[i];
popView.shouldDestroy = true;
popView.shouldCache = false;
popView.willUnload();
// only the leaving view should be shown, all others hide
this._cachePage(popView, (popView === leavingView));
}
}
if (this.router) {
this.router.stateChange('pop', viewCtrl);
}
this._transition(viewCtrl, leavingView, opts, resolve);
return promise;
};
/**
* Similar to `pop()`, this method let's you navigate back to the root of the stack, no matter how many views that is
* @param {Object} [opts={}] Any options you want to use pass to transtion
*/
NavController.prototype.popToRoot = function (opts) {
if (opts === void 0) { opts = {}; }
return this.popTo(this.first(), opts);
};
/**
* Inserts a view into the nav stack at the specified index.
* This is useful if you need to add a view at any point in your navigation stack
*
* ```typescript
* export class Detail {
* constructor(nav: NavController) {
* this.nav = nav;
* }
* insertView(){
* this.nav.insert(1,Info)
* }
* }
* ```
*
* This will insert the `Info` view into the second slot of our navigation stack
*
* @param {Number} index The index where you want to insert the view
* @param {Any} component The name of the component you want to insert into the nav stack
* @returns {Promise} Returns a promise when the view has been inserted into the navigation stack
*/
NavController.prototype.insert = function (index, componentType, params, opts) {
if (params === void 0) { params = {}; }
if (opts === void 0) { opts = {}; }
if (!componentType || index < 0) {
return Promise.reject('invalid insert');
}
// push it onto the end
if (index >= this._views.length) {
return this.push(componentType, params, opts);
}
// create new ViewController, but don't render yet
var viewCtrl = new view_controller_1.ViewController(this, componentType, params);
viewCtrl.state = CACHED_STATE;
viewCtrl.shouldDestroy = false;
viewCtrl.shouldCache = false;
this._incId(viewCtrl);
this._views.splice(index, 0, viewCtrl);
this._cleanup();
return Promise.resolve();
};
/**
* Removes a view from the nav stack at the specified index.
*
* ```typescript
* export class Detail {
* constructor(nav: NavController) {
* this.nav = nav;
* }
* removeView(){
* this.nav.remove(1)
* }
* }
* ```
*
* @param {Number} index Remove the view from the nav stack at that index
* @param {Object} [opts={}] Any options you want to use pass to transtion
* @returns {Promise} Returns a promise when the view has been removed
*/
NavController.prototype.remove = function (index, opts) {
if (opts === void 0) { opts = {}; }
if (index < 0 || index >= this._views.length) {
return Promise.reject("index out of range");
}
var viewToRemove = this._views[index];
if (this.isActive(viewToRemove)) {
return this.pop(opts);
}
viewToRemove.shouldDestroy = true;
this._cleanup();
return Promise.resolve();
};
/**
* @private
*/
NavController.prototype.setViews = function (components, opts) {
if (opts === void 0) { opts = {}; }
console.warn('setViews() deprecated, use setPages() instead');
return this.setPages(components, opts);
};
/**
* You can set the views of the current navigation stack and navigate to the last view past
*
*
*```typescript
* import {Page, NavController} from 'ionic/ionic'
* import {Detail} from '../detail/detail'
* import {Info} from '../info/info'
*
* export class Home {
* constructor(nav: NavController) {
* this.nav = nav;
* }
* setPages() {
* this.nav.setPages([List,Detail, Info]);
* }
* }
*```
*
*
*In this example, we're giving the current nav stack an array of pages. Then the navigation stack will navigate to the last view in the array and remove the orignal view you came from.
*
*By default, animations are disabled, but they can be enabled by passing options to the navigation controller
*
*
*```typescript
* import {Page, NavController} from 'ionic/ionic'
* import {Detail} from '../detail/detail'
* import {Info} from '../info/info'
*
* export class Home {
* constructor(nav: NavController) {
* this.nav = nav;
* }
* setPages() {
* this.nav.setPages([List,Detail, Info],{
* animate: true
* });
* }
* }
*```
*
*
*You can also pass any navigation params to the individual pages in the array.
*
*
*```typescript
* import {Page, NavController} from 'ionic/ionic'
* import {Detail} from '../detail/detail'
* import {Info} from '../info/info'
*
* export class Home {
* constructor(nav: NavController) {
* this.nav = nav;
* }
* setPages() {
* this.nav.setPages([{
* componentType: List,
* params: {id: 43}
* }, {
* componentType: Detail,
* params: {id: 45}
* },{
* componentType: Info,
* params: {id: 5}
* }]);
* }
* }
*```
*
* @param {Array} component an arry of components to load in the stack
* @param {Object} [opts={}] Any options you want to use pass
* @returns {Promise} Returns a promise when the pages are set
*/
NavController.prototype.setPages = function (components, opts) {
if (opts === void 0) { opts = {}; }
if (!components || !components.length) {
return Promise.resolve();
}
var leavingView = this.getActive() || new view_controller_1.ViewController();
// if animate has not been set then default to false
opts.animate = opts.animate || false;
// ensure leaving views are not cached, and should be destroyed
opts.cacheLeavingView = false;
// get the views to auto remove without having to do a transiton for each
// the last view (the currently active one) will do a normal transition out
if (this._views.length > 1) {
var autoRemoveItems = this._views.slice(0, this._views.length - 1);
var popView;
for (var i = 0; i < autoRemoveItems.length; i++) {
popView = autoRemoveItems[i];
popView.shouldDestroy = true;
popView.shouldCache = false;
popView.willUnload();
if (opts.animate) {
// only the leaving view should be shown, all others hide
this._cachePage(popView, (popView === leavingView));
}
}
}
var componentObj = null;
var componentType = null;
var viewCtrl = null;
// create the ViewControllers that go before the new active ViewController
// in the stack, but the previous views shouldn't render yet
if (components.length > 1) {
var newBeforeItems = components.slice(0, components.length - 1);
for (var j = 0; j < newBeforeItems.length; j++) {
componentObj = newBeforeItems[j];
if (componentObj) {
// could be an object with a componentType property, or it is a componentType
componentType = componentObj.componentType || componentObj;
viewCtrl = new view_controller_1.ViewController(this, componentType, componentObj.params);
viewCtrl.state = CACHED_STATE;
viewCtrl.shouldDestroy = false;
viewCtrl.shouldCache = false;
// add the item to the stack
this._add(viewCtrl);
}
}
}
// get the component that will become the active item
// it'll be the last one in the given components array
componentObj = components[components.length - 1];
componentType = componentObj.componentType || componentObj;
// transition the leaving and entering
return this.push(componentType, componentObj.params, opts);
};
/**
* Set the root for the current navigation stack
* @param {Component} The name of the component you want to push on the navigation stack
* @param {Object} [params={}] Any nav-params you want to pass along to the next view
* @param {Object} [opts={}] Any options you want to use pass to transtion
* @returns {Promise} Returns a promise when done
*/
NavController.prototype.setRoot = function (componentType, params, opts) {
if (params === void 0) { params = {}; }
if (opts === void 0) { opts = {}; }
return this.setPages([{
componentType: componentType,
params: params
}], opts);
};
/**
* @private
*/
NavController.prototype._transition = function (enteringView, leavingView, opts, done) {
if (enteringView === leavingView) {
// if the entering view and leaving view are the same thing don't continue
return done(enteringView);
}
if (!opts.animation) {
opts.animation = this.config.get('pageTransition');
}
if (this.config.get('animate') === false) {
opts.animate = false;
}
if (!enteringView) {
// if no entering view then create a bogus one
// already consider this bogus one loaded
enteringView = new view_controller_1.ViewController();
enteringView.loaded();
}
var wtfScope = instrumentation_1.wtfStartTimeRange('ionic.NavController#_transition ' + enteringView.name);
/* Async steps to complete a transition
1. _render: compile the view and render it in the DOM. Load page if it hasn't loaded already. When done call postRender
2. _postRender: Run willEnter/willLeave, then wait a frame (change detection happens), then call beginTransition
3. _beforeTrans: Create the transition's animation, play the animation, wait for it to end
4. _afterTrans: Run didEnter/didLeave, call _transComplete()
5. _transComplete: Cleanup, remove cache views, then call the final callback
*/
// begin the multiple async process of transitioning to the entering view
this._render(enteringView, leavingView, opts, function () {
instrumentation_1.wtfEndTimeRange(wtfScope);
done(enteringView);
});
};
/**
* @private
*/
NavController.prototype._render = function (enteringView, leavingView, opts, done) {
// compile/load the view into the DOM
var _this = this;
if (enteringView.shouldDestroy) {
// about to be destroyed, shouldn't continue
done();
}
else if (enteringView.isLoaded()) {
// already compiled this view, do not load again and continue
this._postRender(enteringView, leavingView, opts, done);
}
else {
// view has not been compiled/loaded yet
// continue once the view has finished compiling
// DOM WRITE
this.loadPage(enteringView, null, opts, function () {
if (enteringView.onReady) {
// this entering view needs to wait for it to be ready
// this is used by Tabs to wait for the first page of
// the first selected tab to be loaded
enteringView.onReady(function () {
enteringView.loaded();
_this._postRender(enteringView, leavingView, opts, done);
});
}
else {
enteringView.loaded();
_this._postRender(enteringView, leavingView, opts, done);
}
});
}
};
/**
* @private
*/
NavController.prototype._postRender = function (enteringView, leavingView, opts, done) {
var _this = this;
var wtfScope = instrumentation_1.wtfStartTimeRange('ionic.NavController#_postRender ' + enteringView.name);
// called after _render has completed and the view is compiled/loaded
if (enteringView.shouldDestroy) {
// view already marked as a view that will be destroyed, don't continue
instrumentation_1.wtfEndTimeRange(wtfScope);
done();
}
else if (!opts.preload) {
// the enteringView will become the active view, and is not being preloaded
// call each view's lifecycle events
// POSSIBLE DOM READ THEN DOM WRITE
enteringView.willEnter();
leavingView.willLeave();
// set the correct zIndex for the entering and leaving views
// DOM WRITE
this._setZIndex(enteringView, leavingView, opts.direction);
// make sure the entering and leaving views are showing
// and all others are hidden, but don't remove the leaving view yet
// DOM WRITE
this._cleanup(enteringView, leavingView, true);
// lifecycle events may have updated some data
// wait one frame and allow the raf to do a change detection
// before kicking off the transition and showing the new view
dom_1.raf(function () {
instrumentation_1.wtfEndTimeRange(wtfScope);
_this._beforeTrans(enteringView, leavingView, opts, done);
});
}
else {
// this view is being preloaded, don't call lifecycle events
// transition does not need to animate
opts.animate = false;
instrumentation_1.wtfEndTimeRange(wtfScope);
this._beforeTrans(enteringView, leavingView, opts, done);
}
};
/**
* @private
*/
NavController.prototype._beforeTrans = function (enteringView, leavingView, opts, done) {
var _this = this;
var wtfScope = instrumentation_1.wtfStartTimeRange('ionic.NavController#_beforeTrans ' + enteringView.name);
// called after one raf from postRender()
// create the transitions animation, play the animation
// when the transition ends call wait for it to end
// everything during the transition should runOutsideAngular
this._zone.runOutsideAngular(function () {
// ensure the entering view is not destroyed or cached
enteringView.shouldDestroy = false;
enteringView.shouldCache = false;
// set that the new view pushed on the stack is staged to be entering/leaving
// staged state is important for the transition to find the correct view
enteringView.state = STAGED_ENTERING_STATE;
leavingView.state = STAGED_LEAVING_STATE;
// init the transition animation
opts.renderDelay = opts.transitionDelay || self._trnsDelay;
var transAnimation = animation_1.Animation.createTransition(enteringView, leavingView, opts);
if (opts.animate === false) {
// force it to not animate the elements, just apply the "to" styles
transAnimation.clearDuration();
transAnimation.duration(0);
}
var duration = transAnimation.duration();
var enableApp = (duration < 64);
// block any clicks during the transition and provide a
// fallback to remove the clickblock if something goes wrong
_this.app.setEnabled(enableApp, duration);
_this.setTransitioning(!enableApp, duration);
if (opts.pageType) {
transAnimation.before.addClass(opts.pageType);
}
instrumentation_1.wtfEndTimeRange(wtfScope);
// start the transition
transAnimation.play(function () {
// transition animation has ended
// dispose the animation and it's element references
transAnimation.dispose();
_this._afterTrans(enteringView, leavingView, opts, done);
});
});
};
/**
* @private
*/
NavController.prototype._afterTrans = function (enteringView, leavingView, opts, done) {
var _this = this;
var wtfScope = instrumentation_1.wtfStartTimeRange('ionic.NavController#_afterTrans ' + enteringView.name);
// transition has completed, update each view's state
// place back into the zone, run didEnter/didLeave
// call the final callback when done
enteringView.state = ACTIVE_STATE;
leavingView.state = CACHED_STATE;
// run inside of the zone again
this._zone.run(function () {
if (!opts.preload) {
enteringView.didEnter();
leavingView.didLeave();
}
if (_this.keyboard.isOpen()) {
// the keyboard is still open!
// no problem, let's just close for them
_this.keyboard.close();
_this.keyboard.onClose(function () {
// keyboard has finished closing, transition complete
_this._transComplete();
instrumentation_1.wtfEndTimeRange(wtfScope);
done();
}, 32);
}
else {
// all good, transition complete
_this._transComplete();
instrumentation_1.wtfEndTimeRange(wtfScope);
done();
}
});
};
/**
* @private
*/
NavController.prototype._transComplete = function () {
var wtfScope = instrumentation_1.wtfCreateScope('ionic.NavController#_transComplete')();
this._views.forEach(function (view) {
if (view) {
if (view.shouldDestroy) {
view.didUnload();
}
else if (view.state === CACHED_STATE && view.shouldCache) {
view.shouldCache = false;
}
}
});
// allow clicks again, but still set an enable time
// meaning nothing with this view controller can happen for XXms
this.app.setEnabled(true);
this.setTransitioning(false);
this._sbComplete();
this._cleanup();
instrumentation_1.wtfLeave(wtfScope);
};
/**
* @private
*/
NavController.prototype.loadPage = function (viewCtrl, navbarContainerRef, opts, done) {
var _this = this;
var wtfTimeRangeScope = instrumentation_1.wtfStartTimeRange('ionic.NavController#loadPage ' + viewCtrl.name);
// guts of DynamicComponentLoader#loadIntoLocation
this._compiler.compileInHost(viewCtrl.componentType).then(function (hostProtoViewRef) {
var wtfScope = instrumentation_1.wtfCreateScope('ionic.NavController#loadPage_After_Compile')();
var providers = _this.providers.concat(core_1.Injector.resolve([
core_1.provide(view_controller_1.ViewController, { useValue: viewCtrl }),
core_1.provide(NavParams, { useValue: viewCtrl.params })
]));
var location = _this.elementRef;
if (_this._anchorName) {
location = _this._viewManager.getNamedElementInComponentView(location, _this._anchorName);
}
var viewContainer = _this._viewManager.getViewContainer(location);
var hostViewRef = viewContainer.createHostView(hostProtoViewRef, viewContainer.length, providers);
var pageElementRef = _this._viewManager.getHostElement(hostViewRef);
var component = _this._viewManager.getComponent(pageElementRef);
// auto-add page css className created from component JS class name
var cssClassName = util_1.pascalCaseToDashCase(viewCtrl.componentType.name);
_this._renderer.setElementClass(pageElementRef, cssClassName, true);
viewCtrl.addDestroy(function () {
// ensure the element is cleaned up for when the view pool reuses this element
_this._renderer.setElementAttribute(pageElementRef, 'class', null);
_this._renderer.setElementAttribute(pageElementRef, 'style', null);
// remove the page from its container
var index = viewContainer.indexOf(hostViewRef);
if (index !== -1) {
viewContainer.remove(index);
}
});
// a new ComponentRef has been created
// set the ComponentRef's instance to this ViewController
viewCtrl.setInstance(component);
// remember the ElementRef to the ion-page elementRef that was just created
viewCtrl.setPageRef(pageElementRef);
if (!navbarContainerRef) {
navbarContainerRef = viewCtrl.getNavbarViewRef();
}
var navbarTemplateRef = viewCtrl.getNavbarTemplateRef();
if (navbarContainerRef && navbarTemplateRef) {
var navbarView = navbarContainerRef.createEmbeddedView(navbarTemplateRef);
viewCtrl.addDestroy(function () {
var index = navbarContainerRef.indexOf(navbarView);
if (index > -1) {
navbarContainerRef.remove(index);
}
});
}
opts.postLoad && opts.postLoad(viewCtrl);
if (_this._views.length === 1) {
_this._zone.runOutsideAngular(function () {
dom_1.rafFrames(38, function () {
_this._renderer.setElementClass(_this.elementRef, 'has-views', true);
});
});
}
instrumentation_1.wtfEndTimeRange(wtfTimeRangeScope);
instrumentation_1.wtfLeave(wtfScope);
done(viewCtrl);
});
};
/**
* @private
*/
NavController.prototype._setZIndex = function (enteringView, leavingView, direction) {
var enteringPageRef = enteringView && enteringView.pageRef();
if (enteringPageRef) {
if (!leavingView || !leavingView.isLoaded()) {
enteringView.zIndex = this.initZIndex;
}
else if (direction === 'back') {
// moving back
enteringView.zIndex = leavingView.zIndex - 1;
}
else {
// moving forward
enteringView.zIndex = leavingView.zIndex + 1;
}
if (enteringView.zIndex !== enteringView._zIndex) {
this._renderer.setElementStyle(enteringPageRef, 'z-index', enteringView.zIndex);
enteringView._zIndex = enteringView.zIndex;
}
}
};
/**
* @private
*/
NavController.prototype._cachePage = function (viewCtrl, shouldShow) {
// using hidden element attribute to display:none and not render views
// renderAttr of '' means the hidden attribute will be added
// renderAttr of null means the hidden attribute will be removed
// doing checks to make sure we only make an update to the element when needed
if (shouldShow && viewCtrl._hdnAttr === '' ||
!shouldShow && viewCtrl._hdnAttr !== '') {
viewCtrl._hdnAttr = (shouldShow ? null : '');
this._renderer.setElementAttribute(viewCtrl.pageRef(), 'hidden', viewCtrl._hdnAttr);
var navbarRef = viewCtrl.navbarRef();
if (navbarRef) {
this._renderer.setElementAttribute(navbarRef, 'hidden', viewCtrl._hdnAttr);
}
}
};
/**
* @private
*/
NavController.prototype._cleanup = function (activeView, previousView, skipDestroy) {
var _this = this;
// the active page, and the previous page, should be rendered in dom and ready to go
// all others, like a cached page 2 back, should be display: none and not rendered
var destroys = [];
activeView = activeView || this.getActive();
previousView = previousView || this.getPrevious(activeView);
this._views.forEach(function (view) {
if (view) {
if (view.shouldDestroy && !skipDestroy) {
destroys.push(view);
}
else if (view.isLoaded()) {
var shouldShow = (view === activeView) || (view === previousView);
_this._cachePage(view, shouldShow);
}
}
});
// all pages being destroyed should be removed from the list of pages
// and completely removed from the dom
destroys.forEach(function (view) {
_this._remove(view);
view.destroy();
});
};
/**
* @private
*/
NavController.prototype.swipeBackStart = function () {
var _this = this;
return;
if (!this.app.isEnabled() || !this.canSwipeBack()) {
return;
}
// disables the app during the transition
this.app.setEnabled(false);
this.setTransitioning(true);
// default the direction to "back"
var opts = {
direction: 'back'
};
// get the active view and set that it is staged to be leaving
// was probably the one popped from the stack
var leavingView = this.getActive() || new view_controller_1.ViewController();
leavingView.shouldDestroy = true;
leavingView.shouldCache = false;
leavingView.willLeave();
leavingView.willUnload();
// the entering view is now the new last view
var enteringView = this.getPrevious(leavingView);
enteringView.shouldDestroy = false;
enteringView.shouldCache = false;
enteringView.willEnter();
// wait for the new view to complete setup
this._render(enteringView, {}, function () {
_this._zone.runOutsideAngular(function () {
// set that the new view pushed on the stack is staged to be entering/leaving
// staged state is important for the transition to find the correct view
enteringView.state = STAGED_ENTERING_STATE;
leavingView.state = STAGED_LEAVING_STATE;
// init the swipe back transition animation
_this._sbTrans = Transition.create(_this, opts);
_this._sbTrans.easing('linear').progressStart();
});
});
};
/**
* @private
*/
NavController.prototype.swipeBackProgress = function (value) {
return;
if (this._sbTrans) {
// continue to disable the app while actively dragging
this.app.setEnabled(false, 4000);
this.setTransitioning(true, 4000);
// set the transition animation's progress
this._sbTrans.progress(value);
}
};
/**
* @private
*/
NavController.prototype.swipeBackEnd = function (completeSwipeBack, rate) {
var _this = this;
return;
if (!this._sbTrans)
return;
// disables the app during the transition
this.app.setEnabled(false);
this.setTransitioning(true);
this._sbTrans.progressEnd(completeSwipeBack, rate).then(function () {
_this._zone.run(function () {
// find the views that were entering and leaving
var enteringView = _this._getStagedEntering();
var leavingView = _this._getStagedLeaving();
if (enteringView && leavingView) {
// finish up the animation
if (completeSwipeBack) {
// swipe back has completed navigating back
// update each view's state
enteringView.state = ACTIVE_STATE;
leavingView.state = CACHED_STATE;
enteringView.didEnter();
leavingView.didLeave();
if (_this.router) {
// notify router of the pop state change
_this.router.stateChange('pop', enteringView);
}
}
else {
// cancelled the swipe back, they didn't end up going back
// return views to their original state
leavingView.state = ACTIVE_STATE;
enteringView.state = CACHED_STATE;
leavingView.willEnter();
leavingView.didEnter();
enteringView.didLeave();
leavingView.shouldDestroy = false;
enteringView.shouldDestroy = false;
}
}
// empty out and dispose the swipe back transition animation
_this._sbTrans && _this._sbTrans.dispose();
_this._sbTrans = null;
// all done!
_this._transComplete();
});
});
};
/**
* @private
*/
NavController.prototype._sbComplete = function () {
return;
if (this.canSwipeBack()) {
// it is possible to swipe back
if (this.sbGesture) {
// this is already an active gesture, don't create another one
return;
}
var opts = {
edge: 'left',
threshold: this._sbThreshold
};
this.sbGesture = new swipe_back_1.SwipeBackGesture(this.getNativeElement(), opts, this);
console.debug('SwipeBackGesture listen');
this.sbGesture.listen();
}
else if (this.sbGesture) {
// it is not possible to swipe back and there is an
// active sbGesture, so unlisten it
console.debug('SwipeBackGesture unlisten');
this.sbGesture.unlisten();
this.sbGesture = null;
}
};
/**
* Check to see if swipe-to-go-back is enabled
* @param {boolean=} isSwipeBackEnabled Set whether or not swipe-to-go-back is enabled
* @returns {boolean} Whether swipe-to-go-back is enabled
*/
NavController.prototype.isSwipeBackEnabled = function (val) {
if (arguments.length) {
this._sbEnabled = !!val;
}
return this._sbEnabled;
};
/**
* If it's possible to use swipe back or not. If it's not possible
* to go back, or swipe back is not enable then this will return false.
* If it is possible to go back, and swipe back is enabled, then this
* will return true.
* @returns {boolean} Whether you can swipe to go back
*/
NavController.prototype.canSwipeBack = function () {
return (this._sbEnabled && this.canGoBack());
};
/**
* Returns `true` if there's a valid previous page that we can pop back to.
* Otherwise returns false.
* @returns {boolean} Whether there is a page to go back to
*/
NavController.prototype.canGoBack = function () {
var activeView = this.getActive();
if (activeView) {
return activeView.enableBack();
}
return false;
};
/**
* @private
*/
NavController.prototype.navbarViewContainer = function (nbContainer) {
if (nbContainer) {
this._nbContainer = nbContainer;
}
if (this._nbContainer) {
return this._nbContainer;
}
if (this.parent) {
return this.parent.navbarViewContainer();
}
};
/**
* @private
* @returns {TODO} TODO
*/
NavController.prototype.anchorElementRef = function () {
if (arguments.length) {
this._anchorER = arguments[0];
}
return this._anchorER;
};
/**
* @private
*/
NavController.prototype._add = function (viewCtrl) {
this._incId(viewCtrl);
this._views.push(viewCtrl);
};
/**
* @private
*/
NavController.prototype._incId = function (viewCtrl) {
viewCtrl.id = this.id + '-' + (++this._ids);
};
/**
* @private
*/
NavController.prototype._remove = function (viewOrIndex) {
util_1.array.remove(this._views, viewOrIndex);
};
/**
* @private
*/
NavController.prototype._getStagedEntering = function () {
for (var i = 0, ii = this._views.length; i < ii; i++) {
if (this._views[i].state === STAGED_ENTERING_STATE) {
return this._views[i];
}
}
return null;
};
/**
* @private
*/
NavController.prototype._getStagedLeaving = function () {
for (var i = 0, ii = this._views.length; i < ii; i++) {
if (this._views[i].state === STAGED_LEAVING_STATE) {
return this._views[i];
}
}
return null;
};
/**
* @private
* @returns {Component} TODO
*/
NavController.prototype.getActive = function () {
for (var i = this._views.length - 1; i >= 0; i--) {
if (this._views[i].state === ACTIVE_STATE && !this._views[i].shouldDestroy) {
return this._views[i];
}
}
return null;
};
/**
* @param {Index} The index of the page you want to get
* @returns {Component} Returns the component that matches the index given
*/
NavController.prototype.getByIndex = function (index) {
if (index < this._views.length && index > -1) {
return this._views[index];
}
return null;
};
/**
* @private
* @param {Handle} The handle of the page you want to get
* @returns {Component} Returns the component that matches the handle given
*/
NavController.prototype.getByHandle = function (handle) {
for (var i = 0, ii = this._views.length; i < ii; i++) {
if (this._views[i].handle === handle) {
return this._views[i];
}
}
return null;
};
/**
* @private
* @param {TODO} pageType TODO
* @returns {TODO} TODO
*/
NavController.prototype.getByType = function (pageType) {
for (var i = 0, ii = this._views.length; i < ii; i++) {
if (this._views[i].pageType === pageType) {
return this._views[i];
}
}
return null;
};
/**
* @private
* @param {TODO} view TODO
* @returns {TODO} TODO
*/
NavController.prototype.getPrevious = function (viewCtrl) {
if (viewCtrl) {
var viewIndex = this._views.indexOf(viewCtrl);
for (var i = viewIndex - 1; i >= 0; i--) {
if (!this._views[i].shouldDestroy) {
return this._views[i];
}
}
}
return null;
};
/**
* First page in this nav controller's stack. This would not return a page which is about to be destroyed.
* @returns {Component} Returns the first component page in the current stack
*/
NavController.prototype.first = function () {
for (var i = 0, l = this._views.length; i < l; i++) {
if (!this._views[i].shouldDestroy) {
return this._views[i];
}
}
return null;
};
/**
* Last page in this nav controller's stack. This would not return a page which is about to be destroyed.
* @returns {Component} Returns the last component page in the current stack
*/
NavController.prototype.last = function () {
for (var i = this._views.length - 1; i >= 0; i--) {
if (!this._views[i].shouldDestroy) {
return this._views[i];
}
}
return null;
};
/**
* @private
* @param {TODO} view TODO
* @returns {TODO} TODO
*/
NavController.prototype.indexOf = function (viewCtrl) {
return this._views.indexOf(viewCtrl);
};
/**
* Number of sibling views in the nav controller. This does
* not include views which are about to be destroyed.
* @returns {Number} The number of views in stack, including the current view
*/
NavController.prototype.length = function () {
var len = 0;
for (var i = 0, l = this._views.length; i < l; i++) {
if (!this._views[i].shouldDestroy) {
len++;
}
}
return len;
};
/**
* @private
* @param {TODO} view TODO
* @returns {boolean}
*/
NavController.prototype.isActive = function (viewCtrl) {
return !!(viewCtrl && viewCtrl.state === ACTIVE_STATE);
};
Object.defineProperty(NavController.prototype, "rootNav", {
/**
* Returns the root NavController.
* @returns {NavController}
*/
get: function () {
var nav = this;
while (nav.parent) {
nav = nav.parent;
}
return nav;
},
enumerable: true,
configurable: true
});
/**
* @private
* @param {TODO} router TODO
*/
NavController.prototype.registerRouter = function (router) {
this.router = router;
};
return NavController;
})(ion_1.Ion);
exports.NavController = NavController;
var ACTIVE_STATE = 1;
var CACHED_STATE = 2;
var STAGED_ENTERING_STATE = 3;
var STAGED_LEAVING_STATE = 4;
var ctrlIds = -1;
/**
* @name NavParams
* @description
* NavParams are an object that exists on a page and can contain data for that particular view.
* Similar to how data was pass to a view in V1 with `$stateParams`, NavParams offer a much more flexible
* option with a simple `get` method.
*
* @usage
* ```ts
* export class MyClass{
* constructor(params: NavParams){
* this.params = params;
* // userParams is an object we have in our nav-parameters
* this.params.get('userParams');
* }
* }
* ```
* @demo /docs/v2/demos/nav-params/
* @see {@link /docs/v2/components#navigation Navigation Component Docs}
* @see {@link ../NavController/ NavController API Docs}
* @see {@link ../Nav/ Nav API Docs}
* @see {@link ../NavPush/ NavPush API Docs}
*/
var NavParams = (function () {
/**
* @private
* @param {TODO} data TODO
*/
function NavParams(data) {
this.data = data || {};
}
/**
* Get the value of a nav-parameter for the current view
*
* ```ts
* export class MyClass{
* constructor(params: NavParams){
* this.params = params;
* // userParams is an object we have in our nav-parameters
* this.params.get('userParams');
* }
* }
* ```
*
*
* @param {string} parameter Which param you want to look up
*/
NavParams.prototype.get = function (param) {
return this.data[param];
};
return NavParams;
})();
exports.NavParams = NavParams;
/***/ },
/* 22 */
/***/ function(module, exports) {
module.exports = require("angular2")["instrumentation"];
/***/ },
/* 23 */
/***/ function(module, exports, __webpack_require__) {
var dom = __webpack_require__(11);
/**
* Base class for all Ionic components. Exposes some common functionality
* that all Ionic components need, such as accessing underlying native elements and
* sending/receiving app-level events.
*/
var Ion = (function () {
function Ion(elementRef, config) {
this.elementRef = elementRef;
this.config = config;
}
Ion.prototype.ngOnInit = function () {
var cls = this.constructor;
if (cls.defaultInputs && this.config) {
for (var prop in cls.defaultInputs) {
// Priority:
// ---------
// 1) Value set from within constructor
// 2) Value set from the host element's attribute
// 3) Value set by the users global config
// 4) Value set by the default mode/platform config
// 5) Value set from the component's default
if (this[prop]) {
// this property has already been set on the instance
// could be from the user setting the element's attribute
// or from the user setting it within the constructor
continue;
}
// get the property values from a global user/platform config
var configVal = this.config.get(prop);
if (configVal) {
this[prop] = configVal;
continue;
}
// wasn't set yet, so go with property's default value
this[prop] = cls.defaultInputs[prop];
}
}
};
Ion.prototype.getElementRef = function () {
return this.elementRef;
};
Ion.prototype.getNativeElement = function () {
return this.elementRef.nativeElement;
};
Ion.prototype.getDimensions = function () {
return dom.getDimensions(this);
};
Ion.prototype.width = function () {
return dom.getDimensions(this).width;
};
Ion.prototype.height = function () {
return dom.getDimensions(this).height;
};
return Ion;
})();
exports.Ion = Ion;
/***/ },
/* 24 */
/***/ function(module, exports, __webpack_require__) {
var nav_controller_1 = __webpack_require__(21);
/**
* @name ViewController
* @description
* Access various features and information about the current view
* @usage
* ```ts
* import {Page, ViewController} from 'ionic/ionic';
* @Page....
* export class MyPage{
* constructor(viewCtrl: ViewController){
* this.viewCtrl = viewCtrl;
* }
* }
* ```
*/
var ViewController = (function () {
function ViewController(navCtrl, componentType, params) {
if (params === void 0) { params = {}; }
this.navCtrl = navCtrl;
this.componentType = componentType;
this.params = new nav_controller_1.NavParams(params);
this.instance = {};
this.state = 0;
this._destroys = [];
this._loaded = false;
}
/**
* Check to see if you can go back in the navigation stack
* @param {boolean} Check whether or not you can go back from this page
* @returns {boolean} Returns if it's possible to go back from this Page.
*/
ViewController.prototype.enableBack = function () {
// update if it's possible to go back from this nav item
if (this.navCtrl) {
var previousItem = this.navCtrl.getPrevious(this);
// the previous view may exist, but if it's about to be destroyed
// it shouldn't be able to go back to
return !!(previousItem && !previousItem.shouldDestroy);
}
return false;
};
/**
* @private
*/
ViewController.prototype.setInstance = function (instance) {
this.instance = instance;
};
Object.defineProperty(ViewController.prototype, "name", {
/**
* @private
*/
get: function () {
return this.componentType ? this.componentType.name : '';
},
enumerable: true,
configurable: true
});
Object.defineProperty(ViewController.prototype, "index", {
/**
* You can find out the index of the current view is in the current navigation stack
*
* ```typescript
* export class Page1 {
* constructor(view: ViewController){
* this.view = view;
* // Just log out the index
* console.log(this.view.index);
* }
* }
* ```
*
* @returns {Number} Returns the index of this page within its NavController.
*/
get: function () {
return (this.navCtrl ? this.navCtrl.indexOf(this) : -1);
},
enumerable: true,
configurable: true
});
/**
* @returns {boolean} Returns if this Page is the root page of the NavController.
*/
ViewController.prototype.isRoot = function () {
return (this.index === 0);
};
/**
* @private
*/
ViewController.prototype.addDestroy = function (destroyFn) {
this._destroys.push(destroyFn);
};
/**
* @private
*/
ViewController.prototype.destroy = function () {
for (var i = 0; i < this._destroys.length; i++) {
this._destroys[i]();
}
this._destroys = [];
};
/**
* @private
*/
ViewController.prototype.setNavbarTemplateRef = function (templateRef) {
this._nbTmpRef = templateRef;
};
/**
* @private
*/
ViewController.prototype.getNavbarTemplateRef = function () {
return this._nbTmpRef;
};
/**
* @private
*/
ViewController.prototype.getNavbarViewRef = function () {
return this._nbVwRef;
};
/**
* @private
*/
ViewController.prototype.setNavbarViewRef = function (viewContainerRef) {
this._nbVwRef = viewContainerRef;
};
/**
* @private
*/
ViewController.prototype.setPageRef = function (elementRef) {
this._pgRef = elementRef;
};
/**
* @private
* @returns {ElementRef} Returns the Page's ElementRef
*/
ViewController.prototype.pageRef = function () {
return this._pgRef;
};
/**
* @private
*/
ViewController.prototype.setContentRef = function (elementRef) {
this._cntRef = elementRef;
};
/**
* @private
* @returns {ElementRef} Returns the Page's Content ElementRef
*/
ViewController.prototype.contentRef = function () {
return this._cntRef;
};
/**
* @private
*/
ViewController.prototype.setContent = function (directive) {
this._cntDir = directive;
};
/**
* @private
* @returns {Component} Returns the Page's Content component reference.
*/
ViewController.prototype.getContent = function () {
return this._cntDir;
};
/**
* @private
*/
ViewController.prototype.setNavbar = function (directive) {
this._nbDir = directive;
};
/**
* @private
*/
ViewController.prototype.getNavbar = function () {
return this._nbDir;
};
/**
* You can find out of the current view has a Navbar or not. Be sure to wrap this in an `onPageWillEnter` method in order to make sure the view has rendered fully.
*
* ```typescript
* export class Page1 {
* constructor(view: ViewController) {
* this.view = view
* }
* onPageWillEnter(){
* console.log('Do we have a Navbar?', this.view.hasNavbar());
* }
*}
* ```
*
* @returns {boolean} Returns a boolean if this Page has a navbar or not.
*/
ViewController.prototype.hasNavbar = function () {
return !!this.getNavbar();
};
/**
* @private
*/
ViewController.prototype.navbarRef = function () {
var navbar = this.getNavbar();
return navbar && navbar.getElementRef();
};
/**
* @private
*/
ViewController.prototype.titleRef = function () {
var navbar = this.getNavbar();
return navbar && navbar.getTitleRef();
};
/**
* @private
*/
ViewController.prototype.navbarItemRefs = function () {
var navbar = this.getNavbar();
return navbar && navbar.getItemRefs();
};
/**
* @private
*/
ViewController.prototype.backBtnRef = function () {
var navbar = this.getNavbar();
return navbar && navbar.getBackButtonRef();
};
/**
* @private
*/
ViewController.prototype.backBtnTextRef = function () {
var navbar = this.getNavbar();
return navbar && navbar.getBackButtonTextRef();
};
/**
* @private
*/
ViewController.prototype.navbarBgRef = function () {
var navbar = this.getNavbar();
return navbar && navbar.getBackgroundRef();
};
/**
* You can change the text of the back button on a view-by-view basis.
*
* ```ts
* export class MyClass{
* constructor(viewCtrl: ViewController){
* this.viewCtrl = viewCtrl
* }
* onPageWillEnter() {
* this.viewCtrl.setBackButtonText('Previous');
* }
* }
* ```
* Make sure you use the view events when calling this method, otherwise the back-button will not have been created
*
* @param {string} backButtonText Set the back button text.
*/
ViewController.prototype.setBackButtonText = function (val) {
var navbar = this.getNavbar();
if (navbar) {
navbar.bbText = val;
}
};
/**
* Set if the back button for the current view is visible or not. Be sure to wrap this in `onPageWillEnter` to make sure the has been compleltly rendered.
* @param {boolean} Set if this Page's back button should show or not.
*/
ViewController.prototype.showBackButton = function (shouldShow) {
var navbar = this.getNavbar();
if (navbar) {
navbar.hideBackButton = !shouldShow;
}
};
/**
* @private
*/
ViewController.prototype.isLoaded = function () {
return this._loaded;
};
/**
* @private
* The view has loaded. This event only happens once per view being
* created. If a view leaves but is cached, then this will not
* fire again on a subsequent viewing. This method is a good place
* to put your setup code for the view; however, it is not the
* recommended method to use when a view becomes active.
*/
ViewController.prototype.loaded = function () {
this._loaded = true;
if (!this.shouldDestroy) {
ctrlFn(this, 'onPageLoaded');
}
};
/**
* @private
* The view is about to enter and become the active view.
*/
ViewController.prototype.willEnter = function () {
if (!this.shouldDestroy) {
ctrlFn(this, 'onPageWillEnter');
}
};
/**
* @private
* The view has fully entered and is now the active view. This
* will fire, whether it was the first load or loaded from the cache.
*/
ViewController.prototype.didEnter = function () {
var navbar = this.getNavbar();
navbar && navbar.didEnter();
ctrlFn(this, 'onPageDidEnter');
};
/**
* @private
* The view has is about to leave and no longer be the active view.
*/
ViewController.prototype.willLeave = function () {
ctrlFn(this, 'onPageWillLeave');
};
/**
* @private
* The view has finished leaving and is no longer the active view. This
* will fire, whether it is cached or unloaded.
*/
ViewController.prototype.didLeave = function () {
ctrlFn(this, 'onPageDidLeave');
};
/**
* @private
* The view is about to be destroyed and have its elements removed.
*/
ViewController.prototype.willUnload = function () {
ctrlFn(this, 'onPageWillUnload');
};
/**
* @private
* The view has been destroyed and its elements have been removed.
*/
ViewController.prototype.didUnload = function () {
ctrlFn(this, 'onPageDidUnload');
};
return ViewController;
})();
exports.ViewController = ViewController;
function ctrlFn(viewCtrl, fnName) {
if (viewCtrl.instance && viewCtrl.instance[fnName]) {
try {
viewCtrl.instance[fnName]();
}
catch (e) {
console.error(fnName + ': ' + e.message);
}
}
}
/***/ },
/* 25 */
/***/ function(module, exports, __webpack_require__) {
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var slide_edge_gesture_1 = __webpack_require__(26);
var SwipeBackGesture = (function (_super) {
__extends(SwipeBackGesture, _super);
function SwipeBackGesture(element, opts, navCtrl) {
if (opts === void 0) { opts = {}; }
_super.call(this, element, opts);
// Can check corners through use of eg 'left top'
this.edges = opts.edge.split(' ');
this.threshold = opts.threshold;
this.navCtrl = navCtrl;
}
SwipeBackGesture.prototype.onSlideStart = function () {
this.navCtrl.swipeBackStart();
};
SwipeBackGesture.prototype.onSlide = function (slide, ev) {
this.navCtrl.swipeBackProgress(slide.distance / slide.max);
};
SwipeBackGesture.prototype.onSlideEnd = function (slide, ev) {
var shouldComplete = (Math.abs(ev.velocityX) > 0.2 || Math.abs(slide.delta) > Math.abs(slide.max) * 0.5);
// TODO: calculate a better playback rate depending on velocity and distance
this.navCtrl.swipeBackEnd(shouldComplete, 1);
};
return SwipeBackGesture;
})(slide_edge_gesture_1.SlideEdgeGesture);
exports.SwipeBackGesture = SwipeBackGesture;
/***/ },
/* 26 */
/***/ function(module, exports, __webpack_require__) {
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var slide_gesture_1 = __webpack_require__(27);
var util_1 = __webpack_require__(10);
var dom_1 = __webpack_require__(11);
var SlideEdgeGesture = (function (_super) {
__extends(SlideEdgeGesture, _super);
function SlideEdgeGesture(element, opts) {
if (opts === void 0) { opts = {}; }
util_1.defaults(opts, {
edge: 'left',
threshold: 50
});
_super.call(this, element, opts);
// Can check corners through use of eg 'left top'
this.edges = opts.edge.split(' ');
this.threshold = opts.threshold;
}
SlideEdgeGesture.prototype.canStart = function (ev) {
var _this = this;
this._d = this.getContainerDimensions();
return this.edges.every(function (edge) { return _this._checkEdge(edge, ev.center); });
};
SlideEdgeGesture.prototype.getContainerDimensions = function () {
return {
left: 0,
top: 0,
width: dom_1.windowDimensions().width,
height: dom_1.windowDimensions().height
};
};
SlideEdgeGesture.prototype._checkEdge = function (edge, pos) {
switch (edge) {
case 'left': return pos.x <= this._d.left + this.threshold;
case 'right': return pos.x >= this._d.width - this.threshold;
case 'top': return pos.y <= this._d.top + this.threshold;
case 'bottom': return pos.y >= this._d.height - this.threshold;
}
};
return SlideEdgeGesture;
})(slide_gesture_1.SlideGesture);
exports.SlideEdgeGesture = SlideEdgeGesture;
/***/ },
/* 27 */
/***/ function(module, exports, __webpack_require__) {
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var drag_gesture_1 = __webpack_require__(28);
var util = __webpack_require__(14);
var SlideGesture = (function (_super) {
__extends(SlideGesture, _super);
function SlideGesture(element, opts) {
if (opts === void 0) { opts = {}; }
_super.call(this, element, opts);
this.element = element;
}
/*
* Get the min and max for the slide. pageX/pageY.
* Only called on dragstart.
*/
SlideGesture.prototype.getSlideBoundaries = function (slide, ev) {
return {
min: 0,
max: this.element.offsetWidth
};
};
/*
* Get the element's pos when the drag starts.
* For example, an open side menu starts at 100% and a closed
* sidemenu starts at 0%.
*/
SlideGesture.prototype.getElementStartPos = function (slide, ev) {
return 0;
};
SlideGesture.prototype.canStart = function () {
return true;
};
SlideGesture.prototype.onDragStart = function (ev) {
var _this = this;
if (!this.canStart(ev))
return false;
this.slide = {};
var promise = this.onSlideBeforeStart(this.slide, ev) || Promise.resolve();
promise.then(function () {
var _a = _this.getSlideBoundaries(_this.slide, ev), min = _a.min, max = _a.max;
_this.slide.min = min;
_this.slide.max = max;
_this.slide.elementStartPos = _this.getElementStartPos(_this.slide, ev);
_this.slide.pointerStartPos = ev.center[_this.direction];
_this.slide.started = true;
_this.onSlideStart(_this.slide, ev);
}).catch(function () {
_this.slide = null;
});
};
SlideGesture.prototype.onDrag = function (ev) {
if (!this.slide || !this.slide.started)
return;
this.slide.pos = ev.center[this.direction];
this.slide.distance = util.clamp(this.slide.min, this.slide.pos - this.slide.pointerStartPos + this.slide.elementStartPos, this.slide.max);
this.slide.delta = this.slide.pos - this.slide.pointerStartPos;
this.onSlide(this.slide, ev);
};
SlideGesture.prototype.onDragEnd = function (ev) {
if (!this.slide || !this.slide.started)
return;
this.onSlideEnd(this.slide, ev);
this.slide = null;
};
SlideGesture.prototype.onSlideBeforeStart = function () { };
SlideGesture.prototype.onSlideStart = function () { };
SlideGesture.prototype.onSlide = function () { };
SlideGesture.prototype.onSlideEnd = function () { };
return SlideGesture;
})(drag_gesture_1.DragGesture);
exports.SlideGesture = SlideGesture;
/***/ },
/* 28 */
/***/ function(module, exports, __webpack_require__) {
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var gesture_1 = __webpack_require__(29);
var util = __webpack_require__(14);
var DragGesture = (function (_super) {
__extends(DragGesture, _super);
function DragGesture(element, opts) {
if (opts === void 0) { opts = {}; }
util.defaults(opts, {});
_super.call(this, element, opts);
}
DragGesture.prototype.listen = function () {
var _this = this;
_super.prototype.listen.call(this);
this.on('panstart', function (ev) {
if (_this.onDragStart(ev) !== false) {
_this.dragging = true;
}
});
this.on('panmove', function (ev) {
if (!_this.dragging)
return;
if (_this.onDrag(ev) === false) {
_this.dragging = false;
}
});
this.on('panend', function (ev) {
if (!_this.dragging)
return;
_this.onDragEnd(ev);
_this.dragging = false;
});
this.hammertime.get('pan').set(this._options);
};
DragGesture.prototype.onDrag = function () { };
DragGesture.prototype.onDragStart = function () { };
DragGesture.prototype.onDragEnd = function () { };
return DragGesture;
})(gesture_1.Gesture);
exports.DragGesture = DragGesture;
/***/ },
/* 29 */
/***/ function(module, exports, __webpack_require__) {
var util = __webpack_require__(14);
var hammer_1 = __webpack_require__(30);
/**
* A gesture recognizer class.
*
* TODO(mlynch): Re-enable the DOM event simulation that was causing issues (or verify hammer does this already, it might);
*/
var Gesture = (function () {
function Gesture(element, opts) {
if (opts === void 0) { opts = {}; }
util.defaults(opts, {
domEvents: true
});
this.element = element;
// Map 'x' or 'y' string to hammerjs opts
this.direction = opts.direction || 'x';
opts.direction = this.direction === 'x' ?
hammer_1.Hammer.DIRECTION_HORIZONTAL :
hammer_1.Hammer.DIRECTION_VERTICAL;
this._options = opts;
this._callbacks = {};
}
Gesture.prototype.options = function (opts) {
if (opts === void 0) { opts = {}; }
util.extend(this._options, opts);
};
Gesture.prototype.on = function (type, cb) {
if (type == 'pinch' || type == 'rotate') {
this.hammertime.get('pinch').set({ enable: true });
}
this.hammertime.on(type, cb);
(this._callbacks[type] || (this._callbacks[type] = [])).push(cb);
};
Gesture.prototype.off = function (type, cb) {
this.hammertime.off(type, this._callbacks[type] ? cb : null);
};
Gesture.prototype.listen = function () {
this.hammertime = hammer_1.Hammer(this.element, this._options);
};
Gesture.prototype.unlisten = function () {
if (this.hammertime) {
for (var type in this._callbacks) {
for (var i = 0; i < this._callbacks[type].length; i++) {
this.hammertime.off(type, this._callbacks[type]);
}
}
this.hammertime.destroy();
this.hammertime = null;
this._callbacks = {};
}
};
Gesture.prototype.destroy = function () {
this.unlisten();
};
return Gesture;
})();
exports.Gesture = Gesture;
/***/ },
/* 30 */
/***/ function(module, exports) {
/*! Hammer.JS - v2.0.4 - 2014-09-28
* http://hammerjs.github.io/
*
* Copyright (c) 2014 Jorik Tangelder;
* Licensed under the MIT license */
var VENDOR_PREFIXES = ['', 'webkit', 'moz', 'MS', 'ms', 'o'];
var TEST_ELEMENT = document.createElement('div');
var TYPE_FUNCTION = 'function';
var round = Math.round;
var abs = Math.abs;
var now = Date.now;
/**
* set a timeout with a given scope
* @param {Function} fn
* @param {Number} timeout
* @param {Object} context
* @returns {number}
*/
function setTimeoutContext(fn, timeout, context) {
return setTimeout(bindFn(fn, context), timeout);
}
/**
* if the argument is an array, we want to execute the fn on each entry
* if it aint an array we don't want to do a thing.
* this is used by all the methods that accept a single and array argument.
* @param {*|Array} arg
* @param {String} fn
* @param {Object} [context]
* @returns {Boolean}
*/
function invokeArrayArg(arg, fn, context) {
if (Array.isArray(arg)) {
each(arg, context[fn], context);
return true;
}
return false;
}
/**
* walk objects and arrays
* @param {Object} obj
* @param {Function} iterator
* @param {Object} context
*/
function each(obj, iterator, context) {
var i;
if (!obj) {
return;
}
if (obj.forEach) {
obj.forEach(iterator, context);
}
else if (obj.length !== undefined) {
i = 0;
while (i < obj.length) {
iterator.call(context, obj[i], i, obj);
i++;
}
}
else {
for (i in obj) {
obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
}
}
}
/**
* extend object.
* means that properties in dest will be overwritten by the ones in src.
* @param {Object} dest
* @param {Object} src
* @param {Boolean} [merge]
* @returns {Object} dest
*/
function extend(dest, src, merge) {
var keys = Object.keys(src);
var i = 0;
while (i < keys.length) {
if (!merge || (merge && dest[keys[i]] === undefined)) {
dest[keys[i]] = src[keys[i]];
}
i++;
}
return dest;
}
/**
* merge the values from src in the dest.
* means that properties that exist in dest will not be overwritten by src
* @param {Object} dest
* @param {Object} src
* @returns {Object} dest
*/
function merge(dest, src) {
return extend(dest, src, true);
}
/**
* simple class inheritance
* @param {Function} child
* @param {Function} base
* @param {Object} [properties]
*/
function inherit(child, base, properties) {
var baseP = base.prototype, childP;
childP = child.prototype = Object.create(baseP);
childP.constructor = child;
childP._super = baseP;
if (properties) {
extend(childP, properties);
}
}
/**
* simple function bind
* @param {Function} fn
* @param {Object} context
* @returns {Function}
*/
function bindFn(fn, context) {
return function boundFn() {
return fn.apply(context, arguments);
};
}
/**
* let a boolean value also be a function that must return a boolean
* this first item in args will be used as the context
* @param {Boolean|Function} val
* @param {Array} [args]
* @returns {Boolean}
*/
function boolOrFn(val, args) {
if (typeof val == TYPE_FUNCTION) {
return val.apply(args ? args[0] || undefined : undefined, args);
}
return val;
}
/**
* use the val2 when val1 is undefined
* @param {*} val1
* @param {*} val2
* @returns {*}
*/
function ifUndefined(val1, val2) {
return (val1 === undefined) ? val2 : val1;
}
/**
* addEventListener with multiple events at once
* @param {EventTarget} target
* @param {String} types
* @param {Function} handler
*/
function addEventListeners(target, types, handler) {
each(splitStr(types), function (type) {
//console.debug('hammer addEventListener', type, target.tagName);
target.addEventListener(type, handler, false);
});
}
/**
* removeEventListener with multiple events at once
* @param {EventTarget} target
* @param {String} types
* @param {Function} handler
*/
function removeEventListeners(target, types, handler) {
each(splitStr(types), function (type) {
//console.debug('hammer removeEventListener', type, target.tagName);
target.removeEventListener(type, handler, false);
});
}
/**
* find if a node is in the given parent
* @method hasParent
* @param {HTMLElement} node
* @param {HTMLElement} parent
* @return {Boolean} found
*/
function hasParent(node, parent) {
while (node) {
if (node == parent) {
return true;
}
node = node.parentNode;
}
return false;
}
/**
* small indexOf wrapper
* @param {String} str
* @param {String} find
* @returns {Boolean} found
*/
function inStr(str, find) {
return str.indexOf(find) > -1;
}
/**
* split string on whitespace
* @param {String} str
* @returns {Array} words
*/
function splitStr(str) {
return str.trim().split(/\s+/g);
}
/**
* find if a array contains the object using indexOf or a simple polyFill
* @param {Array} src
* @param {String} find
* @param {String} [findByKey]
* @return {Boolean|Number} false when not found, or the index
*/
function inArray(src, find, findByKey) {
if (src.indexOf && !findByKey) {
return src.indexOf(find);
}
else {
var i = 0;
while (i < src.length) {
if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) {
return i;
}
i++;
}
return -1;
}
}
/**
* convert array-like objects to real arrays
* @param {Object} obj
* @returns {Array}
*/
function toArray(obj) {
return Array.prototype.slice.call(obj, 0);
}
/**
* unique array with objects based on a key (like 'id') or just by the array's value
* @param {Array} src [{id:1},{id:2},{id:1}]
* @param {String} [key]
* @param {Boolean} [sort=False]
* @returns {Array} [{id:1},{id:2}]
*/
function uniqueArray(src, key, sort) {
var results = [];
var values = [];
var i = 0;
while (i < src.length) {
var val = key ? src[i][key] : src[i];
if (inArray(values, val) < 0) {
results.push(src[i]);
}
values[i] = val;
i++;
}
if (sort) {
if (!key) {
results = results.sort();
}
else {
results = results.sort(function sortUniqueArray(a, b) {
return a[key] > b[key];
});
}
}
return results;
}
/**
* get the prefixed property
* @param {Object} obj
* @param {String} property
* @returns {String|Undefined} prefixed
*/
function prefixed(obj, property) {
var prefix, prop;
var camelProp = property[0].toUpperCase() + property.slice(1);
var i = 0;
while (i < VENDOR_PREFIXES.length) {
prefix = VENDOR_PREFIXES[i];
prop = (prefix) ? prefix + camelProp : property;
if (prop in obj) {
return prop;
}
i++;
}
return undefined;
}
/**
* get a unique id
* @returns {number} uniqueId
*/
var _uniqueId = 1;
function uniqueId() {
return _uniqueId++;
}
/**
* get the window object of an element
* @param {HTMLElement} element
* @returns {DocumentView|Window}
*/
function getWindowForElement(element) {
var doc = element.ownerDocument;
return (doc.defaultView || doc.parentWindow);
}
var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
var SUPPORT_TOUCH = ('ontouchstart' in window);
var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined;
var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
var INPUT_TYPE_TOUCH = 'touch';
var INPUT_TYPE_PEN = 'pen';
var INPUT_TYPE_MOUSE = 'mouse';
var INPUT_TYPE_KINECT = 'kinect';
var COMPUTE_INTERVAL = 25;
var INPUT_START = 1;
var INPUT_MOVE = 2;
var INPUT_END = 4;
var INPUT_CANCEL = 8;
var DIRECTION_NONE = 1;
var DIRECTION_LEFT = 2;
var DIRECTION_RIGHT = 4;
var DIRECTION_UP = 8;
var DIRECTION_DOWN = 16;
var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
var PROPS_XY = ['x', 'y'];
var PROPS_CLIENT_XY = ['clientX', 'clientY'];
/**
* create new input type manager
* @param {Manager} manager
* @param {Function} callback
* @returns {Input}
* @constructor
*/
function Input(manager, callback) {
var self = this;
this.manager = manager;
this.callback = callback;
this.element = manager.element;
this.target = manager.options.inputTarget;
// smaller wrapper around the handler, for the scope and the enabled state of the manager,
// so when disabled the input events are completely bypassed.
this.domHandler = function (ev) {
if (boolOrFn(manager.options.enable, [manager])) {
self.handler(ev);
}
};
this.init();
}
Input.prototype = {
/**
* should handle the inputEvent data and trigger the callback
* @virtual
*/
handler: function () { },
/**
* bind the events
*/
init: function () {
//console.debug('hammer Input init')
this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
},
/**
* unbind the events
*/
destroy: function () {
this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
}
};
/**
* create new input type manager
* called by the Manager constructor
* @param {Hammer} manager
* @returns {Input}
*/
function createInputInstance(manager) {
var Type;
var inputClass = manager.options.inputClass;
if (inputClass) {
Type = inputClass;
}
else if (SUPPORT_POINTER_EVENTS) {
Type = PointerEventInput;
}
else if (SUPPORT_ONLY_TOUCH) {
Type = TouchInput;
}
else if (!SUPPORT_TOUCH) {
Type = MouseInput;
}
else {
Type = TouchMouseInput;
}
return new (Type)(manager, inputHandler);
}
/**
* handle input events
* @param {Manager} manager
* @param {String} eventType
* @param {Object} input
*/
function inputHandler(manager, eventType, input) {
var pointersLen = input.pointers.length;
var changedPointersLen = input.changedPointers.length;
var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0));
var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0));
input.isFirst = !!isFirst;
input.isFinal = !!isFinal;
if (isFirst) {
manager.session = {};
}
// source event is the normalized value of the domEvents
// like 'touchstart, mouseup, pointerdown'
input.eventType = eventType;
// compute scale, rotation etc
computeInputData(manager, input);
// emit secret event
manager.emit('hammer.input', input);
manager.recognize(input);
manager.session.prevInput = input;
}
/**
* extend the data with some usable properties like scale, rotate, velocity etc
* @param {Object} manager
* @param {Object} input
*/
function computeInputData(manager, input) {
var session = manager.session;
var pointers = input.pointers;
var pointersLength = pointers.length;
// store the first input to calculate the distance and direction
if (!session.firstInput) {
session.firstInput = simpleCloneInputData(input);
}
// to compute scale and rotation we need to store the multiple touches
if (pointersLength > 1 && !session.firstMultiple) {
session.firstMultiple = simpleCloneInputData(input);
}
else if (pointersLength === 1) {
session.firstMultiple = false;
}
var firstInput = session.firstInput;
var firstMultiple = session.firstMultiple;
var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
var center = input.center = getCenter(pointers);
input.timeStamp = now();
input.deltaTime = input.timeStamp - firstInput.timeStamp;
input.angle = getAngle(offsetCenter, center);
input.distance = getDistance(offsetCenter, center);
computeDeltaXY(session, input);
input.offsetDirection = getDirection(input.deltaX, input.deltaY);
input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
computeIntervalInputData(session, input);
// find the correct target
var target = manager.element;
if (hasParent(input.srcEvent.target, target)) {
target = input.srcEvent.target;
}
input.target = target;
}
function computeDeltaXY(session, input) {
var center = input.center;
var offset = session.offsetDelta || {};
var prevDelta = session.prevDelta || {};
var prevInput = session.prevInput || {};
if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
prevDelta = session.prevDelta = {
x: prevInput.deltaX || 0,
y: prevInput.deltaY || 0
};
offset = session.offsetDelta = {
x: center.x,
y: center.y
};
}
input.deltaX = prevDelta.x + (center.x - offset.x);
input.deltaY = prevDelta.y + (center.y - offset.y);
}
/**
* velocity is calculated every x ms
* @param {Object} session
* @param {Object} input
*/
function computeIntervalInputData(session, input) {
var last = session.lastInterval || input, deltaTime = input.timeStamp - last.timeStamp, velocity, velocityX, velocityY, direction;
if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
var deltaX = last.deltaX - input.deltaX;
var deltaY = last.deltaY - input.deltaY;
var v = getVelocity(deltaTime, deltaX, deltaY);
velocityX = v.x;
velocityY = v.y;
velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
direction = getDirection(deltaX, deltaY);
session.lastInterval = input;
}
else {
// use latest velocity info if it doesn't overtake a minimum period
velocity = last.velocity;
velocityX = last.velocityX;
velocityY = last.velocityY;
direction = last.direction;
}
input.velocity = velocity;
input.velocityX = velocityX;
input.velocityY = velocityY;
input.direction = direction;
}
/**
* create a simple clone from the input used for storage of firstInput and firstMultiple
* @param {Object} input
* @returns {Object} clonedInputData
*/
function simpleCloneInputData(input) {
// make a simple copy of the pointers because we will get a reference if we don't
// we only need clientXY for the calculations
var pointers = [];
var i = 0;
while (i < input.pointers.length) {
pointers[i] = {
clientX: round(input.pointers[i].clientX),
clientY: round(input.pointers[i].clientY)
};
i++;
}
return {
timeStamp: now(),
pointers: pointers,
center: getCenter(pointers),
deltaX: input.deltaX,
deltaY: input.deltaY
};
}
/**
* get the center of all the pointers
* @param {Array} pointers
* @return {Object} center contains `x` and `y` properties
*/
function getCenter(pointers) {
var pointersLength = pointers.length;
// no need to loop when only one touch
if (pointersLength === 1) {
return {
x: round(pointers[0].clientX),
y: round(pointers[0].clientY)
};
}
var x = 0, y = 0, i = 0;
while (i < pointersLength) {
x += pointers[i].clientX;
y += pointers[i].clientY;
i++;
}
return {
x: round(x / pointersLength),
y: round(y / pointersLength)
};
}
/**
* calculate the velocity between two points. unit is in px per ms.
* @param {Number} deltaTime
* @param {Number} x
* @param {Number} y
* @return {Object} velocity `x` and `y`
*/
function getVelocity(deltaTime, x, y) {
return {
x: x / deltaTime || 0,
y: y / deltaTime || 0
};
}
/**
* get the direction between two points
* @param {Number} x
* @param {Number} y
* @return {Number} direction
*/
function getDirection(x, y) {
if (x === y) {
return DIRECTION_NONE;
}
if (abs(x) >= abs(y)) {
return x > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
}
return y > 0 ? DIRECTION_UP : DIRECTION_DOWN;
}
/**
* calculate the absolute distance between two points
* @param {Object} p1 {x, y}
* @param {Object} p2 {x, y}
* @param {Array} [props] containing x and y keys
* @return {Number} distance
*/
function getDistance(p1, p2, props) {
if (!props) {
props = PROPS_XY;
}
var x = p2[props[0]] - p1[props[0]], y = p2[props[1]] - p1[props[1]];
return Math.sqrt((x * x) + (y * y));
}
/**
* calculate the angle between two coordinates
* @param {Object} p1
* @param {Object} p2
* @param {Array} [props] containing x and y keys
* @return {Number} angle
*/
function getAngle(p1, p2, props) {
if (!props) {
props = PROPS_XY;
}
var x = p2[props[0]] - p1[props[0]], y = p2[props[1]] - p1[props[1]];
return Math.atan2(y, x) * 180 / Math.PI;
}
/**
* calculate the rotation degrees between two pointersets
* @param {Array} start array of pointers
* @param {Array} end array of pointers
* @return {Number} rotation
*/
function getRotation(start, end) {
return getAngle(end[1], end[0], PROPS_CLIENT_XY) - getAngle(start[1], start[0], PROPS_CLIENT_XY);
}
/**
* calculate the scale factor between two pointersets
* no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
* @param {Array} start array of pointers
* @param {Array} end array of pointers
* @return {Number} scale
*/
function getScale(start, end) {
return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
}
var MOUSE_INPUT_MAP = {
mousedown: INPUT_START,
mousemove: INPUT_MOVE,
mouseup: INPUT_END
};
var MOUSE_ELEMENT_EVENTS = 'mousedown';
var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
/**
* Mouse events input
* @constructor
* @extends Input
*/
function MouseInput() {
this.evEl = MOUSE_ELEMENT_EVENTS;
this.evWin = MOUSE_WINDOW_EVENTS;
this.allow = true; // used by Input.TouchMouse to disable mouse events
this.pressed = false; // mousedown state
Input.apply(this, arguments);
}
inherit(MouseInput, Input, {
/**
* handle mouse events
* @param {Object} ev
*/
handler: function MEhandler(ev) {
var eventType = MOUSE_INPUT_MAP[ev.type];
// on start we want to have the left mouse button down
if (eventType & INPUT_START && ev.button === 0) {
this.pressed = true;
}
if (eventType & INPUT_MOVE && ev.which !== 1) {
eventType = INPUT_END;
}
// mouse must be down, and mouse events are allowed (see the TouchMouse input)
if (!this.pressed || !this.allow) {
return;
}
if (eventType & INPUT_END) {
this.pressed = false;
}
this.callback(this.manager, eventType, {
pointers: [ev],
changedPointers: [ev],
pointerType: INPUT_TYPE_MOUSE,
srcEvent: ev
});
}
});
var POINTER_INPUT_MAP = {
pointerdown: INPUT_START,
pointermove: INPUT_MOVE,
pointerup: INPUT_END,
pointercancel: INPUT_CANCEL,
pointerout: INPUT_CANCEL
};
// in IE10 the pointer types is defined as an enum
var IE10_POINTER_TYPE_ENUM = {
2: INPUT_TYPE_TOUCH,
3: INPUT_TYPE_PEN,
4: INPUT_TYPE_MOUSE,
5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
};
var POINTER_ELEMENT_EVENTS = 'pointerdown';
var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';
// IE10 has prefixed support, and case-sensitive
if (window.MSPointerEvent) {
POINTER_ELEMENT_EVENTS = 'MSPointerDown';
POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
}
/**
* Pointer events input
* @constructor
* @extends Input
*/
function PointerEventInput() {
this.evEl = POINTER_ELEMENT_EVENTS;
this.evWin = POINTER_WINDOW_EVENTS;
Input.apply(this, arguments);
this.store = (this.manager.session.pointerEvents = []);
}
inherit(PointerEventInput, Input, {
/**
* handle mouse events
* @param {Object} ev
*/
handler: function PEhandler(ev) {
var store = this.store;
var removePointer = false;
var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
var isTouch = (pointerType == INPUT_TYPE_TOUCH);
// get index of the event in the store
var storeIndex = inArray(store, ev.pointerId, 'pointerId');
// start and mouse must be down
if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
if (storeIndex < 0) {
store.push(ev);
storeIndex = store.length - 1;
}
}
else if (eventType & (INPUT_END | INPUT_CANCEL)) {
removePointer = true;
}
// it not found, so the pointer hasn't been down (so it's probably a hover)
if (storeIndex < 0) {
return;
}
// update the event in the store
store[storeIndex] = ev;
this.callback(this.manager, eventType, {
pointers: store,
changedPointers: [ev],
pointerType: pointerType,
srcEvent: ev
});
if (removePointer) {
// remove from the store
store.splice(storeIndex, 1);
}
}
});
var SINGLE_TOUCH_INPUT_MAP = {
touchstart: INPUT_START,
touchmove: INPUT_MOVE,
touchend: INPUT_END,
touchcancel: INPUT_CANCEL
};
var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
/**
* Touch events input
* @constructor
* @extends Input
*/
function SingleTouchInput() {
this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
this.started = false;
Input.apply(this, arguments);
}
inherit(SingleTouchInput, Input, {
handler: function TEhandler(ev) {
var type = SINGLE_TOUCH_INPUT_MAP[ev.type];
// should we handle the touch events?
if (type === INPUT_START) {
this.started = true;
}
if (!this.started) {
return;
}
var touches = normalizeSingleTouches.call(this, ev, type);
// when done, reset the started state
if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
this.started = false;
}
this.callback(this.manager, type, {
pointers: touches[0],
changedPointers: touches[1],
pointerType: INPUT_TYPE_TOUCH,
srcEvent: ev
});
}
});
/**
* @this {TouchInput}
* @param {Object} ev
* @param {Number} type flag
* @returns {undefined|Array} [all, changed]
*/
function normalizeSingleTouches(ev, type) {
var all = toArray(ev.touches);
var changed = toArray(ev.changedTouches);
if (type & (INPUT_END | INPUT_CANCEL)) {
all = uniqueArray(all.concat(changed), 'identifier', true);
}
return [all, changed];
}
var TOUCH_INPUT_MAP = {
touchstart: INPUT_START,
touchmove: INPUT_MOVE,
touchend: INPUT_END,
touchcancel: INPUT_CANCEL
};
var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
/**
* Multi-user touch events input
* @constructor
* @extends Input
*/
function TouchInput() {
this.evTarget = TOUCH_TARGET_EVENTS;
this.targetIds = {};
Input.apply(this, arguments);
}
inherit(TouchInput, Input, {
handler: function MTEhandler(ev) {
var type = TOUCH_INPUT_MAP[ev.type];
var touches = getTouches.call(this, ev, type);
if (!touches) {
return;
}
this.callback(this.manager, type, {
pointers: touches[0],
changedPointers: touches[1],
pointerType: INPUT_TYPE_TOUCH,
srcEvent: ev
});
}
});
/**
* @this {TouchInput}
* @param {Object} ev
* @param {Number} type flag
* @returns {undefined|Array} [all, changed]
*/
function getTouches(ev, type) {
var allTouches = toArray(ev.touches);
var targetIds = this.targetIds;
// when there is only one touch, the process can be simplified
if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
targetIds[allTouches[0].identifier] = true;
return [allTouches, allTouches];
}
var i, targetTouches, changedTouches = toArray(ev.changedTouches), changedTargetTouches = [], target = this.target;
// get target touches from touches
targetTouches = allTouches.filter(function (touch) {
return hasParent(touch.target, target);
});
// collect touches
if (type === INPUT_START) {
i = 0;
while (i < targetTouches.length) {
targetIds[targetTouches[i].identifier] = true;
i++;
}
}
// filter changed touches to only contain touches that exist in the collected target ids
i = 0;
while (i < changedTouches.length) {
if (targetIds[changedTouches[i].identifier]) {
changedTargetTouches.push(changedTouches[i]);
}
// cleanup removed touches
if (type & (INPUT_END | INPUT_CANCEL)) {
delete targetIds[changedTouches[i].identifier];
}
i++;
}
if (!changedTargetTouches.length) {
return;
}
return [
// merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true),
changedTargetTouches
];
}
/**
* Combined touch and mouse input
*
* Touch has a higher priority then mouse, and while touching no mouse events are allowed.
* This because touch devices also emit mouse events while doing a touch.
*
* @constructor
* @extends Input
*/
function TouchMouseInput() {
Input.apply(this, arguments);
var handler = bindFn(this.handler, this);
this.touch = new TouchInput(this.manager, handler);
this.mouse = new MouseInput(this.manager, handler);
}
inherit(TouchMouseInput, Input, {
/**
* handle mouse and touch events
* @param {Hammer} manager
* @param {String} inputEvent
* @param {Object} inputData
*/
handler: function TMEhandler(manager, inputEvent, inputData) {
var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH), isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE);
// when we're in a touch event, so block all upcoming mouse events
// most mobile browser also emit mouseevents, right after touchstart
if (isTouch) {
this.mouse.allow = false;
}
else if (isMouse && !this.mouse.allow) {
return;
}
// reset the allowMouse when we're done
if (inputEvent & (INPUT_END | INPUT_CANCEL)) {
this.mouse.allow = true;
}
this.callback(manager, inputEvent, inputData);
},
/**
* remove the event listeners
*/
destroy: function destroy() {
this.touch.destroy();
this.mouse.destroy();
}
});
var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
// magical touchAction value
var TOUCH_ACTION_COMPUTE = 'compute';
var TOUCH_ACTION_AUTO = 'auto';
var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
var TOUCH_ACTION_NONE = 'none';
var TOUCH_ACTION_PAN_X = 'pan-x';
var TOUCH_ACTION_PAN_Y = 'pan-y';
/**
* Touch Action
* sets the touchAction property or uses the js alternative
* @param {Manager} manager
* @param {String} value
* @constructor
*/
function TouchAction(manager, value) {
this.manager = manager;
this.set(value);
}
TouchAction.prototype = {
/**
* set the touchAction value on the element or enable the polyfill
* @param {String} value
*/
set: function (value) {
// find out the touch-action by the event handlers
if (value == TOUCH_ACTION_COMPUTE) {
value = this.compute();
}
if (NATIVE_TOUCH_ACTION) {
this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
}
this.actions = value.toLowerCase().trim();
},
/**
* just re-set the touchAction value
*/
update: function () {
this.set(this.manager.options.touchAction);
},
/**
* compute the value for the touchAction property based on the recognizer's settings
* @returns {String} value
*/
compute: function () {
var actions = [];
each(this.manager.recognizers, function (recognizer) {
if (boolOrFn(recognizer.options.enable, [recognizer])) {
actions = actions.concat(recognizer.getTouchAction());
}
});
return cleanTouchActions(actions.join(' '));
},
/**
* this method is called on each input cycle and provides the preventing of the browser behavior
* @param {Object} input
*/
preventDefaults: function (input) {
// not needed with native support for the touchAction property
if (NATIVE_TOUCH_ACTION) {
return;
}
var srcEvent = input.srcEvent;
var direction = input.offsetDirection;
// if the touch action did prevented once this session
if (this.manager.session.prevented) {
srcEvent.preventDefault();
return;
}
var actions = this.actions;
var hasNone = inStr(actions, TOUCH_ACTION_NONE);
var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
if (hasNone ||
(hasPanY && direction & DIRECTION_HORIZONTAL) ||
(hasPanX && direction & DIRECTION_VERTICAL)) {
return this.preventSrc(srcEvent);
}
},
/**
* call preventDefault to prevent the browser's default behavior (scrolling in most cases)
* @param {Object} srcEvent
*/
preventSrc: function (srcEvent) {
this.manager.session.prevented = true;
srcEvent.preventDefault();
}
};
/**
* when the touchActions are collected they are not a valid value, so we need to clean things up. *
* @param {String} actions
* @returns {*}
*/
function cleanTouchActions(actions) {
// none
if (inStr(actions, TOUCH_ACTION_NONE)) {
return TOUCH_ACTION_NONE;
}
var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
// pan-x and pan-y can be combined
if (hasPanX && hasPanY) {
return TOUCH_ACTION_PAN_X + ' ' + TOUCH_ACTION_PAN_Y;
}
// pan-x OR pan-y
if (hasPanX || hasPanY) {
return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
}
// manipulation
if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
return TOUCH_ACTION_MANIPULATION;
}
return TOUCH_ACTION_AUTO;
}
/**
* Recognizer flow explained; *
* All recognizers have the initial state of POSSIBLE when a input session starts.
* The definition of a input session is from the first input until the last input, with all it's movement in it. *
* Example session for mouse-input: mousedown -> mousemove -> mouseup
*
* On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
* which determines with state it should be.
*
* If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
* POSSIBLE to give it another change on the next cycle.
*
* Possible
* |
* +-----+---------------+
* | |
* +-----+-----+ |
* | | |
* Failed Cancelled |
* +-------+------+
* | |
* Recognized Began
* |
* Changed
* |
* Ended/Recognized
*/
var STATE_POSSIBLE = 1;
var STATE_BEGAN = 2;
var STATE_CHANGED = 4;
var STATE_ENDED = 8;
var STATE_RECOGNIZED = STATE_ENDED;
var STATE_CANCELLED = 16;
var STATE_FAILED = 32;
/**
* Recognizer
* Every recognizer needs to extend from this class.
* @constructor
* @param {Object} options
*/
function Recognizer(options) {
this.id = uniqueId();
this.manager = null;
this.options = merge(options || {}, this.defaults);
// default is enable true
this.options.enable = ifUndefined(this.options.enable, true);
this.state = STATE_POSSIBLE;
this.simultaneous = {};
this.requireFail = [];
}
Recognizer.prototype = {
/**
* @virtual
* @type {Object}
*/
defaults: {},
/**
* set options
* @param {Object} options
* @return {Recognizer}
*/
set: function (options) {
extend(this.options, options);
// also update the touchAction, in case something changed about the directions/enabled state
this.manager && this.manager.touchAction.update();
return this;
},
/**
* recognize simultaneous with an other recognizer.
* @param {Recognizer} otherRecognizer
* @returns {Recognizer} this
*/
recognizeWith: function (otherRecognizer) {
if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
return this;
}
var simultaneous = this.simultaneous;
otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
if (!simultaneous[otherRecognizer.id]) {
simultaneous[otherRecognizer.id] = otherRecognizer;
otherRecognizer.recognizeWith(this);
}
return this;
},
/**
* drop the simultaneous link. it doesnt remove the link on the other recognizer.
* @param {Recognizer} otherRecognizer
* @returns {Recognizer} this
*/
dropRecognizeWith: function (otherRecognizer) {
if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
return this;
}
otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
delete this.simultaneous[otherRecognizer.id];
return this;
},
/**
* recognizer can only run when an other is failing
* @param {Recognizer} otherRecognizer
* @returns {Recognizer} this
*/
requireFailure: function (otherRecognizer) {
if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
return this;
}
var requireFail = this.requireFail;
otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
if (inArray(requireFail, otherRecognizer) === -1) {
requireFail.push(otherRecognizer);
otherRecognizer.requireFailure(this);
}
return this;
},
/**
* drop the requireFailure link. it does not remove the link on the other recognizer.
* @param {Recognizer} otherRecognizer
* @returns {Recognizer} this
*/
dropRequireFailure: function (otherRecognizer) {
if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
return this;
}
otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
var index = inArray(this.requireFail, otherRecognizer);
if (index > -1) {
this.requireFail.splice(index, 1);
}
return this;
},
/**
* has require failures boolean
* @returns {boolean}
*/
hasRequireFailures: function () {
return this.requireFail.length > 0;
},
/**
* if the recognizer can recognize simultaneous with an other recognizer
* @param {Recognizer} otherRecognizer
* @returns {Boolean}
*/
canRecognizeWith: function (otherRecognizer) {
return !!this.simultaneous[otherRecognizer.id];
},
/**
* You should use `tryEmit` instead of `emit` directly to check
* that all the needed recognizers has failed before emitting.
* @param {Object} input
*/
emit: function (input) {
var self = this;
var state = this.state;
function emit(withState) {
self.manager.emit(self.options.event + (withState ? stateStr(state) : ''), input);
}
// 'panstart' and 'panmove'
if (state < STATE_ENDED) {
emit(true);
}
emit(); // simple 'eventName' events
// panend and pancancel
if (state >= STATE_ENDED) {
emit(true);
}
},
/**
* Check that all the require failure recognizers has failed,
* if true, it emits a gesture event,
* otherwise, setup the state to FAILED.
* @param {Object} input
*/
tryEmit: function (input) {
if (this.canEmit()) {
return this.emit(input);
}
// it's failing anyway
this.state = STATE_FAILED;
},
/**
* can we emit?
* @returns {boolean}
*/
canEmit: function () {
var i = 0;
while (i < this.requireFail.length) {
if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
return false;
}
i++;
}
return true;
},
/**
* update the recognizer
* @param {Object} inputData
*/
recognize: function (inputData) {
// make a new copy of the inputData
// so we can change the inputData without messing up the other recognizers
var inputDataClone = extend({}, inputData);
// is is enabled and allow recognizing?
if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
this.reset();
this.state = STATE_FAILED;
return;
}
// reset when we've reached the end
if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
this.state = STATE_POSSIBLE;
}
this.state = this.process(inputDataClone);
// the recognizer has recognized a gesture
// so trigger an event
if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
this.tryEmit(inputDataClone);
}
},
/**
* return the state of the recognizer
* the actual recognizing happens in this method
* @virtual
* @param {Object} inputData
* @returns {Const} STATE
*/
process: function (inputData) { },
/**
* return the preferred touch-action
* @virtual
* @returns {Array}
*/
getTouchAction: function () { },
/**
* called when the gesture isn't allowed to recognize
* like when another is being recognized or it is disabled
* @virtual
*/
reset: function () { }
};
/**
* get a usable string, used as event postfix
* @param {Const} state
* @returns {String} state
*/
function stateStr(state) {
if (state & STATE_CANCELLED) {
return 'cancel';
}
else if (state & STATE_ENDED) {
return 'end';
}
else if (state & STATE_CHANGED) {
return 'move';
}
else if (state & STATE_BEGAN) {
return 'start';
}
return '';
}
/**
* direction cons to string
* @param {Const} direction
* @returns {String}
*/
function directionStr(direction) {
if (direction == DIRECTION_DOWN) {
return 'down';
}
else if (direction == DIRECTION_UP) {
return 'up';
}
else if (direction == DIRECTION_LEFT) {
return 'left';
}
else if (direction == DIRECTION_RIGHT) {
return 'right';
}
return '';
}
/**
* get a recognizer by name if it is bound to a manager
* @param {Recognizer|String} otherRecognizer
* @param {Recognizer} recognizer
* @returns {Recognizer}
*/
function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
var manager = recognizer.manager;
if (manager) {
return manager.get(otherRecognizer);
}
return otherRecognizer;
}
/**
* This recognizer is just used as a base for the simple attribute recognizers.
* @constructor
* @extends Recognizer
*/
function AttrRecognizer() {
Recognizer.apply(this, arguments);
}
inherit(AttrRecognizer, Recognizer, {
/**
* @namespace
* @memberof AttrRecognizer
*/
defaults: {
/**
* @type {Number}
* @default 1
*/
pointers: 1
},
/**
* Used to check if it the recognizer receives valid input, like input.distance > 10.
* @memberof AttrRecognizer
* @param {Object} input
* @returns {Boolean} recognized
*/
attrTest: function (input) {
var optionPointers = this.options.pointers;
return optionPointers === 0 || input.pointers.length === optionPointers;
},
/**
* Process the input and return the state for the recognizer
* @memberof AttrRecognizer
* @param {Object} input
* @returns {*} State
*/
process: function (input) {
var state = this.state;
var eventType = input.eventType;
var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
var isValid = this.attrTest(input);
// on cancel input and we've recognized before, return STATE_CANCELLED
if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
return state | STATE_CANCELLED;
}
else if (isRecognized || isValid) {
if (eventType & INPUT_END) {
return state | STATE_ENDED;
}
else if (!(state & STATE_BEGAN)) {
return STATE_BEGAN;
}
return state | STATE_CHANGED;
}
return STATE_FAILED;
}
});
/**
* Pan
* Recognized when the pointer is down and moved in the allowed direction.
* @constructor
* @extends AttrRecognizer
*/
function PanRecognizer() {
AttrRecognizer.apply(this, arguments);
this.pX = null;
this.pY = null;
}
inherit(PanRecognizer, AttrRecognizer, {
/**
* @namespace
* @memberof PanRecognizer
*/
defaults: {
event: 'pan',
threshold: 10,
pointers: 1,
direction: DIRECTION_ALL
},
getTouchAction: function () {
var direction = this.options.direction;
var actions = [];
if (direction & DIRECTION_HORIZONTAL) {
actions.push(TOUCH_ACTION_PAN_Y);
}
if (direction & DIRECTION_VERTICAL) {
actions.push(TOUCH_ACTION_PAN_X);
}
return actions;
},
directionTest: function (input) {
var options = this.options;
var hasMoved = true;
var distance = input.distance;
var direction = input.direction;
var x = input.deltaX;
var y = input.deltaY;
// lock to axis?
if (!(direction & options.direction)) {
if (options.direction & DIRECTION_HORIZONTAL) {
direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT;
hasMoved = x != this.pX;
distance = Math.abs(input.deltaX);
}
else {
direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN;
hasMoved = y != this.pY;
distance = Math.abs(input.deltaY);
}
}
input.direction = direction;
return hasMoved && distance > options.threshold && direction & options.direction;
},
attrTest: function (input) {
return AttrRecognizer.prototype.attrTest.call(this, input) &&
(this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input)));
},
emit: function (input) {
this.pX = input.deltaX;
this.pY = input.deltaY;
var direction = directionStr(input.direction);
if (direction) {
this.manager.emit(this.options.event + direction, input);
}
this._super.emit.call(this, input);
}
});
/**
* Pinch
* Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
* @constructor
* @extends AttrRecognizer
*/
function PinchRecognizer() {
AttrRecognizer.apply(this, arguments);
}
inherit(PinchRecognizer, AttrRecognizer, {
/**
* @namespace
* @memberof PinchRecognizer
*/
defaults: {
event: 'pinch',
threshold: 0,
pointers: 2
},
getTouchAction: function () {
return [TOUCH_ACTION_NONE];
},
attrTest: function (input) {
return this._super.attrTest.call(this, input) &&
(Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
},
emit: function (input) {
this._super.emit.call(this, input);
if (input.scale !== 1) {
var inOut = input.scale < 1 ? 'in' : 'out';
this.manager.emit(this.options.event + inOut, input);
}
}
});
/**
* Press
* Recognized when the pointer is down for x ms without any movement.
* @constructor
* @extends Recognizer
*/
function PressRecognizer() {
Recognizer.apply(this, arguments);
this._timer = null;
this._input = null;
}
inherit(PressRecognizer, Recognizer, {
/**
* @namespace
* @memberof PressRecognizer
*/
defaults: {
event: 'press',
pointers: 1,
time: 500,
threshold: 5 // a minimal movement is ok, but keep it low
},
getTouchAction: function () {
return [TOUCH_ACTION_AUTO];
},
process: function (input) {
var options = this.options;
var validPointers = input.pointers.length === options.pointers;
var validMovement = input.distance < options.threshold;
var validTime = input.deltaTime > options.time;
this._input = input;
// we only allow little movement
// and we've reached an end event, so a tap is possible
if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) {
this.reset();
}
else if (input.eventType & INPUT_START) {
this.reset();
this._timer = setTimeoutContext(function () {
this.state = STATE_RECOGNIZED;
this.tryEmit();
}, options.time, this);
}
else if (input.eventType & INPUT_END) {
return STATE_RECOGNIZED;
}
return STATE_FAILED;
},
reset: function () {
clearTimeout(this._timer);
},
emit: function (input) {
if (this.state !== STATE_RECOGNIZED) {
return;
}
if (input && (input.eventType & INPUT_END)) {
this.manager.emit(this.options.event + 'up', input);
}
else {
this._input.timeStamp = now();
this.manager.emit(this.options.event, this._input);
}
}
});
/**
* Rotate
* Recognized when two or more pointer are moving in a circular motion.
* @constructor
* @extends AttrRecognizer
*/
function RotateRecognizer() {
AttrRecognizer.apply(this, arguments);
}
inherit(RotateRecognizer, AttrRecognizer, {
/**
* @namespace
* @memberof RotateRecognizer
*/
defaults: {
event: 'rotate',
threshold: 0,
pointers: 2
},
getTouchAction: function () {
return [TOUCH_ACTION_NONE];
},
attrTest: function (input) {
return this._super.attrTest.call(this, input) &&
(Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
}
});
/**
* Swipe
* Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
* @constructor
* @extends AttrRecognizer
*/
function SwipeRecognizer() {
AttrRecognizer.apply(this, arguments);
}
inherit(SwipeRecognizer, AttrRecognizer, {
/**
* @namespace
* @memberof SwipeRecognizer
*/
defaults: {
event: 'swipe',
threshold: 10,
velocity: 0.65,
direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
pointers: 1
},
getTouchAction: function () {
return PanRecognizer.prototype.getTouchAction.call(this);
},
attrTest: function (input) {
var direction = this.options.direction;
var velocity;
if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
velocity = input.velocity;
}
else if (direction & DIRECTION_HORIZONTAL) {
velocity = input.velocityX;
}
else if (direction & DIRECTION_VERTICAL) {
velocity = input.velocityY;
}
return this._super.attrTest.call(this, input) &&
direction & input.direction &&
input.distance > this.options.threshold &&
abs(velocity) > this.options.velocity && input.eventType & INPUT_END;
},
emit: function (input) {
var direction = directionStr(input.direction);
if (direction) {
this.manager.emit(this.options.event + direction, input);
}
this.manager.emit(this.options.event, input);
}
});
/**
* A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
* between the given interval and position. The delay option can be used to recognize multi-taps without firing
* a single tap.
*
* The eventData from the emitted event contains the property `tapCount`, which contains the amount of
* multi-taps being recognized.
* @constructor
* @extends Recognizer
*/
function TapRecognizer() {
Recognizer.apply(this, arguments);
// previous time and center,
// used for tap counting
this.pTime = false;
this.pCenter = false;
this._timer = null;
this._input = null;
this.count = 0;
}
inherit(TapRecognizer, Recognizer, {
/**
* @namespace
* @memberof PinchRecognizer
*/
defaults: {
event: 'tap',
pointers: 1,
taps: 1,
interval: 300,
time: 250,
threshold: 2,
posThreshold: 10 // a multi-tap can be a bit off the initial position
},
getTouchAction: function () {
return [TOUCH_ACTION_MANIPULATION];
},
process: function (input) {
var options = this.options;
var validPointers = input.pointers.length === options.pointers;
var validMovement = input.distance < options.threshold;
var validTouchTime = input.deltaTime < options.time;
this.reset();
if ((input.eventType & INPUT_START) && (this.count === 0)) {
return this.failTimeout();
}
// we only allow little movement
// and we've reached an end event, so a tap is possible
if (validMovement && validTouchTime && validPointers) {
if (input.eventType != INPUT_END) {
return this.failTimeout();
}
var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true;
var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
this.pTime = input.timeStamp;
this.pCenter = input.center;
if (!validMultiTap || !validInterval) {
this.count = 1;
}
else {
this.count += 1;
}
this._input = input;
// if tap count matches we have recognized it,
// else it has began recognizing...
var tapCount = this.count % options.taps;
if (tapCount === 0) {
// no failing requirements, immediately trigger the tap event
// or wait as long as the multitap interval to trigger
if (!this.hasRequireFailures()) {
return STATE_RECOGNIZED;
}
else {
this._timer = setTimeoutContext(function () {
this.state = STATE_RECOGNIZED;
this.tryEmit();
}, options.interval, this);
return STATE_BEGAN;
}
}
}
return STATE_FAILED;
},
failTimeout: function () {
this._timer = setTimeoutContext(function () {
this.state = STATE_FAILED;
}, this.options.interval, this);
return STATE_FAILED;
},
reset: function () {
clearTimeout(this._timer);
},
emit: function () {
if (this.state == STATE_RECOGNIZED) {
this._input.tapCount = this.count;
this.manager.emit(this.options.event, this._input);
}
}
});
/**
* Simple way to create an manager with a default set of recognizers.
* @param {HTMLElement} element
* @param {Object} [options]
* @constructor
*/
function Hammer(element, options) {
options = options || {};
options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);
return new Manager(element, options);
}
exports.Hammer = Hammer;
/**
* @const {string}
*/
Hammer.VERSION = '2.0.4';
/**
* default settings
* @namespace
*/
Hammer.defaults = {
/**
* set if DOM events are being triggered.
* But this is slower and unused by simple implementations, so disabled by default.
* @type {Boolean}
* @default false
*/
domEvents: false,
/**
* The value for the touchAction property/fallback.
* When set to `compute` it will magically set the correct value based on the added recognizers.
* @type {String}
* @default compute
*/
touchAction: TOUCH_ACTION_COMPUTE,
/**
* @type {Boolean}
* @default true
*/
enable: true,
/**
* EXPERIMENTAL FEATURE -- can be removed/changed
* Change the parent input target element.
* If Null, then it is being set the to main element.
* @type {Null|EventTarget}
* @default null
*/
inputTarget: null,
/**
* force an input class
* @type {Null|Function}
* @default null
*/
inputClass: null,
/**
* Default recognizer setup when calling `Hammer()`
* When creating a new Manager these will be skipped.
* @type {Array}
*/
preset: [
// RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
[RotateRecognizer, { enable: false }],
[PinchRecognizer, { enable: false }, ['rotate']],
[SwipeRecognizer, { direction: DIRECTION_HORIZONTAL }],
[PanRecognizer, { direction: DIRECTION_HORIZONTAL }, ['swipe']],
[TapRecognizer],
[TapRecognizer, { event: 'doubletap', taps: 2 }, ['tap']],
[PressRecognizer]
],
/**
* Some CSS properties can be used to improve the working of Hammer.
* Add them to this method and they will be set when creating a new Manager.
* @namespace
*/
cssProps: {
/**
* Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
* @type {String}
* @default 'none'
*/
userSelect: 'none',
/**
* Disable the Windows Phone grippers when pressing an element.
* @type {String}
* @default 'none'
*/
touchSelect: 'none',
/**
* Disables the default callout shown when you touch and hold a touch target.
* On iOS, when you touch and hold a touch target such as a link, Safari displays
* a callout containing information about the link. This property allows you to disable that callout.
* @type {String}
* @default 'none'
*/
touchCallout: 'none',
/**
* Specifies whether zooming is enabled. Used by IE10>
* @type {String}
* @default 'none'
*/
contentZooming: 'none',
/**
* Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
* @type {String}
* @default 'none'
*/
userDrag: 'none',
/**
* Overrides the highlight color shown when the user taps a link or a JavaScript
* clickable element in iOS. This property obeys the alpha value, if specified.
* @type {String}
* @default 'rgba(0,0,0,0)'
*/
tapHighlightColor: 'rgba(0,0,0,0)'
}
};
var STOP = 1;
var FORCED_STOP = 2;
/**
* Manager
* @param {HTMLElement} element
* @param {Object} [options]
* @constructor
*/
function Manager(element, options) {
options = options || {};
this.options = merge(options, Hammer.defaults);
this.options.inputTarget = this.options.inputTarget || element;
this.handlers = {};
this.session = {};
this.recognizers = [];
this.element = element;
this.input = createInputInstance(this);
this.touchAction = new TouchAction(this, this.options.touchAction);
toggleCssProps(this, true);
each(options.recognizers, function (item) {
var recognizer = this.add(new (item[0])(item[1]));
item[2] && recognizer.recognizeWith(item[2]);
item[3] && recognizer.requireFailure(item[3]);
}, this);
}
Manager.prototype = {
/**
* set options
* @param {Object} options
* @returns {Manager}
*/
set: function (options) {
extend(this.options, options);
// Options that need a little more setup
if (options.touchAction) {
this.touchAction.update();
}
if (options.inputTarget) {
// Clean up existing event listeners and reinitialize
this.input.destroy();
this.input.target = options.inputTarget;
this.input.init();
}
return this;
},
/**
* stop recognizing for this session.
* This session will be discarded, when a new [input]start event is fired.
* When forced, the recognizer cycle is stopped immediately.
* @param {Boolean} [force]
*/
stop: function (force) {
this.session.stopped = force ? FORCED_STOP : STOP;
},
/**
* run the recognizers!
* called by the inputHandler function on every movement of the pointers (touches)
* it walks through all the recognizers and tries to detect the gesture that is being made
* @param {Object} inputData
*/
recognize: function (inputData) {
var session = this.session;
if (session.stopped) {
return;
}
// run the touch-action polyfill
this.touchAction.preventDefaults(inputData);
var recognizer;
var recognizers = this.recognizers;
// this holds the recognizer that is being recognized.
// so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
// if no recognizer is detecting a thing, it is set to `null`
var curRecognizer = session.curRecognizer;
// reset when the last recognizer is recognized
// or when we're in a new session
if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) {
curRecognizer = session.curRecognizer = null;
}
var i = 0;
while (i < recognizers.length) {
recognizer = recognizers[i];
// find out if we are allowed try to recognize the input for this one.
// 1. allow if the session is NOT forced stopped (see the .stop() method)
// 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
// that is being recognized.
// 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
// this can be setup with the `recognizeWith()` method on the recognizer.
if (session.stopped !== FORCED_STOP && (!curRecognizer || recognizer == curRecognizer ||
recognizer.canRecognizeWith(curRecognizer))) {
recognizer.recognize(inputData);
}
else {
recognizer.reset();
}
// if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
// current active recognizer. but only if we don't already have an active recognizer
if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
curRecognizer = session.curRecognizer = recognizer;
}
i++;
}
},
/**
* get a recognizer by its event name.
* @param {Recognizer|String} recognizer
* @returns {Recognizer|Null}
*/
get: function (recognizer) {
if (recognizer instanceof Recognizer) {
return recognizer;
}
var recognizers = this.recognizers;
for (var i = 0; i < recognizers.length; i++) {
if (recognizers[i].options.event == recognizer) {
return recognizers[i];
}
}
return null;
},
/**
* add a recognizer to the manager
* existing recognizers with the same event name will be removed
* @param {Recognizer} recognizer
* @returns {Recognizer|Manager}
*/
add: function (recognizer) {
if (invokeArrayArg(recognizer, 'add', this)) {
return this;
}
// remove existing
var existing = this.get(recognizer.options.event);
if (existing) {
this.remove(existing);
}
this.recognizers.push(recognizer);
recognizer.manager = this;
this.touchAction.update();
return recognizer;
},
/**
* remove a recognizer by name or instance
* @param {Recognizer|String} recognizer
* @returns {Manager}
*/
remove: function (recognizer) {
if (invokeArrayArg(recognizer, 'remove', this)) {
return this;
}
var recognizers = this.recognizers;
recognizer = this.get(recognizer);
recognizers.splice(inArray(recognizers, recognizer), 1);
this.touchAction.update();
return this;
},
/**
* bind event
* @param {String} events
* @param {Function} handler
* @returns {EventEmitter} this
*/
on: function (events, handler) {
var handlers = this.handlers;
each(splitStr(events), function (event) {
handlers[event] = handlers[event] || [];
handlers[event].push(handler);
});
return this;
},
/**
* unbind event, leave emit blank to remove all handlers
* @param {String} events
* @param {Function} [handler]
* @returns {EventEmitter} this
*/
off: function (events, handler) {
var handlers = this.handlers;
each(splitStr(events), function (event) {
if (!handler) {
delete handlers[event];
}
else {
handlers[event].splice(inArray(handlers[event], handler), 1);
}
});
return this;
},
/**
* emit event to the listeners
* @param {String} event
* @param {Object} data
*/
emit: function (event, data) {
// we also want to trigger dom events
if (this.options.domEvents) {
triggerDomEvent(event, data);
}
// no handlers, so skip it all
var handlers = this.handlers[event] && this.handlers[event].slice();
if (!handlers || !handlers.length) {
return;
}
data.type = event;
data.preventDefault = function () {
data.srcEvent.preventDefault();
};
var i = 0;
while (i < handlers.length) {
handlers[i](data);
i++;
}
},
/**
* destroy the manager and unbinds all events
* it doesn't unbind dom events, that is the user own responsibility
*/
destroy: function () {
this.element && toggleCssProps(this, false);
this.handlers = {};
this.session = {};
this.input.destroy();
this.element = null;
}
};
/**
* add/remove the css properties as defined in manager.options.cssProps
* @param {Manager} manager
* @param {Boolean} add
*/
function toggleCssProps(manager, add) {
var element = manager.element;
each(manager.options.cssProps, function (value, name) {
element.style[prefixed(element.style, name)] = add ? value : '';
});
}
/**
* trigger dom event
* @param {String} event
* @param {Object} data
*/
function triggerDomEvent(event, data) {
var gestureEvent = document.createEvent('Event');
gestureEvent.initEvent(event, true, true);
gestureEvent.gesture = data;
data.target.dispatchEvent(gestureEvent);
}
extend(Hammer, {
INPUT_START: INPUT_START,
INPUT_MOVE: INPUT_MOVE,
INPUT_END: INPUT_END,
INPUT_CANCEL: INPUT_CANCEL,
STATE_POSSIBLE: STATE_POSSIBLE,
STATE_BEGAN: STATE_BEGAN,
STATE_CHANGED: STATE_CHANGED,
STATE_ENDED: STATE_ENDED,
STATE_RECOGNIZED: STATE_RECOGNIZED,
STATE_CANCELLED: STATE_CANCELLED,
STATE_FAILED: STATE_FAILED,
DIRECTION_NONE: DIRECTION_NONE,
DIRECTION_LEFT: DIRECTION_LEFT,
DIRECTION_RIGHT: DIRECTION_RIGHT,
DIRECTION_UP: DIRECTION_UP,
DIRECTION_DOWN: DIRECTION_DOWN,
DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,
DIRECTION_VERTICAL: DIRECTION_VERTICAL,
DIRECTION_ALL: DIRECTION_ALL,
Manager: Manager,
Input: Input,
TouchAction: TouchAction,
TouchInput: TouchInput,
MouseInput: MouseInput,
PointerEventInput: PointerEventInput,
TouchMouseInput: TouchMouseInput,
SingleTouchInput: SingleTouchInput,
Recognizer: Recognizer,
AttrRecognizer: AttrRecognizer,
Tap: TapRecognizer,
Pan: PanRecognizer,
Swipe: SwipeRecognizer,
Pinch: PinchRecognizer,
Rotate: RotateRecognizer,
Press: PressRecognizer,
on: addEventListeners,
off: removeEventListeners,
each: each,
merge: merge,
extend: extend,
inherit: inherit,
bindFn: bindFn,
prefixed: prefixed
});
// attach to window for angular2 gesture listeners
window.Hammer = Hammer;
/***/ },
/* 31 */
/***/ function(module, exports, __webpack_require__) {
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1 = __webpack_require__(3);
var overlay_controller_1 = __webpack_require__(13);
var config_1 = __webpack_require__(8);
var animation_1 = __webpack_require__(20);
var util_1 = __webpack_require__(14);
/**
* @name Modal
* @description
* The Modal is a content pane that can go over the user's current page.
* Usually used for making a choice or editing an item. A modal can be opened
* similar to how {@link /docs/v2/api/components/nav/NavController/#push NavController.push} works,
* where it is passed a Page component, along with optional Page params,
* and options for presenting the modal.
*
* @usage
* ```ts
* class MyApp {
*
* constructor(modal: Modal) {
* this.modal = modal;
* }
*
* openContactModal() {
* this.modal.open(ContactUs);
* }
*
* openProfileModal() {
* this.modal.open(Profile, { userId: 8675309 }, {
* enterAnimation: 'my-fade-in',
* leaveAnimation: 'my-fade-out',
* handle: 'profile-modal'
* });
* }
*
* }
* ```
* @demo /docs/v2/demos/modal/
* @see {@link /docs/v2/components#modals Modal Component Docs}
*/
var Modal = (function () {
function Modal(ctrl, config) {
this.ctrl = ctrl;
this.config = config;
}
/**
* Opens a new modal using the page component is was pass as the first
* argument. This is similar to how NavController's `push` method works.
* Currently you must have `` in the `@App` component's template
* for the modal to work correctly. (This is something that will
* be hopefully be removed in the near future.)
*
* @param pageComponent The Page component to load in the modal.
* @param {Object} [params={}] Optional data which can be passed to the page
* component, which can be read from the constructor's `NavParams`.
* @param {Object} [opts={}] Additional options for this one modal instance of.
* Options include `enterAnimation` and `leaveAnimation`, which
* allows customization of which animation to use.
* @returns {Promise} Returns a promise which resolves when the modal has
* loaded and its entering animation has completed. The resolved promise's
* value is the instance of the newly created modal.
*/
Modal.prototype.open = function (pageComponent, params, opts) {
if (params === void 0) { params = {}; }
if (opts === void 0) { opts = {}; }
opts = util_1.extend({
pageType: OVERLAY_TYPE,
enterAnimation: this.config.get('modalEnter'),
leaveAnimation: this.config.get('modalLeave'),
}, opts);
return this.ctrl.open(pageComponent, params, opts);
};
/**
* Get the instance of a modal. This is usually helpful to getting ahold of a
* certain modal, from anywhere within the app, and closing it. By calling
* just `get()` without a `handle` argument, it'll return the active modal
* on top (it is possible to have multipe modals opened at the same time).
* If getting just the active modal isn't enough, when creating
* a modal, it's options can be given a `handle`, which is simply a string-based
* name for the modal instance. You can later get a reference to that modal's
* instance by calling this method with the same handle name.
* @param [handle] Optional string name given in the modal's options when it was opened.
* @returns Returns the instance of the modal if it is found, otherwise `null`.
*/
Modal.prototype.get = function (handle) {
if (handle) {
return this.ctrl.getByHandle(handle);
}
return this.ctrl.getByType(OVERLAY_TYPE);
};
Modal = __decorate([
core_1.Injectable(),
__metadata('design:paramtypes', [(typeof (_a = typeof overlay_controller_1.OverlayController !== 'undefined' && overlay_controller_1.OverlayController) === 'function' && _a) || Object, (typeof (_b = typeof config_1.Config !== 'undefined' && config_1.Config) === 'function' && _b) || Object])
], Modal);
return Modal;
var _a, _b;
})();
exports.Modal = Modal;
var OVERLAY_TYPE = 'modal';
/**
* Animations for modals
*/
var ModalSlideIn = (function (_super) {
__extends(ModalSlideIn, _super);
function ModalSlideIn(enteringView, leavingView, opts) {
_super.call(this, enteringView.pageRef(), opts);
this
.easing('cubic-bezier(0.36,0.66,0.04,1)')
.duration(400)
.fromTo('translateY', '100%', '0%')
.before.addClass('show-page');
}
return ModalSlideIn;
})(animation_1.Animation);
animation_1.Animation.register('modal-slide-in', ModalSlideIn);
var ModalSlideOut = (function (_super) {
__extends(ModalSlideOut, _super);
function ModalSlideOut(enteringView, leavingView, opts) {
_super.call(this, leavingView.pageRef(), opts);
this
.easing('ease-out')
.duration(250)
.fromTo('translateY', '0%', '100%');
}
return ModalSlideOut;
})(animation_1.Animation);
animation_1.Animation.register('modal-slide-out', ModalSlideOut);
var ModalMDSlideIn = (function (_super) {
__extends(ModalMDSlideIn, _super);
function ModalMDSlideIn(enteringView, leavingView, opts) {
_super.call(this, enteringView.pageRef(), opts);
this
.easing('cubic-bezier(0.36,0.66,0.04,1)')
.duration(280)
.fromTo('translateY', '40px', '0px')
.fadeIn()
.before.addClass('show-page');
}
return ModalMDSlideIn;
})(animation_1.Animation);
animation_1.Animation.register('modal-md-slide-in', ModalMDSlideIn);
var ModalMDSlideOut = (function (_super) {
__extends(ModalMDSlideOut, _super);
function ModalMDSlideOut(enteringView, leavingView, opts) {
_super.call(this, leavingView.pageRef(), opts);
this
.duration(200)
.easing('cubic-bezier(0.47,0,0.745,0.715)')
.fromTo('translateY', '0px', '40px')
.fadeOut();
}
return ModalMDSlideOut;
})(animation_1.Animation);
animation_1.Animation.register('modal-md-slide-out', ModalMDSlideOut);
/***/ },
/* 32 */
/***/ function(module, exports, __webpack_require__) {
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1 = __webpack_require__(3);
var common_1 = __webpack_require__(18);
var overlay_controller_1 = __webpack_require__(13);
var config_1 = __webpack_require__(8);
var animation_1 = __webpack_require__(20);
var nav_controller_1 = __webpack_require__(21);
var button_1 = __webpack_require__(33);
var util_1 = __webpack_require__(10);
/**
* @name Popup
* @description
* The Ionic Popup service allows the creation of popup windows that require the user to respond in order to continue.
*
* The popup service has support for more flexible versions of the built in `alert()`, `prompt()`, and `confirm()` functions that users are used to, in addition to allowing popups with completely custom content and look.
*
* @usage
* ```ts
* class myApp {
*
* constructor(popup: Popup) {
* this.popup = popup;
* }
*
* doAlert() {
* this.popup.alert({
* title: "New Friend!",
* template: "Your friend, Obi wan Kenobi, just accepted your friend request!",
* cssClass: 'my-alert'
* }).then(() => {
* console.log('Alert closed');
* });
* }
*
* doPrompt() {
* this.popup.prompt({
* title: "New Album",
* template: "Enter a name for this new album you're so keen on adding",
* inputPlaceholder: "Title",
* okText: "Save",
* okType: "secondary"
* }).then((name) => {
* console.log('Name entered:', name);
* }, () => {
* console.error('Prompt closed');
* });
* }
*
* doConfirm() {
* this.popup.confirm({
* title: "Use this lightsaber?",
* subTitle: "You can't exchange lightsabers",
* template: "Do you agree to use this lightsaber to do good across the intergalactic galaxy?",
* cancelText: "Disagree",
* okText: "Agree"
* }).then((result, ev) => {
* console.log('Confirmed!', result);
* }, () => {
* console.error('Not confirmed!');
* });
* }
* }
* ```
* @demo /docs/v2/demos/popup/
* @see {@link /docs/v2/components#popups Popup Component Docs}
*/
var Popup = (function () {
function Popup(ctrl, config) {
this.ctrl = ctrl;
this.config = config;
}
/**
* @private
* @param {TODO} opts TODO
* @returns {object} A promise
*/
Popup.prototype.open = function (opts) {
var _this = this;
return new Promise(function (resolve, reject) {
opts.promiseResolve = resolve;
opts.promiseReject = reject;
opts = util_1.extend({
pageType: OVERLAY_TYPE,
enterAnimation: _this.config.get('popupEnter'),
leaveAnimation: _this.config.get('popupLeave')
}, opts);
return _this.ctrl.open(PopupCmp, opts, opts);
});
};
/**
* Show a simple alert popup with a message and one button
* that the user can tap to close the popup.
* @param {object} opts The options for showing the alert, of the form:
* - `{String}` `title` The title of the popup.
* - `{String}` `cssClass` (optional). The custom CSS class name.
* - `{String}` `subTitle` (optional). The sub-title of the popup.
* - `{String}` `template` (optional). The html template to place in the popup body.
* - `{String}` `okText` (default: 'OK'). The text of the OK button.
* @returns {object} A promise which is resolved when the popup is closed.
*/
Popup.prototype.alert = function (opts) {
if (opts === void 0) { opts = {}; }
if (typeof opts === 'string') {
opts = {
title: opts
};
}
var button = {
text: opts.okText || 'OK',
type: opts.okType || '',
onTap: function (event, popupRef) {
// Allow it to close
//resolve();
}
};
opts = util_1.extend({
showPrompt: false,
cancel: function () {
//reject();
},
buttons: [
button
]
}, opts);
return this.open(opts);
};
/**
* Show a simple confirm popup with a message, Cancel and OK button.
*
* Resolves the promise with true if the user presses the OK button, and false if the user presses the Cancel button.
*
* @param {object} opts The options for showing the confirm, of the form:
* - `{String}` `title` The title of the popup.
* - `{String}` `cssClass` (optional). The custom CSS class name.
* - `{String}` `subTitle` (optional). The sub-title of the popup.
* - `{String}` `template` (optional). The html template to place in the popup body.
* - `{String}` `okText` (default: 'OK'). The text of the OK button.
* - `{String}` `cancelText` (default: 'Cancel'). The text of the OK button.
* @returns {object} A promise which is resolved when the popup is closed.
*/
Popup.prototype.confirm = function (opts) {
if (opts === void 0) { opts = {}; }
if (typeof opts === 'string') {
opts = {
title: opts
};
}
var okButton = {
text: opts.okText || 'OK',
type: opts.okType || '',
onTap: function (event, popupRef) {
// Allow it to close
}
};
var cancelButton = {
text: opts.cancelText || 'Cancel',
type: opts.cancelType || '',
isCancel: true,
onTap: function (event, popupRef) {
// Allow it to close
}
};
opts = util_1.extend({
showPrompt: false,
cancel: function () {
},
buttons: [
cancelButton, okButton
]
}, opts);
return this.open(opts);
};
/**
* Show a simple prompt popup with a message, input, Cancel and OK button.
*
* Resolves the promise with the value of the input if the user presses OK, and with undefined if the user presses Cancel.
*
* @param {object} opts The options for showing the prompt, of the form:
* - `{String}` `title` The title of the popup.
* - `{String}` `cssClass` (optional). The custom CSS class name.
* - `{String}` `subTitle` (optional). The sub-title of the popup.
* - `{String}` `template` (optional). The html template to place in the popup body.
* - `{String}` `inputType` (default: 'text'). The type of input to use.
* - `{String} `inputPlaceholder` (default: ''). A placeholder to use for the input.
* - `{String}` `okText` (default: 'OK'). The text of the OK button.
* - `{String}` `cancelText` (default: 'Cancel'). The text of the OK button.
* @returns {object} A promise which is resolved when the popup is closed.
*/
Popup.prototype.prompt = function (opts) {
if (opts === void 0) { opts = {}; }
if (typeof opts === 'string') {
opts = {
title: opts
};
}
var okButton = {
text: opts.okText || 'OK',
type: opts.okType || '',
onTap: function (event, popupRef) {
// Allow it to close
}
};
var cancelButton = {
text: opts.cancelText || 'Cancel',
type: opts.cancelType || '',
isCancel: true,
onTap: function (event, popupRef) {
// Allow it to close
}
};
opts = util_1.extend({
showPrompt: true,
promptPlaceholder: '',
cancel: function () {
},
buttons: [
cancelButton, okButton
]
}, opts);
return this.open(opts);
};
/**
* @private
* @param {TODO} handle TODO
* @returns {TODO} TODO
*/
Popup.prototype.get = function (handle) {
if (handle) {
return this.ctrl.getByHandle(handle);
}
return this.ctrl.getByType(OVERLAY_TYPE);
};
Popup = __decorate([
core_1.Injectable(),
__metadata('design:paramtypes', [(typeof (_a = typeof overlay_controller_1.OverlayController !== 'undefined' && overlay_controller_1.OverlayController) === 'function' && _a) || Object, (typeof (_b = typeof config_1.Config !== 'undefined' && config_1.Config) === 'function' && _b) || Object])
], Popup);
return Popup;
var _a, _b;
})();
exports.Popup = Popup;
var OVERLAY_TYPE = 'popup';
// TODO add button type to button: [type]="button.type"
var PopupCmp = (function () {
function PopupCmp(elementRef, params, renderer) {
this.elementRef = elementRef;
this.d = params.data;
if (this.d.cssClass) {
renderer.setElementClass(elementRef, this.d.cssClass, true);
}
}
PopupCmp.prototype.ngOnInit = function () {
var _this = this;
setTimeout(function () {
// TODO: make more better, no DOM BS
_this.promptInput = _this.elementRef.nativeElement.querySelector('input');
if (_this.promptInput) {
_this.promptInput.value = '';
}
});
};
PopupCmp.prototype.buttonTapped = function (button, ev) {
var promptValue = this.promptInput && this.promptInput.value;
var retVal = button.onTap && button.onTap(ev, this, {
promptValue: promptValue
});
// If the event.preventDefault() wasn't called, close
if (!ev.defaultPrevented) {
// If this is a cancel button, reject the promise
if (button.isCancel) {
this.d.promiseReject();
}
else {
// Resolve with the prompt value
this.d.promiseResolve(promptValue);
}
return this.close();
}
};
PopupCmp.prototype.cancel = function (ev) {
this.d.cancel && this.d.cancel(event);
if (!ev.defaultPrevented) {
this.d.promiseReject();
return this.close();
}
};
PopupCmp = __decorate([
core_1.Component({
selector: 'ion-popup',
template: '' +
'
' +
'
' +
'' +
'' +
'
' +
'
' +
'' +
'' +
'
' +
'
' +
'' +
'
' +
'
',
host: {
'role': 'dialog'
},
directives: [common_1.FORM_DIRECTIVES, common_1.NgClass, common_1.NgIf, common_1.NgFor, button_1.Button]
}),
__metadata('design:paramtypes', [(typeof (_a = typeof core_1.ElementRef !== 'undefined' && core_1.ElementRef) === 'function' && _a) || Object, (typeof (_b = typeof nav_controller_1.NavParams !== 'undefined' && nav_controller_1.NavParams) === 'function' && _b) || Object, (typeof (_c = typeof core_1.Renderer !== 'undefined' && core_1.Renderer) === 'function' && _c) || Object])
], PopupCmp);
return PopupCmp;
var _a, _b, _c;
})();
/**
* Animations for popups
*/
var PopupPopIn = (function (_super) {
__extends(PopupPopIn, _super);
function PopupPopIn(enteringView, leavingView, opts) {
_super.call(this, null, opts);
var ele = enteringView.pageRef().nativeElement;
var backdrop = new animation_1.Animation(ele.querySelector('.backdrop'));
var wrapper = new animation_1.Animation(ele.querySelector('.popup-wrapper'));
wrapper.fromTo('opacity', '0.01', '1').fromTo('scale', '1.1', '1');
backdrop.fromTo('opacity', '0.01', '0.3');
this
.easing('ease-in-out')
.duration(200)
.add(backdrop, wrapper);
}
return PopupPopIn;
})(animation_1.Animation);
animation_1.Animation.register('popup-pop-in', PopupPopIn);
var PopupPopOut = (function (_super) {
__extends(PopupPopOut, _super);
function PopupPopOut(enteringView, leavingView, opts) {
_super.call(this, null, opts);
var ele = leavingView.pageRef().nativeElement;
var backdrop = new animation_1.Animation(ele.querySelector('.backdrop'));
var wrapper = new animation_1.Animation(ele.querySelector('.popup-wrapper'));
wrapper.fromTo('opacity', '1', '0').fromTo('scale', '1', '0.9');
backdrop.fromTo('opacity', '0.3', '0');
this
.easing('ease-in-out')
.duration(200)
.add(backdrop, wrapper);
}
return PopupPopOut;
})(animation_1.Animation);
animation_1.Animation.register('popup-pop-out', PopupPopOut);
var PopupMdPopIn = (function (_super) {
__extends(PopupMdPopIn, _super);
function PopupMdPopIn(enteringView, leavingView, opts) {
_super.call(this, null, opts);
var ele = enteringView.pageRef().nativeElement;
var backdrop = new animation_1.Animation(ele.querySelector('.backdrop'));
var wrapper = new animation_1.Animation(ele.querySelector('.popup-wrapper'));
wrapper.fromTo('opacity', '0.01', '1').fromTo('scale', '1.1', '1');
backdrop.fromTo('opacity', '0.01', '0.5');
this
.easing('ease-in-out')
.duration(200)
.add(backdrop, wrapper);
}
return PopupMdPopIn;
})(animation_1.Animation);
animation_1.Animation.register('popup-md-pop-in', PopupMdPopIn);
var PopupMdPopOut = (function (_super) {
__extends(PopupMdPopOut, _super);
function PopupMdPopOut(enteringView, leavingView, opts) {
_super.call(this, null, opts);
var ele = leavingView.pageRef().nativeElement;
var backdrop = new animation_1.Animation(ele.querySelector('.backdrop'));
var wrapper = new animation_1.Animation(ele.querySelector('.popup-wrapper'));
wrapper.fromTo('opacity', '1', '0').fromTo('scale', '1', '0.9');
backdrop.fromTo('opacity', '0.5', '0');
this
.easing('ease-in-out')
.duration(200)
.add(backdrop, wrapper);
}
return PopupMdPopOut;
})(animation_1.Animation);
animation_1.Animation.register('popup-md-pop-out', PopupMdPopOut);
/***/ },
/* 33 */
/***/ function(module, exports, __webpack_require__) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1 = __webpack_require__(3);
var config_1 = __webpack_require__(8);
/**
* @name Button
* @module ionic
* @property [outline] - for an unfilled outline button
* @property [clear] - for a transparent button that only shows text and icons
* @property [round] - for a button with rounded corners
* @property [block] - for a block button that fills it's parent container
* @property [full] - for a full width button
* @property [small] - sets button size to small
* @property [large] - sets button size to large
* @property [disabled] - disables the button
* @property [fab] - for a floating action button
* @property [fab-left] - position a fab button to the left
* @property [fab-right] - position a fab button to the right
* @property [fab-center] - position a fab button towards the center
* @property [fab-top] - position a fab button towards the top
* @property [fab-bottom] - position a fab button towards the bottom
* @property [color] - Dynamically set which color attribute this button should use.
* @description
* Buttons are simple components in Ionic, can consist of text, an icon, or both, and can be enhanced with a wide range of attributes.
* @demo /docs/v2/demos/buttons/
* @see {@link /docs/v2/components#buttons Button Component Docs}
*/
var Button = (function () {
function Button(config, _elementRef, _renderer) {
this._elementRef = _elementRef;
this._renderer = _renderer;
this._role = 'button'; // bar-button/item-button
this._size = null; // large/small
this._style = 'default'; // outline/clear/solid
this._shape = null; // round/fab
this._display = null; // block/full
this._lastColor = null;
this._colors = []; // primary/secondary
this._icon = null; // left/right/only
this._disabled = false; // disabled
var element = _elementRef.nativeElement;
if (config.get('hoverCSS') === false) {
_renderer.setElementClass(_elementRef, 'disable-hover', true);
}
if (element.hasAttribute('ion-item')) {
// no need to put on these classes for an ion-item
this._role = null;
return;
}
if (element.hasAttribute('disabled')) {
this._disabled = true;
}
this._readAttrs(element);
this._readIcon(element);
}
/**
* @private
*/
Button.prototype.ngAfterContentInit = function () {
this._lastColor = this.color;
if (this.color) {
this._colors = [this.color];
}
this._assignCss(true);
};
/**
* @private
*/
Button.prototype.ngAfterContentChecked = function () {
if (this._lastColor !== this.color) {
this._assignCss(false);
this._lastColor = this.color;
this._colors = [this.color];
this._assignCss(true);
}
};
/**
* @private
*/
Button.prototype.setRole = function (val) {
this._role = val;
};
Button.prototype._readIcon = function (element) {
// figure out if and where the icon lives in the button
var childNodes = element.childNodes;
var childNode;
var nodes = [];
for (var i = 0, l = childNodes.length; i < l; i++) {
childNode = childNodes[i];
if (childNode.nodeType === 3) {
// text node
if (childNode.textContent.trim() !== '') {
nodes.push(TEXT);
}
}
else if (childNode.nodeType === 1) {
if (childNode.nodeName === 'ICON') {
// icon element node
nodes.push(ICON);
}
else {
// element other than an
nodes.push(TEXT);
}
}
}
if (nodes.length > 1) {
if (nodes[0] === ICON && nodes[1] === TEXT) {
this._icon = 'icon-left';
}
else if (nodes[0] === TEXT && nodes[1] === ICON) {
this._icon = 'icon-right';
}
}
else if (nodes.length === 1 && nodes[0] === ICON) {
this._icon = 'icon-only';
}
};
Button.prototype._readAttrs = function (element) {
var elementAttrs = element.attributes;
var attrName;
for (var i = 0, l = elementAttrs.length; i < l; i++) {
if (elementAttrs[i].value !== '')
continue;
attrName = elementAttrs[i].name;
if (BUTTON_STYLE_ATTRS.indexOf(attrName) > -1) {
this._style = attrName;
}
else if (BUTTON_DISPLAY_ATTRS.indexOf(attrName) > -1) {
this._display = attrName;
}
else if (BUTTON_SHAPE_ATTRS.indexOf(attrName) > -1) {
this._shape = attrName;
}
else if (BUTTON_SIZE_ATTRS.indexOf(attrName) > -1) {
this._size = attrName;
}
else if (!(IGNORE_ATTRS.test(attrName))) {
this._colors.push(attrName);
}
}
};
Button.prototype._assignCss = function (assignCssClass) {
var _this = this;
var role = this._role;
if (role) {
this._renderer.setElementClass(this._elementRef, role, assignCssClass); // button
this._setClass(this._style, assignCssClass); // button-clear
this._setClass(this._shape, assignCssClass); // button-round
this._setClass(this._display, assignCssClass); // button-full
this._setClass(this._size, assignCssClass); // button-small
this._setClass(this._icon, assignCssClass); // button-icon-left
var colorStyle = (this._style !== 'default' ? this._style + '-' : '');
this._colors.forEach(function (colorName) {
_this._setClass(colorStyle + colorName, assignCssClass); // button-secondary, button-clear-secondary
});
}
};
Button.prototype._setClass = function (type, assignCssClass) {
if (type) {
this._renderer.setElementClass(this._elementRef, this._role + '-' + type, assignCssClass);
}
};
/**
* @private
*/
Button.setRoles = function (contentButtonChildren, role) {
var buttons = contentButtonChildren.toArray();
buttons.forEach(function (button) {
button.setRole(role);
});
};
Button = __decorate([
core_1.Directive({
selector: 'button,[button]',
inputs: ['color']
}),
__metadata('design:paramtypes', [(typeof (_a = typeof config_1.Config !== 'undefined' && config_1.Config) === 'function' && _a) || Object, (typeof (_b = typeof core_1.ElementRef !== 'undefined' && core_1.ElementRef) === 'function' && _b) || Object, (typeof (_c = typeof core_1.Renderer !== 'undefined' && core_1.Renderer) === 'function' && _c) || Object])
], Button);
return Button;
var _a, _b, _c;
})();
exports.Button = Button;
var BUTTON_SIZE_ATTRS = ['large', 'small'];
var BUTTON_STYLE_ATTRS = ['clear', 'outline', 'solid'];
var BUTTON_SHAPE_ATTRS = ['round', 'fab'];
var BUTTON_DISPLAY_ATTRS = ['block', 'full'];
var IGNORE_ATTRS = /_ng|button|left|right/;
var TEXT = 1;
var ICON = 2;
/***/ },
/* 34 */
/***/ function(module, exports, __webpack_require__) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1 = __webpack_require__(3);
/**
* Events is a pub/sub style event system for sending and responding to application-level
* events across your app.
* @usage
* ```ts
* // first page (publish an event when a user is created)
* function createUser(user) {
* console.log('User created!')
* events.publish('user:created', user);
* }
*
* // second page (listen for the user created event)
* events.subscribe('user:created', (user) => {
* console.log('Welcome', user);
* });
*
* ```
*/
var Events = (function () {
function Events() {
this.channels = [];
}
/**
* Subscribe to an event topic. Events that get posted to that topic
* will trigger the provided handler.
*
* @param topic the topic to subscribe to
* @param handler the event handler
*/
Events.prototype.subscribe = function (topic) {
var _this = this;
var handlers = [];
for (var _i = 1; _i < arguments.length; _i++) {
handlers[_i - 1] = arguments[_i];
}
if (!this.channels[topic]) {
this.channels[topic] = [];
}
handlers.forEach(function (handler) {
_this.channels[topic].push(handler);
});
};
/**
* Unsubscribe from the given topic. Your handler will
* no longer receive events published to this topic.
*
* @param topic the topic to unsubscribe from
* @param handler the event handler
*
* @return true if a handler was removed
*/
Events.prototype.unsubscribe = function (topic, handler) {
var t = this.channels[topic];
if (!t) {
// Wasn't found, wasn't removed
return false;
}
if (!handler) {
// Remove all handlers for this topic
delete this.channels[topic];
return true;
}
// We need to find and remove a specific handler
var i = t.indexOf(handler);
if (i < 0) {
// Wasn't found, wasn't removed
return false;
}
t.splice(i, 1);
// If the channel is empty now, remove it from the channel map
if (!t.length) {
delete this.channels[topic];
}
return true;
};
/**
* Publish an event to the given topic.
*
* @param topic the topic to publish to
* @param eventData the data to send as the event
*/
Events.prototype.publish = function (topic) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
var t = this.channels[topic];
if (!t) {
return null;
}
var responses = [];
t.forEach(function (handler) {
responses.push(handler(args));
});
return responses;
};
Events = __decorate([
core_1.Injectable(),
__metadata('design:paramtypes', [])
], Events);
return Events;
})();
exports.Events = Events;
/***/ },
/* 35 */
/***/ function(module, exports) {
/**
* @private
* Map of possible pages that can be navigated to using an Ionic NavController
*/
var NavRegistry = (function () {
function NavRegistry(pages) {
if (pages === void 0) { pages = []; }
this._pages = new Map(pages.map(function (page) { return [page.name, page]; }));
}
NavRegistry.prototype.get = function (pageName) {
return this._pages.get(pageName);
};
NavRegistry.prototype.set = function (page) {
this._pages.set(page.name, page);
};
return NavRegistry;
})();
exports.NavRegistry = NavRegistry;
/***/ },
/* 36 */
/***/ function(module, exports, __webpack_require__) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1 = __webpack_require__(3);
/**
* @private
* Provide multi-language and i18n support in your app. Translate works by
* mapping full strings to language translated ones. That means that you don't need
* to provide strings for your default language, just new languages.
*
* @usage
* ```js
* Translate.translations({
* 'de': {
* 'Welcome to MyApp': 'Willkommen auf'
* }
* })
*
* Changing the default language:
*
* Translate.setLanguage('de');
* ```
*
* Usage in a template:
*
* ```js
* {{ 'Welcome to MyApp' | translate }}
* ```
*/
var Translate = (function () {
function Translate() {
this._transMap = {};
}
Translate.prototype.translations = function (lang, map) {
this._transMap[lang] = map;
};
Translate.prototype.setLanguage = function (lang) {
this._language = lang;
};
Translate.prototype.getTranslations = function (lang) {
return this._transMap[lang];
};
Translate.prototype.translate = function (key, lang) {
// If the language isn't specified and we have no overridden one, return the string passed.
if (!lang && !this._language) {
return key;
}
var setLanguage = lang || this._language;
var map = this.getTranslations(setLanguage);
if (!map) {
console.warn('I18N: No translation for key', key, 'using language', setLanguage);
return '';
}
return this._getTranslation(map, key);
};
Translate.prototype._getTranslation = function (map, key) {
return map && map[key] || '';
};
Translate = __decorate([
core_1.Injectable(),
__metadata('design:paramtypes', [])
], Translate);
return Translate;
})();
exports.Translate = Translate;
/***/ },
/* 37 */
/***/ function(module, exports) {
var FeatureDetect = (function () {
function FeatureDetect() {
}
FeatureDetect.prototype.run = function (window, document) {
this._results = {};
for (var name in featureDetects) {
this._results[name] = featureDetects[name](window, document, document.body);
}
};
FeatureDetect.prototype.has = function (featureName) {
return !!this._results[featureName];
};
FeatureDetect.add = function (name, fn) {
featureDetects[name] = fn;
};
return FeatureDetect;
})();
exports.FeatureDetect = FeatureDetect;
var featureDetects = {};
// FeatureDetect.add('sticky', function(window, document) {
// // css position sticky
// let ele = document.createElement('div');
// ele.style.cssText = 'position:-webkit-sticky;position:sticky';
// return ele.style.position.indexOf('sticky') > -1;
// });
FeatureDetect.add('hairlines', function (window, document, body) {
/**
* Hairline Shim
* Add the "hairline" CSS class name to the body tag
* if the browser supports subpixels.
*/
var canDo = false;
if (window.devicePixelRatio >= 2) {
var hairlineEle = document.createElement('div');
hairlineEle.style.border = '.5px solid transparent';
body.appendChild(hairlineEle);
if (hairlineEle.offsetHeight === 1) {
body.classList.add('hairlines');
canDo = true;
}
body.removeChild(hairlineEle);
}
return canDo;
});
/***/ },
/* 38 */
/***/ function(module, exports, __webpack_require__) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1 = __webpack_require__(3);
var app_1 = __webpack_require__(6);
var config_1 = __webpack_require__(8);
var dom_1 = __webpack_require__(11);
var activator_1 = __webpack_require__(39);
var ripple_1 = __webpack_require__(40);
/**
* @private
*/
var TapClick = (function () {
function TapClick(app, config, zone) {
var self = this;
self.app = app;
self.zone = zone;
self.lastTouch = 0;
self.disableClick = 0;
self.lastActivated = 0;
if (config.get('activator') == 'ripple') {
self.activator = new ripple_1.RippleActivator(app, config, zone);
}
else if (config.get('activator') == 'highlight') {
self.activator = new activator_1.Activator(app, config, zone);
}
self.usePolyfill = (config.get('tapPolyfill') === true);
zone.runOutsideAngular(function () {
addListener('click', self.click.bind(self), true);
addListener('touchstart', self.touchStart.bind(self));
addListener('touchend', self.touchEnd.bind(self));
addListener('touchcancel', self.pointerCancel.bind(self));
addListener('mousedown', self.mouseDown.bind(self), true);
addListener('mouseup', self.mouseUp.bind(self), true);
});
self.pointerMove = function (ev) {
if (dom_1.hasPointerMoved(POINTER_MOVE_UNTIL_CANCEL, self.startCoord, dom_1.pointerCoord(ev))) {
self.pointerCancel(ev);
}
};
}
TapClick.prototype.touchStart = function (ev) {
this.lastTouch = Date.now();
this.pointerStart(ev);
};
TapClick.prototype.touchEnd = function (ev) {
this.lastTouch = Date.now();
if (this.usePolyfill && this.startCoord && this.app.isEnabled()) {
var endCoord = dom_1.pointerCoord(ev);
if (!dom_1.hasPointerMoved(POINTER_TOLERANCE, this.startCoord, endCoord)) {
console.debug('create click from touch ' + Date.now());
// prevent native mouse click events for XX amount of time
this.disableClick = this.lastTouch + DISABLE_NATIVE_CLICK_AMOUNT;
// manually dispatch the mouse click event
var clickEvent = document.createEvent('MouseEvents');
clickEvent.initMouseEvent('click', true, true, window, 1, 0, 0, endCoord.x, endCoord.y, false, false, false, false, 0, null);
clickEvent.isIonicTap = true;
ev.target.dispatchEvent(clickEvent);
}
}
this.pointerEnd(ev);
};
TapClick.prototype.mouseDown = function (ev) {
if (this.isDisabledNativeClick()) {
console.debug('mouseDown prevent ' + ev.target.tagName + ' ' + Date.now());
// does not prevent default on purpose
// so native blur events from inputs can happen
ev.stopPropagation();
}
else if (this.lastTouch + DISABLE_NATIVE_CLICK_AMOUNT < Date.now()) {
this.pointerStart(ev);
}
};
TapClick.prototype.mouseUp = function (ev) {
if (this.isDisabledNativeClick()) {
console.debug('mouseUp prevent ' + ev.target.tagName + ' ' + Date.now());
ev.preventDefault();
ev.stopPropagation();
}
if (this.lastTouch + DISABLE_NATIVE_CLICK_AMOUNT < Date.now()) {
this.pointerEnd(ev);
}
};
TapClick.prototype.pointerStart = function (ev) {
var activatableEle = getActivatableTarget(ev.target);
if (activatableEle) {
this.startCoord = dom_1.pointerCoord(ev);
var now = Date.now();
if (this.lastActivated + 150 < now) {
this.activator && this.activator.downAction(ev, activatableEle, this.startCoord.x, this.startCoord.y);
this.lastActivated = now;
}
this.moveListeners(true);
}
else {
this.startCoord = null;
}
};
TapClick.prototype.pointerEnd = function (ev) {
this.moveListeners(false);
this.activator && this.activator.upAction();
};
TapClick.prototype.pointerCancel = function (ev) {
console.debug('pointerCancel from ' + ev.type + ' ' + Date.now());
this.activator && this.activator.clearState();
this.moveListeners(false);
};
TapClick.prototype.moveListeners = function (shouldAdd) {
removeListener(this.usePolyfill ? 'touchmove' : 'mousemove', this.pointerMove);
//this.zone.runOutsideAngular(() => {
if (shouldAdd) {
addListener(this.usePolyfill ? 'touchmove' : 'mousemove', this.pointerMove);
}
else {
}
//});
};
TapClick.prototype.click = function (ev) {
var preventReason = null;
if (!this.app.isEnabled()) {
preventReason = 'appDisabled';
}
else if (!ev.isIonicTap && this.isDisabledNativeClick()) {
preventReason = 'nativeClick';
}
if (preventReason !== null) {
console.debug('click prevent ' + preventReason + ' ' + Date.now());
ev.preventDefault();
ev.stopPropagation();
}
};
TapClick.prototype.isDisabledNativeClick = function () {
return this.disableClick > Date.now();
};
TapClick = __decorate([
core_1.Injectable(),
__metadata('design:paramtypes', [(typeof (_a = typeof app_1.IonicApp !== 'undefined' && app_1.IonicApp) === 'function' && _a) || Object, (typeof (_b = typeof config_1.Config !== 'undefined' && config_1.Config) === 'function' && _b) || Object, (typeof (_c = typeof core_1.NgZone !== 'undefined' && core_1.NgZone) === 'function' && _c) || Object])
], TapClick);
return TapClick;
var _a, _b, _c;
})();
exports.TapClick = TapClick;
function getActivatableTarget(ele) {
var targetEle = ele;
for (var x = 0; x < 4; x++) {
if (!targetEle)
break;
if (isActivatable(targetEle))
return targetEle;
targetEle = targetEle.parentElement;
}
return null;
}
/**
* @private
*/
function isActivatable(ele) {
if (ACTIVATABLE_ELEMENTS.test(ele.tagName)) {
return true;
}
var attributes = ele.attributes;
for (var i = 0, l = attributes.length; i < l; i++) {
if (ACTIVATABLE_ATTRIBUTES.test(attributes[i].name)) {
return true;
}
}
return false;
}
exports.isActivatable = isActivatable;
function addListener(type, listener, useCapture) {
document.addEventListener(type, listener, useCapture);
}
function removeListener(type, listener) {
document.removeEventListener(type, listener);
}
var ACTIVATABLE_ELEMENTS = /^(A|BUTTON)$/;
var ACTIVATABLE_ATTRIBUTES = /tappable|button/i;
var POINTER_TOLERANCE = 4;
var POINTER_MOVE_UNTIL_CANCEL = 10;
var DISABLE_NATIVE_CLICK_AMOUNT = 2500;
/***/ },
/* 39 */
/***/ function(module, exports, __webpack_require__) {
var dom_1 = __webpack_require__(11);
var Activator = (function () {
function Activator(app, config, zone) {
this.app = app;
this.zone = zone;
this.queue = [];
this.active = [];
this.clearStateDefers = 5;
this.clearAttempt = 0;
this.activatedClass = config.get('activatedClass') || 'activated';
this.x = 0;
this.y = 0;
}
Activator.prototype.downAction = function (ev, activatableEle, pointerX, pointerY, callback) {
// the user just pressed down
var self = this;
if (self.disableActivated(ev))
return false;
// remember where they pressed
self.x = pointerX;
self.y = pointerY;
// queue to have this element activated
self.queue.push(activatableEle);
function activateCss() {
var activatableEle;
for (var i = 0; i < self.queue.length; i++) {
activatableEle = self.queue[i];
if (activatableEle && activatableEle.parentNode) {
self.active.push(activatableEle);
activatableEle.classList.add(self.activatedClass);
}
}
self.queue = [];
}
this.zone.runOutsideAngular(function () {
dom_1.rafFrames(2, activateCss);
});
return true;
};
Activator.prototype.upAction = function () {
// the user was pressing down, then just let up
var self = this;
function activateUp() {
self.clearState();
}
this.zone.runOutsideAngular(function () {
dom_1.rafFrames(self.clearStateDefers, activateUp);
});
};
Activator.prototype.clearState = function () {
// all states should return to normal
var _this = this;
if (!this.app.isEnabled()) {
// the app is actively disabled, so don't bother deactivating anything.
// this makes it easier on the GPU so it doesn't have to redraw any
// buttons during a transition. This will retry in XX milliseconds.
setTimeout(function () {
_this.clearState();
}, 600);
}
else {
// not actively transitioning, good to deactivate any elements
this.deactivate();
}
};
Activator.prototype.deactivate = function () {
// remove the active class from all active elements
var self = this;
self.queue = [];
function deactivate() {
for (var i = 0; i < self.active.length; i++) {
self.active[i].classList.remove(self.activatedClass);
}
self.active = [];
}
dom_1.rafFrames(2, deactivate);
};
Activator.prototype.disableActivated = function (ev) {
if (ev.defaultPrevented)
return true;
var targetEle = ev.target;
for (var x = 0; x < 4; x++) {
if (!targetEle)
break;
if (targetEle.hasAttribute('disable-activated'))
return true;
targetEle = targetEle.parentElement;
}
return false;
};
return Activator;
})();
exports.Activator = Activator;
/***/ },
/* 40 */
/***/ function(module, exports, __webpack_require__) {
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var activator_1 = __webpack_require__(39);
var animation_1 = __webpack_require__(20);
var dom_1 = __webpack_require__(11);
var RippleActivator = (function (_super) {
__extends(RippleActivator, _super);
function RippleActivator(app, config, zone) {
_super.call(this, app, config, zone);
this.expands = {};
this.fades = {};
this.expandSpeed = null;
}
RippleActivator.prototype.downAction = function (ev, activatableEle, pointerX, pointerY) {
var _this = this;
if (_super.prototype.downAction.call(this, ev, activatableEle, pointerX, pointerY)) {
// create a new ripple element
this.expandSpeed = EXPAND_DOWN_PLAYBACK_RATE;
this.zone.runOutsideAngular(function () {
dom_1.raf(function () {
var clientRect = activatableEle.getBoundingClientRect();
dom_1.raf(function () {
_this.createRipple(activatableEle, pointerX, pointerY, clientRect);
});
});
});
}
};
RippleActivator.prototype.createRipple = function (activatableEle, pointerX, pointerY, clientRect) {
var _this = this;
var clientPointerX = (pointerX - clientRect.left);
var clientPointerY = (pointerY - clientRect.top);
var x = Math.max(Math.abs(clientRect.width - clientPointerX), clientPointerX) * 2;
var y = Math.max(Math.abs(clientRect.height - clientPointerY), clientPointerY) * 2;
var diameter = Math.max(Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)), 64);
var radius = Math.sqrt(clientRect.width + clientRect.height);
var duration = (1000 * Math.sqrt(radius / TOUCH_DOWN_ACCEL) + 0.5);
var rippleEle = document.createElement('md-ripple');
var rippleId = Date.now();
var eleStyle = rippleEle.style;
eleStyle.width = eleStyle.height = diameter + 'px';
eleStyle.marginTop = eleStyle.marginLeft = -(diameter / 2) + 'px';
eleStyle.left = clientPointerX + 'px';
eleStyle.top = clientPointerY + 'px';
activatableEle.appendChild(rippleEle);
// create the animation for the fade out, but don't start it yet
this.fades[rippleId] = new animation_1.Animation(rippleEle, { renderDelay: 0 });
this.fades[rippleId]
.fadeOut()
.duration(FADE_OUT_DURATION)
.playbackRate(1)
.onFinish(function () {
dom_1.raf(function () {
_this.fades[rippleId].dispose(true);
delete _this.fades[rippleId];
});
});
// expand the circle from the users starting point
// start slow, and when they let up, then speed up the animation
this.expands[rippleId] = new animation_1.Animation(rippleEle, { renderDelay: 0 });
this.expands[rippleId]
.fromTo('scale', '0.001', '1')
.duration(duration)
.playbackRate(this.expandSpeed)
.onFinish(function () {
_this.expands[rippleId].dispose();
delete _this.expands[rippleId];
_this.next();
})
.play();
};
RippleActivator.prototype.upAction = function () {
var _this = this;
this.deactivate();
this.expandSpeed = 1;
this.zone.runOutsideAngular(function () {
dom_1.rafFrames(4, function () {
_this.next();
});
});
};
RippleActivator.prototype.next = function () {
var now = Date.now();
var rippleId;
for (rippleId in this.expands) {
if (parseInt(rippleId, 10) + 4000 < now) {
this.expands[rippleId].dispose(true);
delete this.expands[rippleId];
}
else if (this.expands[rippleId].playbackRate() === EXPAND_DOWN_PLAYBACK_RATE) {
this.expands[rippleId].playbackRate(EXPAND_OUT_PLAYBACK_RATE);
}
}
for (rippleId in this.fades) {
if (parseInt(rippleId, 10) + 4000 < now) {
this.fades[rippleId].dispose(true);
delete this.fades[rippleId];
}
else if (!this.fades[rippleId].isPlaying) {
this.fades[rippleId].isPlaying = true;
this.fades[rippleId].play();
}
}
};
RippleActivator.prototype.clearState = function () {
this.deactivate();
this.next();
};
return RippleActivator;
})(activator_1.Activator);
exports.RippleActivator = RippleActivator;
var TOUCH_DOWN_ACCEL = 512;
var EXPAND_DOWN_PLAYBACK_RATE = 0.35;
var EXPAND_OUT_PLAYBACK_RATE = 3;
var FADE_OUT_DURATION = 700;
/***/ },
/* 41 */
/***/ function(module, exports, __webpack_require__) {
var common_1 = __webpack_require__(18);
var overlay_1 = __webpack_require__(42);
var menu_1 = __webpack_require__(43);
var menu_toggle_1 = __webpack_require__(45);
var menu_close_1 = __webpack_require__(48);
var button_1 = __webpack_require__(33);
var blur_1 = __webpack_require__(49);
var content_1 = __webpack_require__(50);
var scroll_1 = __webpack_require__(52);
var pull_to_refresh_1 = __webpack_require__(53);
var slides_1 = __webpack_require__(54);
var tabs_1 = __webpack_require__(56);
var tab_1 = __webpack_require__(59);
var list_1 = __webpack_require__(60);
var item_1 = __webpack_require__(63);
var item_sliding_1 = __webpack_require__(64);
var toolbar_1 = __webpack_require__(47);
var icon_1 = __webpack_require__(19);
var checkbox_1 = __webpack_require__(65);
var toggle_1 = __webpack_require__(66);
var text_input_1 = __webpack_require__(67);
var label_1 = __webpack_require__(68);
var segment_1 = __webpack_require__(69);
var radio_1 = __webpack_require__(70);
var searchbar_1 = __webpack_require__(71);
var nav_1 = __webpack_require__(72);
var nav_push_1 = __webpack_require__(73);
var nav_router_1 = __webpack_require__(74);
var navbar_1 = __webpack_require__(46);
var id_1 = __webpack_require__(57);
var show_hide_when_1 = __webpack_require__(75);
/**
* @name IONIC_DIRECTIVES
* @private
* @description
* The core Ionic directives as well as Angular's CORE_DIRECTIVES and
* FORM_DIRECTIVES. Automatically available in every [@Page](../Page/) template.
*
* **Angular**
* - CORE_DIRECTIVES
* - FORM_DIRECTIVES
*
* **Content**
* - OverlayNav
* - Menu
* - MenuToggle
* - MenuClose
*
* - Button
* - Blur
* - Content
* - Scroll
* - Refresher
*
* **Lists**
* - List
* - ListHeader
* - Item
* - ItemSliding
*
* **Slides**
* - Slides
* - Slide
* - SlideLazy
*
* **Tabs**
* - Tabs
* - Tab
*
* **Toolbar**
* - Toolbar
* - ToolbarTitle
* - ToolbarItem
*
* **Media**
* - Icon
*
* **Forms**
* - Searchbar
* - Segment
* - SegmentButton
* - Checkbox
* - RadioGroup
* - RadioButton
* - Toggle
* - TextInput
* - TextInputElement
* - Label
*
* **Nav**
* - Nav
* - NavbarTemplate
* - Navbar
* - NavPush
* - NavPop
* - NavRouter
* - IdRef
*
* - ShowWhen
* - HideWhen
*/
exports.IONIC_DIRECTIVES = [
// Angular
common_1.CORE_DIRECTIVES,
common_1.FORM_DIRECTIVES,
// Content
overlay_1.OverlayNav,
menu_1.Menu,
menu_toggle_1.MenuToggle,
menu_close_1.MenuClose,
button_1.Button,
blur_1.Blur,
content_1.Content,
scroll_1.Scroll,
pull_to_refresh_1.Refresher,
// Lists
list_1.List,
list_1.ListHeader,
item_1.Item,
item_sliding_1.ItemSliding,
// Slides
slides_1.Slides,
slides_1.Slide,
slides_1.SlideLazy,
// Tabs
tabs_1.Tabs,
tab_1.Tab,
// Toolbar
toolbar_1.Toolbar,
toolbar_1.ToolbarTitle,
toolbar_1.ToolbarItem,
// Media
icon_1.Icon,
// Forms
searchbar_1.Searchbar,
searchbar_1.SearchbarInput,
segment_1.Segment,
segment_1.SegmentButton,
checkbox_1.Checkbox,
radio_1.RadioGroup,
radio_1.RadioButton,
toggle_1.Toggle,
text_input_1.TextInput,
text_input_1.TextInputElement,
label_1.Label,
// Nav
nav_1.Nav,
navbar_1.NavbarTemplate,
navbar_1.Navbar,
nav_push_1.NavPush,
nav_push_1.NavPop,
nav_router_1.NavRouter,
id_1.IdRef,
show_hide_when_1.ShowWhen,
show_hide_when_1.HideWhen
];
/***/ },
/* 42 */
/***/ function(module, exports, __webpack_require__) {
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1 = __webpack_require__(3);
var app_1 = __webpack_require__(6);
var config_1 = __webpack_require__(8);
var keyboard_1 = __webpack_require__(16);
var overlay_controller_1 = __webpack_require__(13);
var nav_controller_1 = __webpack_require__(21);
/**
* @private
*/
var OverlayNav = (function (_super) {
__extends(OverlayNav, _super);
function OverlayNav(overlayCtrl, app, config, keyboard, elementRef, compiler, viewManager, zone, renderer, cd) {
_super.call(this, null, app, config, keyboard, elementRef, null, compiler, viewManager, zone, renderer, cd);
if (overlayCtrl.anchor) {
throw ('An app should only have one ');
}
this.initZIndex = 1000;
overlayCtrl.nav = this;
}
OverlayNav = __decorate([
core_1.Component({
selector: 'ion-overlay',
template: ''
}),
__metadata('design:paramtypes', [(typeof (_a = typeof overlay_controller_1.OverlayController !== 'undefined' && overlay_controller_1.OverlayController) === 'function' && _a) || Object, (typeof (_b = typeof app_1.IonicApp !== 'undefined' && app_1.IonicApp) === 'function' && _b) || Object, (typeof (_c = typeof config_1.Config !== 'undefined' && config_1.Config) === 'function' && _c) || Object, (typeof (_d = typeof keyboard_1.Keyboard !== 'undefined' && keyboard_1.Keyboard) === 'function' && _d) || Object, (typeof (_e = typeof core_1.ElementRef !== 'undefined' && core_1.ElementRef) === 'function' && _e) || Object, (typeof (_f = typeof core_1.Compiler !== 'undefined' && core_1.Compiler) === 'function' && _f) || Object, (typeof (_g = typeof core_1.AppViewManager !== 'undefined' && core_1.AppViewManager) === 'function' && _g) || Object, (typeof (_h = typeof core_1.NgZone !== 'undefined' && core_1.NgZone) === 'function' && _h) || Object, (typeof (_j = typeof core_1.Renderer !== 'undefined' && core_1.Renderer) === 'function' && _j) || Object, (typeof (_k = typeof core_1.ChangeDetectorRef !== 'undefined' && core_1.ChangeDetectorRef) === 'function' && _k) || Object])
], OverlayNav);
return OverlayNav;
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
})(nav_controller_1.NavController);
exports.OverlayNav = OverlayNav;
/***/ },
/* 43 */
/***/ function(module, exports, __webpack_require__) {
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var core_1 = __webpack_require__(3);
var ion_1 = __webpack_require__(23);
var app_1 = __webpack_require__(6);
var config_1 = __webpack_require__(8);
var platform_1 = __webpack_require__(9);
var keyboard_1 = __webpack_require__(16);
var gestures = __webpack_require__(44);
/**
* @name Menu
* @description
* _For basic Menu usage, see the [Menu section](../../../../components/#menus)
* of the Component docs._
*
* Menu is a side-menu navigation that can be dragged out or toggled to show.
*
* @usage
* In order to use Menu, you must specify a [reference](https://angular.io/docs/ts/latest/guide/user-input.html#local-variables)
* to the content element that Menu should listen on for drag events, using the `content` property:
*
* ```html
*
*
*
* ...
*
*
*
*
*
* ```
*
* By default, Menus are on the left, but this can be overriden with the `side`
* property:
* ```html
*
* ```
*
* Menus can optionally be given an `id` attribute which allows the app to
* to get ahold of menu references. If no `id` is given then the menu
* automatically receives an `id` created from the side it is on, such as
* `leftMenu` or `rightMenu`. When using more than one menu it is always
* recommended to give each menu a unique `id`. Additionally menuToggle and
* menuClose directives should be given menu id values of their respective
* menu.
*
* Menu supports two display styles: overlay, and reveal. Overlay
* is the traditional Android drawer style, and Reveal is the traditional iOS
* style. By default, Menu will adjust to the correct style for the platform,
* but this can be overriden using the `type` property:
* ```html
*
* ```
*
* To programatically interact with the menu, you first get the menu component.
*
* ```ts
* @Page({
* `
* `
* )}
* export class MyClass{
* constructor(app: IonicApp){
* this.app = app;
* this.menu;
* }
*
* // Wait until the page is ready
* ngAfterViewInit(){
* this.menu = this.app.getComponent('leftMenu');
* }
*
* // Open the menu programatically
* openMenu(){
* this.menu.open();
* }
*
* }
* ```
*
* If you want to use any of the APIs down below, make sure to grabe the menu component by it's ID
*
* @demo /docs/v2/demos/menu/
*
* @see {@link /docs/v2/components#menus Menu Component Docs}
* @see {@link /docs/v2/components#navigation Navigation Component Docs}
* @see {@link ../../nav/Nav Nav API Docs}
*
*/
var Menu = (function (_super) {
__extends(Menu, _super);
function Menu(elementRef, config, app, platform, keyboard, zone) {
_super.call(this, elementRef, config);
this.app = app;
this.platform = platform;
this.keyboard = keyboard;
this.zone = zone;
this.opening = new core_1.EventEmitter('opening');
this.isOpen = false;
this._preventTime = 0;
this.isEnabled = true;
}
/**
* @private
*/
Menu.prototype.ngOnInit = function () {
_super.prototype.ngOnInit.call(this);
var self = this;
var content = self.content;
self._cntEle = (content instanceof Node) ? content : content && content.getNativeElement && content.getNativeElement();
if (!self._cntEle) {
return console.error('Menu: must have a [content] element to listen for drag events on. Example:\n\n\n\n');
}
if (self.side !== 'left' && self.side !== 'right') {
self.side = 'left';
}
if (!self.id) {
// Auto register
self.id = self.side + 'Menu';
if (self.app.getComponent(self.id)) {
// id already exists, make sure this one is unique
self.id += (++menuIds);
}
self.app.register(self.id, self);
}
self._initGesture();
self._initType(self.type);
self._cntEle.classList.add('menu-content');
self._cntEle.classList.add('menu-content-' + self.type);
self.onContentClick = function (ev) {
if (self.isEnabled) {
ev.preventDefault();
ev.stopPropagation();
self.close();
}
};
};
/**
* @private
*/
Menu.prototype._initGesture = function () {
var _this = this;
this.zone.runOutsideAngular(function () {
switch (_this.side) {
case 'right':
_this._gesture = new gestures.RightMenuGesture(_this);
break;
case 'left':
_this._gesture = new gestures.LeftMenuGesture(_this);
break;
}
_this._targetGesture = new gestures.TargetGesture(_this);
});
};
/**
* @private
*/
Menu.prototype._initType = function (type) {
type = type && type.trim().toLowerCase();
if (!type) {
type = this.config.get('menuType');
}
this.type = type;
};
/**
* @private
*/
Menu.prototype._getType = function () {
if (!this._type) {
this._type = new menuTypes[this.type](this);
if (this.config.get('animate') === false) {
this._type.open.duration(33);
this._type.close.duration(33);
}
}
return this._type;
};
/**
* Sets the state of the Menu to open or not.
* @param {boolean} isOpen If the Menu is open or not.
* @return {Promise} returns a promise once set
*/
Menu.prototype.setOpen = function (shouldOpen) {
var _this = this;
// _isPrevented is used to prevent unwanted opening/closing after swiping open/close
// or swiping open the menu while pressing down on the menuToggle button
if (shouldOpen === this.isOpen || this._isPrevented()) {
return Promise.resolve();
}
this._before();
return this._getType().setOpen(shouldOpen).then(function () {
_this._after(shouldOpen);
});
};
/**
* @private
*/
Menu.prototype.setProgressStart = function () {
// user started swiping the menu open/close
if (this._isPrevented() || !this.isEnabled)
return;
this._before();
this._getType().setProgressStart(this.isOpen);
};
/**
* @private
*/
Menu.prototype.setProgess = function (value) {
// user actively dragging the menu
if (this.isEnabled) {
this._prevent();
this._getType().setProgess(value);
this.opening.next(value);
}
};
/**
* @private
*/
Menu.prototype.setProgressEnd = function (shouldComplete) {
var _this = this;
// user has finished dragging the menu
if (this.isEnabled) {
this._prevent();
this._getType().setProgressEnd(shouldComplete).then(function (isOpen) {
_this._after(isOpen);
});
}
};
/**
* @private
*/
Menu.prototype._before = function () {
// this places the menu into the correct location before it animates in
// this css class doesn't actually kick off any animations
if (this.isEnabled) {
this.getNativeElement().classList.add('show-menu');
this.getBackdropElement().classList.add('show-backdrop');
this._prevent();
this.keyboard.close();
}
};
/**
* @private
*/
Menu.prototype._after = function (isOpen) {
// keep opening/closing the menu disabled for a touch more yet
// only add listeners/css if it's enabled and isOpen
// and only remove listeners/css if it's not open
if ((this.isEnabled && isOpen) || !isOpen) {
this._prevent();
this.isOpen = isOpen;
this._cntEle.classList[isOpen ? 'add' : 'remove']('menu-content-open');
this._cntEle.removeEventListener('click', this.onContentClick);
if (isOpen) {
this._cntEle.addEventListener('click', this.onContentClick);
}
else {
this.getNativeElement().classList.remove('show-menu');
this.getBackdropElement().classList.remove('show-backdrop');
}
}
};
/**
* @private
*/
Menu.prototype._prevent = function () {
// used to prevent unwanted opening/closing after swiping open/close
// or swiping open the menu while pressing down on the menuToggle
this._preventTime = Date.now() + 20;
};
/**
* @private
*/
Menu.prototype._isPrevented = function () {
return this._preventTime > Date.now();
};
/**
* Progamatically open the Menu
* @return {Promise} returns a promise when the menu is fully opened
*/
Menu.prototype.open = function () {
return this.setOpen(true);
};
/**
* Progamatically close the Menu
* @return {Promise} returns a promise when the menu is fully closed
*/
Menu.prototype.close = function () {
return this.setOpen(false);
};
/**
* Toggle the menu. If it's closed, it will open, and if opened, it will close
* @return {Promise} returns a promise when the menu has been toggled
*/
Menu.prototype.toggle = function () {
return this.setOpen(!this.isOpen);
};
/**
* Used to enable or disable a menu. For example, there could be multiple
* left menus, but only one of them should be able to be dragged open.
* @param {boolean} shouldEnable True if it should be enabled, false if not.
* @return {Menu} Returns the instance of the menu, which is useful for chaining.
*/
Menu.prototype.enable = function (shouldEnable) {
this.isEnabled = shouldEnable;
if (!shouldEnable) {
this.close();
}
return this;
};
/**
* @private
*/
Menu.prototype.getMenuElement = function () {
return this.getNativeElement();
};
/**
* @private
*/
Menu.prototype.getContentElement = function () {
return this._cntEle;
};
/**
* @private
*/
Menu.prototype.getBackdropElement = function () {
return this.backdrop.elementRef.nativeElement;
};
/**
* @private
*/
Menu.register = function (name, cls) {
menuTypes[name] = cls;
};
/**
* @private
*/
Menu.prototype.ngOnDestroy = function () {
this.app.unregister(this.id);
this._gesture && this._gesture.destroy();
this._targetGesture && this._targetGesture.destroy();
this._type && this._type.ngOnDestroy();
this._cntEle = null;
};
Menu.getById = function (app, menuId) {
var menu = null;
if (menuId) {
menu = app.getComponent(menuId);
if (!menu) {
console.error('Menu with id "' + menuId + '" cannot be found for menuToggle');
return;
}
}
else {
menu = app.getComponent('leftMenu');
if (!menu) {
menu = app.getComponent('rightMenu');
}
if (!menu) {
console.error('Menu with id "leftMenu" or "rightMenu" cannot be found for menuToggle');
return;
}
}
return menu;
};
Menu = __decorate([
core_1.Component({
selector: 'ion-menu',
inputs: [
'content',
'id',
'side',
'type'
],
defaultInputs: {
'side': 'left',
'menuType': 'reveal'
},
outputs: ['opening'],
host: {
'role': 'navigation',
'[attr.side]': 'side',
'[attr.type]': 'type'
},
template: '',
directives: [core_1.forwardRef(function () { return MenuBackdrop; })]
}),
__metadata('design:paramtypes', [(typeof (_a = typeof core_1.ElementRef !== 'undefined' && core_1.ElementRef) === 'function' && _a) || Object, (typeof (_b = typeof config_1.Config !== 'undefined' && config_1.Config) === 'function' && _b) || Object, (typeof (_c = typeof app_1.IonicApp !== 'undefined' && app_1.IonicApp) === 'function' && _c) || Object, (typeof (_d = typeof platform_1.Platform !== 'undefined' && platform_1.Platform) === 'function' && _d) || Object, (typeof (_e = typeof keyboard_1.Keyboard !== 'undefined' && keyboard_1.Keyboard) === 'function' && _e) || Object, (typeof (_f = typeof core_1.NgZone !== 'undefined' && core_1.NgZone) === 'function' && _f) || Object])
], Menu);
return Menu;
var _a, _b, _c, _d, _e, _f;
})(ion_1.Ion);
exports.Menu = Menu;
var menuTypes = {};
var menuIds = 0;
var MenuBackdrop = (function () {
function MenuBackdrop(menu, elementRef) {
this.menu = menu;
this.elementRef = elementRef;
menu.backdrop = this;
}
/**
* @private
*/
MenuBackdrop.prototype.clicked = function (ev) {
console.debug('backdrop clicked');
ev.preventDefault();
ev.stopPropagation();
this.menu.close();
};
MenuBackdrop = __decorate([
core_1.Directive({
selector: '.backdrop',
host: {
'(click)': 'clicked($event)'
}
}),
__param(0, core_1.Host()),
__metadata('design:paramtypes', [Menu, (typeof (_a = typeof core_1.ElementRef !== 'undefined' && core_1.ElementRef) === 'function' && _a) || Object])
], MenuBackdrop);
return MenuBackdrop;
var _a;
})();
/***/ },
/* 44 */
/***/ function(module, exports, __webpack_require__) {
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var slide_edge_gesture_1 = __webpack_require__(26);
var util = __webpack_require__(14);
var MenuContentGesture = (function (_super) {
__extends(MenuContentGesture, _super);
function MenuContentGesture(menu, targetEl, options) {
if (options === void 0) { options = {}; }
_super.call(this, targetEl, util.extend({
direction: (menu.side === 'left' || menu.side === 'right') ? 'x' : 'y',
edge: menu.side,
threshold: 75
}, options));
this.menu = menu;
this.listen();
}
MenuContentGesture.prototype.canStart = function (ev) {
return this.menu.isOpen && this.menu.isEnabled ? true : _super.prototype.canStart.call(this, ev);
};
// Set CSS, then wait one frame for it to apply before sliding starts
MenuContentGesture.prototype.onSlideBeforeStart = function (slide, ev) {
this.menu.setProgressStart();
};
MenuContentGesture.prototype.onSlide = function (slide, ev) {
this.menu.setProgess(slide.distance / slide.max);
};
MenuContentGesture.prototype.onSlideEnd = function (slide, ev) {
var shouldComplete = (Math.abs(ev.velocityX) > 0.2 || Math.abs(slide.delta) > Math.abs(slide.max) * 0.5);
this.menu.setProgressEnd(shouldComplete);
};
MenuContentGesture.prototype.getElementStartPos = function (slide, ev) {
return this.menu.isOpen ? slide.max : slide.min;
};
MenuContentGesture.prototype.getSlideBoundaries = function () {
return {
min: 0,
max: this.menu.width()
};
};
return MenuContentGesture;
})(slide_edge_gesture_1.SlideEdgeGesture);
exports.MenuContentGesture = MenuContentGesture;
/**
* Support dragging the target menu as well as the content.
*/
var TargetGesture = (function (_super) {
__extends(TargetGesture, _super);
function TargetGesture(menu) {
_super.call(this, menu, menu.getNativeElement(), {
threshold: 0
});
}
return TargetGesture;
})(MenuContentGesture);
exports.TargetGesture = TargetGesture;
var LeftMenuGesture = (function (_super) {
__extends(LeftMenuGesture, _super);
function LeftMenuGesture(menu) {
_super.call(this, menu, menu.getContentElement());
}
return LeftMenuGesture;
})(MenuContentGesture);
exports.LeftMenuGesture = LeftMenuGesture;
var RightMenuGesture = (function (_super) {
__extends(RightMenuGesture, _super);
function RightMenuGesture(menu) {
_super.call(this, menu, menu.getContentElement());
}
RightMenuGesture.prototype.onSlide = function (slide, ev) {
this.menu.setProgess(slide.distance / slide.min);
};
RightMenuGesture.prototype.getElementStartPos = function (slide, ev) {
return this.menu.isOpen ? slide.min : slide.max;
};
RightMenuGesture.prototype.getSlideBoundaries = function () {
return {
min: -this.menu.width(),
max: 0
};
};
return RightMenuGesture;
})(MenuContentGesture);
exports.RightMenuGesture = RightMenuGesture;
/***/ },
/* 45 */
/***/ function(module, exports, __webpack_require__) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var core_1 = __webpack_require__(3);
var app_1 = __webpack_require__(6);
var view_controller_1 = __webpack_require__(24);
var navbar_1 = __webpack_require__(46);
var menu_1 = __webpack_require__(43);
/**
* @name MenuToggle
* @description
* Toggle a menu by placing this directive on any item.
* Note that the menu's id must be either `leftMenu` or `rightMenu`
*
* @usage
* ```html
*
*
Page 1
*
*
*
* ```
* @demo /docs/v2/demos/menu/
* @see {@link /docs/v2/components#menus Menu Component Docs}
* @see {@link ../../menu/Menu Menu API Docs}
*/
var MenuToggle = (function () {
function MenuToggle(app, elementRef, viewCtrl, navbar) {
this.app = app;
this.viewCtrl = viewCtrl;
this.withinNavbar = !!navbar;
// Deprecation warning
if (this.withinNavbar && elementRef.nativeElement.tagName === 'A') {
console.warn('Menu toggles within a navbar should use