UNPKG

ionic-angular

Version:

[![Circle CI](https://circleci.com/gh/driftyco/ionic.svg?style=svg)](https://circleci.com/gh/driftyco/ionic)

671 lines (574 loc) 20.9 kB
/** * @ngdoc provider * @name $ionicConfigProvider * @module ionic * @description * Ionic automatically takes platform configurations into account to adjust things like what * transition style to use and whether tab icons should show on the top or bottom. For example, * iOS will move forward by transitioning the entering view from right to center and the leaving * view from center to left. However, Android will transition with the entering view going from * bottom to center, covering the previous view, which remains stationary. It should be noted * that when a platform is not iOS or Android, then it'll default to iOS. So if you are * developing on a desktop browser, it's going to take on iOS default configs. * * These configs can be changed using the `$ionicConfigProvider` during the configuration phase * of your app. Additionally, `$ionicConfig` can also set and get config values during the run * phase and within the app itself. * * By default, all base config variables are set to `'platform'`, which means it'll take on the * default config of the platform on which it's running. Config variables can be set at this * level so all platforms follow the same setting, rather than its platform config. * The following code would set the same config variable for all platforms: * * ```js * $ionicConfigProvider.views.maxCache(10); * ``` * * Additionally, each platform can have it's own config within the `$ionicConfigProvider.platform` * property. The config below would only apply to Android devices. * * ```js * $ionicConfigProvider.platform.android.views.maxCache(5); * ``` * * @usage * ```js * var myApp = angular.module('reallyCoolApp', ['ionic']); * * myApp.config(function($ionicConfigProvider) { * $ionicConfigProvider.views.maxCache(5); * * // note that you can also chain configs * $ionicConfigProvider.backButton.text('Go Back').icon('ion-chevron-left'); * }); * ``` */ /** * @ngdoc method * @name $ionicConfigProvider#views.transition * @description Animation style when transitioning between views. Default `platform`. * * @param {string} transition Which style of view transitioning to use. * * * `platform`: Dynamically choose the correct transition style depending on the platform * the app is running from. If the platform is not `ios` or `android` then it will default * to `ios`. * * `ios`: iOS style transition. * * `android`: Android style transition. * * `none`: Do not perform animated transitions. * * @returns {string} value */ /** * @ngdoc method * @name $ionicConfigProvider#views.maxCache * @description Maximum number of view elements to cache in the DOM. When the max number is * exceeded, the view with the longest time period since it was accessed is removed. Views that * stay in the DOM cache the view's scope, current state, and scroll position. The scope is * disconnected from the `$watch` cycle when it is cached and reconnected when it enters again. * When the maximum cache is `0`, the leaving view's element will be removed from the DOM after * each view transition, and the next time the same view is shown, it will have to re-compile, * attach to the DOM, and link the element again. This disables caching, in effect. * @param {number} maxNumber Maximum number of views to retain. Default `10`. * @returns {number} How many views Ionic will hold onto until the a view is removed. */ /** * @ngdoc method * @name $ionicConfigProvider#views.forwardCache * @description By default, when navigating, views that were recently visited are cached, and * the same instance data and DOM elements are referenced when navigating back. However, when * navigating back in the history, the "forward" views are removed from the cache. If you * navigate forward to the same view again, it'll create a new DOM element and controller * instance. Basically, any forward views are reset each time. Set this config to `true` to have * forward views cached and not reset on each load. * @param {boolean} value * @returns {boolean} */ /** * @ngdoc method * @name $ionicConfigProvider#views.swipeBackEnabled * @description By default on iOS devices, swipe to go back functionality is enabled by default. * This method can be used to disable it globally, or on a per-view basis. * Note: This functionality is only supported on iOS. * @param {boolean} value * @returns {boolean} */ /** * @ngdoc method * @name $ionicConfigProvider#scrolling.jsScrolling * @description Whether to use JS or Native scrolling. Defaults to native scrolling. Setting this to * `true` has the same effect as setting each `ion-content` to have `overflow-scroll='false'`. * @param {boolean} value Defaults to `false` as of Ionic 1.2 * @returns {boolean} */ /** * @ngdoc method * @name $ionicConfigProvider#backButton.icon * @description Back button icon. * @param {string} value * @returns {string} */ /** * @ngdoc method * @name $ionicConfigProvider#backButton.text * @description Back button text. * @param {string} value Defaults to `Back`. * @returns {string} */ /** * @ngdoc method * @name $ionicConfigProvider#backButton.previousTitleText * @description If the previous title text should become the back button text. This * is the default for iOS. * @param {boolean} value * @returns {boolean} */ /** * @ngdoc method * @name $ionicConfigProvider#form.checkbox * @description Checkbox style. Android defaults to `square` and iOS defaults to `circle`. * @param {string} value * @returns {string} */ /** * @ngdoc method * @name $ionicConfigProvider#form.toggle * @description Toggle item style. Android defaults to `small` and iOS defaults to `large`. * @param {string} value * @returns {string} */ /** * @ngdoc method * @name $ionicConfigProvider#spinner.icon * @description Default spinner icon to use. * @param {string} value Can be: `android`, `ios`, `ios-small`, `bubbles`, `circles`, `crescent`, * `dots`, `lines`, `ripple`, or `spiral`. * @returns {string} */ /** * @ngdoc method * @name $ionicConfigProvider#tabs.style * @description Tab style. Android defaults to `striped` and iOS defaults to `standard`. * @param {string} value Available values include `striped` and `standard`. * @returns {string} */ /** * @ngdoc method * @name $ionicConfigProvider#tabs.position * @description Tab position. Android defaults to `top` and iOS defaults to `bottom`. * @param {string} value Available values include `top` and `bottom`. * @returns {string} */ /** * @ngdoc method * @name $ionicConfigProvider#templates.maxPrefetch * @description Sets the maximum number of templates to prefetch from the templateUrls defined in * $stateProvider.state. If set to `0`, the user will have to wait * for a template to be fetched the first time when navigating to a new page. Default `30`. * @param {integer} value Max number of template to prefetch from the templateUrls defined in * `$stateProvider.state()`. * @returns {integer} */ /** * @ngdoc method * @name $ionicConfigProvider#navBar.alignTitle * @description Which side of the navBar to align the title. Default `center`. * * @param {string} value side of the navBar to align the title. * * * `platform`: Dynamically choose the correct title style depending on the platform * the app is running from. If the platform is `ios`, it will default to `center`. * If the platform is `android`, it will default to `left`. If the platform is not * `ios` or `android`, it will default to `center`. * * * `left`: Left align the title in the navBar * * `center`: Center align the title in the navBar * * `right`: Right align the title in the navBar. * * @returns {string} value */ /** * @ngdoc method * @name $ionicConfigProvider#navBar.positionPrimaryButtons * @description Which side of the navBar to align the primary navBar buttons. Default `left`. * * @param {string} value side of the navBar to align the primary navBar buttons. * * * `platform`: Dynamically choose the correct title style depending on the platform * the app is running from. If the platform is `ios`, it will default to `left`. * If the platform is `android`, it will default to `right`. If the platform is not * `ios` or `android`, it will default to `left`. * * * `left`: Left align the primary navBar buttons in the navBar * * `right`: Right align the primary navBar buttons in the navBar. * * @returns {string} value */ /** * @ngdoc method * @name $ionicConfigProvider#navBar.positionSecondaryButtons * @description Which side of the navBar to align the secondary navBar buttons. Default `right`. * * @param {string} value side of the navBar to align the secondary navBar buttons. * * * `platform`: Dynamically choose the correct title style depending on the platform * the app is running from. If the platform is `ios`, it will default to `right`. * If the platform is `android`, it will default to `right`. If the platform is not * `ios` or `android`, it will default to `right`. * * * `left`: Left align the secondary navBar buttons in the navBar * * `right`: Right align the secondary navBar buttons in the navBar. * * @returns {string} value */ IonicModule .provider('$ionicConfig', function() { var provider = this; provider.platform = {}; var PLATFORM = 'platform'; var configProperties = { views: { maxCache: PLATFORM, forwardCache: PLATFORM, transition: PLATFORM, swipeBackEnabled: PLATFORM, swipeBackHitWidth: PLATFORM }, navBar: { alignTitle: PLATFORM, positionPrimaryButtons: PLATFORM, positionSecondaryButtons: PLATFORM, transition: PLATFORM }, backButton: { icon: PLATFORM, text: PLATFORM, previousTitleText: PLATFORM }, form: { checkbox: PLATFORM, toggle: PLATFORM }, scrolling: { jsScrolling: PLATFORM }, spinner: { icon: PLATFORM }, tabs: { style: PLATFORM, position: PLATFORM }, templates: { maxPrefetch: PLATFORM }, platform: {} }; createConfig(configProperties, provider, ''); // Default // ------------------------- setPlatformConfig('default', { views: { maxCache: 10, forwardCache: false, transition: 'ios', swipeBackEnabled: true, swipeBackHitWidth: 45 }, navBar: { alignTitle: 'center', positionPrimaryButtons: 'left', positionSecondaryButtons: 'right', transition: 'view' }, backButton: { icon: 'ion-ios-arrow-back', text: 'Back', previousTitleText: true }, form: { checkbox: 'circle', toggle: 'large' }, scrolling: { jsScrolling: true }, spinner: { icon: 'ios' }, tabs: { style: 'standard', position: 'bottom' }, templates: { maxPrefetch: 30 } }); // iOS (it is the default already) // ------------------------- setPlatformConfig('ios', {}); // Android // ------------------------- setPlatformConfig('android', { views: { transition: 'android', swipeBackEnabled: false }, navBar: { alignTitle: 'left', positionPrimaryButtons: 'right', positionSecondaryButtons: 'right' }, backButton: { icon: 'ion-android-arrow-back', text: false, previousTitleText: false }, form: { checkbox: 'square', toggle: 'small' }, spinner: { icon: 'android' }, tabs: { style: 'striped', position: 'top' }, scrolling: { jsScrolling: false } }); // Windows Phone // ------------------------- setPlatformConfig('windowsphone', { //scrolling: { // jsScrolling: false //} spinner: { icon: 'android' } }); provider.transitions = { views: {}, navBar: {} }; // iOS Transitions // ----------------------- provider.transitions.views.ios = function(enteringEle, leavingEle, direction, shouldAnimate) { function setStyles(ele, opacity, x, boxShadowOpacity) { var css = {}; css[ionic.CSS.TRANSITION_DURATION] = d.shouldAnimate ? '' : 0; css.opacity = opacity; if (boxShadowOpacity > -1) { css.boxShadow = '0 0 10px rgba(0,0,0,' + (d.shouldAnimate ? boxShadowOpacity * 0.45 : 0.3) + ')'; } css[ionic.CSS.TRANSFORM] = 'translate3d(' + x + '%,0,0)'; ionic.DomUtil.cachedStyles(ele, css); } var d = { run: function(step) { if (direction == 'forward') { setStyles(enteringEle, 1, (1 - step) * 99, 1 - step); // starting at 98% prevents a flicker setStyles(leavingEle, (1 - 0.1 * step), step * -33, -1); } else if (direction == 'back') { setStyles(enteringEle, (1 - 0.1 * (1 - step)), (1 - step) * -33, -1); setStyles(leavingEle, 1, step * 100, 1 - step); } else { // swap, enter, exit setStyles(enteringEle, 1, 0, -1); setStyles(leavingEle, 0, 0, -1); } }, shouldAnimate: shouldAnimate && (direction == 'forward' || direction == 'back') }; return d; }; provider.transitions.navBar.ios = function(enteringHeaderBar, leavingHeaderBar, direction, shouldAnimate) { function setStyles(ctrl, opacity, titleX, backTextX) { var css = {}; css[ionic.CSS.TRANSITION_DURATION] = d.shouldAnimate ? '' : '0ms'; css.opacity = opacity === 1 ? '' : opacity; ctrl.setCss('buttons-left', css); ctrl.setCss('buttons-right', css); ctrl.setCss('back-button', css); css[ionic.CSS.TRANSFORM] = 'translate3d(' + backTextX + 'px,0,0)'; ctrl.setCss('back-text', css); css[ionic.CSS.TRANSFORM] = 'translate3d(' + titleX + 'px,0,0)'; ctrl.setCss('title', css); } function enter(ctrlA, ctrlB, step) { if (!ctrlA || !ctrlB) return; var titleX = (ctrlA.titleTextX() + ctrlA.titleWidth()) * (1 - step); var backTextX = (ctrlB && (ctrlB.titleTextX() - ctrlA.backButtonTextLeft()) * (1 - step)) || 0; setStyles(ctrlA, step, titleX, backTextX); } function leave(ctrlA, ctrlB, step) { if (!ctrlA || !ctrlB) return; var titleX = (-(ctrlA.titleTextX() - ctrlB.backButtonTextLeft()) - (ctrlA.titleLeftRight())) * step; setStyles(ctrlA, 1 - step, titleX, 0); } var d = { run: function(step) { var enteringHeaderCtrl = enteringHeaderBar.controller(); var leavingHeaderCtrl = leavingHeaderBar && leavingHeaderBar.controller(); if (d.direction == 'back') { leave(enteringHeaderCtrl, leavingHeaderCtrl, 1 - step); enter(leavingHeaderCtrl, enteringHeaderCtrl, 1 - step); } else { enter(enteringHeaderCtrl, leavingHeaderCtrl, step); leave(leavingHeaderCtrl, enteringHeaderCtrl, step); } }, direction: direction, shouldAnimate: shouldAnimate && (direction == 'forward' || direction == 'back') }; return d; }; // Android Transitions // ----------------------- provider.transitions.views.android = function(enteringEle, leavingEle, direction, shouldAnimate) { shouldAnimate = shouldAnimate && (direction == 'forward' || direction == 'back'); function setStyles(ele, x, opacity) { var css = {}; css[ionic.CSS.TRANSITION_DURATION] = d.shouldAnimate ? '' : 0; css[ionic.CSS.TRANSFORM] = 'translate3d(' + x + '%,0,0)'; css.opacity = opacity; ionic.DomUtil.cachedStyles(ele, css); } var d = { run: function(step) { if (direction == 'forward') { setStyles(enteringEle, (1 - step) * 99, 1); // starting at 98% prevents a flicker setStyles(leavingEle, step * -100, 1); } else if (direction == 'back') { setStyles(enteringEle, (1 - step) * -100, 1); setStyles(leavingEle, step * 100, 1); } else { // swap, enter, exit setStyles(enteringEle, 0, 1); setStyles(leavingEle, 0, 0); } }, shouldAnimate: shouldAnimate }; return d; }; provider.transitions.navBar.android = function(enteringHeaderBar, leavingHeaderBar, direction, shouldAnimate) { function setStyles(ctrl, opacity) { if (!ctrl) return; var css = {}; css.opacity = opacity === 1 ? '' : opacity; ctrl.setCss('buttons-left', css); ctrl.setCss('buttons-right', css); ctrl.setCss('back-button', css); ctrl.setCss('back-text', css); ctrl.setCss('title', css); } return { run: function(step) { setStyles(enteringHeaderBar.controller(), step); setStyles(leavingHeaderBar && leavingHeaderBar.controller(), 1 - step); }, shouldAnimate: shouldAnimate && (direction == 'forward' || direction == 'back') }; }; // No Transition // ----------------------- provider.transitions.views.none = function(enteringEle, leavingEle) { return { run: function(step) { provider.transitions.views.android(enteringEle, leavingEle, false, false).run(step); }, shouldAnimate: false }; }; provider.transitions.navBar.none = function(enteringHeaderBar, leavingHeaderBar) { return { run: function(step) { provider.transitions.navBar.ios(enteringHeaderBar, leavingHeaderBar, false, false).run(step); provider.transitions.navBar.android(enteringHeaderBar, leavingHeaderBar, false, false).run(step); }, shouldAnimate: false }; }; // private: used to set platform configs function setPlatformConfig(platformName, platformConfigs) { configProperties.platform[platformName] = platformConfigs; provider.platform[platformName] = {}; addConfig(configProperties, configProperties.platform[platformName]); createConfig(configProperties.platform[platformName], provider.platform[platformName], ''); } // private: used to recursively add new platform configs function addConfig(configObj, platformObj) { for (var n in configObj) { if (n != PLATFORM && configObj.hasOwnProperty(n)) { if (angular.isObject(configObj[n])) { if (!isDefined(platformObj[n])) { platformObj[n] = {}; } addConfig(configObj[n], platformObj[n]); } else if (!isDefined(platformObj[n])) { platformObj[n] = null; } } } } // private: create methods for each config to get/set function createConfig(configObj, providerObj, platformPath) { forEach(configObj, function(value, namespace) { if (angular.isObject(configObj[namespace])) { // recursively drill down the config object so we can create a method for each one providerObj[namespace] = {}; createConfig(configObj[namespace], providerObj[namespace], platformPath + '.' + namespace); } else { // create a method for the provider/config methods that will be exposed providerObj[namespace] = function(newValue) { if (arguments.length) { configObj[namespace] = newValue; return providerObj; } if (configObj[namespace] == PLATFORM) { // if the config is set to 'platform', then get this config's platform value var platformConfig = stringObj(configProperties.platform, ionic.Platform.platform() + platformPath + '.' + namespace); if (platformConfig || platformConfig === false) { return platformConfig; } // didnt find a specific platform config, now try the default return stringObj(configProperties.platform, 'default' + platformPath + '.' + namespace); } return configObj[namespace]; }; } }); } function stringObj(obj, str) { str = str.split("."); for (var i = 0; i < str.length; i++) { if (obj && isDefined(obj[str[i]])) { obj = obj[str[i]]; } else { return null; } } return obj; } provider.setPlatformConfig = setPlatformConfig; // private: Service definition for internal Ionic use /** * @ngdoc service * @name $ionicConfig * @module ionic * @private */ provider.$get = function() { return provider; }; }) // Fix for URLs in Cordova apps on Windows Phone // http://blogs.msdn.com/b/msdn_answers/archive/2015/02/10/ // running-cordova-apps-on-windows-and-windows-phone-8-1-using-ionic-angularjs-and-other-frameworks.aspx .config(['$compileProvider', function($compileProvider) { $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|sms|tel|geo|ftp|mailto|file|ghttps?|ms-appx-web|ms-appx|x-wmapp0):/); $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|file|content|blob|ms-appx|ms-appx-web|x-wmapp0):|data:image\//); }]);