123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. import { InjectionToken } from '@angular/core';
  2. import { isArray, isDefined, isFunction, isObject } from '../util/util';
  3. /**
  4. * @name Config
  5. * @demo /docs/demos/src/config/
  6. * @description
  7. * The Config lets you configure your entire app or specific platforms.
  8. * You can set the tab placement, icon mode, animations, and more here.
  9. *
  10. * ```ts
  11. * import { IonicApp, IonicModule } from 'ionic-angular';
  12. *
  13. * @NgModule({
  14. * declarations: [ MyApp ],
  15. * imports: [
  16. * BrowserModule,
  17. * IonicModule.forRoot(MyApp, {
  18. * backButtonText: 'Go Back',
  19. * iconMode: 'ios',
  20. * modalEnter: 'modal-slide-in',
  21. * modalLeave: 'modal-slide-out',
  22. * tabsPlacement: 'bottom',
  23. * pageTransition: 'ios-transition'
  24. * }, {}
  25. * )],
  26. * bootstrap: [IonicApp],
  27. * entryComponents: [ MyApp ],
  28. * providers: []
  29. * })
  30. * ```
  31. *
  32. *
  33. * Config can be overwritten at multiple levels allowing for more granular configuration.
  34. * Below is an example where an app can override any setting we want based on a platform.
  35. *
  36. * ```ts
  37. * import { IonicModule } from 'ionic-angular';
  38. *
  39. * @NgModule({
  40. * ...
  41. * imports: [
  42. * BrowserModule,
  43. * IonicModule.forRoot(MyApp, {
  44. * tabsPlacement: 'bottom',
  45. * platforms: {
  46. * ios: {
  47. * tabsPlacement: 'top',
  48. * }
  49. * }
  50. * }, {}
  51. * )],
  52. * ...
  53. * })
  54. * ```
  55. *
  56. * We could also configure these values at a component level. Take `tabsPlacement`,
  57. * we can configure this as a property on our `ion-tabs`.
  58. *
  59. * ```html
  60. * <ion-tabs tabsPlacement="top">
  61. * <ion-tab tabTitle="Dash" tabIcon="pulse" [root]="tabRoot"></ion-tab>
  62. * </ion-tabs>
  63. * ```
  64. *
  65. * The last way we could configure is through URL query strings. This is useful for testing
  66. * while in the browser. Simply add `?ionic<PROPERTYNAME>=<value>` to the url.
  67. *
  68. * ```bash
  69. * http://localhost:8100/?ionicTabsPlacement=bottom
  70. * ```
  71. *
  72. * Any value can be added to config, and looked up at a later in any component.
  73. *
  74. * ```js
  75. * config.set('ios', 'favoriteColor', 'green');
  76. *
  77. * // from any page in your app:
  78. * config.get('favoriteColor'); // 'green' when iOS
  79. * ```
  80. *
  81. *
  82. * A config value can come from anywhere and be anything, but there are default
  83. * values for each mode. The [theming](../../../theming/platform-specific-styles/)
  84. * documentation has a chart of the default mode configuration. The following
  85. * chart displays each property with a description of what it controls.
  86. *
  87. *
  88. * | Config Property | Type | Details |
  89. * |--------------------------|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
  90. * | `activator` | `string` | Used for buttons, changes the effect of pressing on a button. Available options: `"ripple"`, `"highlight"`. |
  91. * | `actionSheetEnter` | `string` | The name of the transition to use while an action sheet is presented. |
  92. * | `actionSheetLeave` | `string` | The name of the transition to use while an action sheet is dismissed. |
  93. * | `alertEnter` | `string` | The name of the transition to use while an alert is presented. |
  94. * | `alertLeave` | `string` | The name of the transition to use while an alert is dismissed. |
  95. * | `backButtonText` | `string` | The text to display by the back button icon in the navbar. |
  96. * | `backButtonIcon` | `string` | The icon to use as the back button icon. |
  97. * | `iconMode` | `string` | The mode to use for all icons throughout the application. Available options: `"ios"`, `"md"` |
  98. * | `locationStrategy` | `string` | Set to 'path' to remove hashbangs when using Deeplinking. |
  99. * | `loadingEnter` | `string` | The name of the transition to use while a loading indicator is presented. |
  100. * | `loadingLeave` | `string` | The name of the transition to use while a loading indicator is dismissed. |
  101. * | `menuType` | `string` | Type of menu to display. Available options: `"overlay"`, `"reveal"`, `"push"`. |
  102. * | `modalEnter` | `string` | The name of the transition to use while a modal is presented. |
  103. * | `modalLeave` | `string` | The name of the transition to use while a modal is dismiss. |
  104. * | `mode` | `string` | The mode to use throughout the application. |
  105. * | `pageTransition` | `string` | The name of the transition to use while changing pages. Available options: `"ios-transition"`, `"md-transition"`, `"wp-transition"`. |
  106. * | `pickerEnter` | `string` | The name of the transition to use while a picker is presented. |
  107. * | `pickerLeave` | `string` | The name of the transition to use while a picker is dismissed. |
  108. * | `popoverEnter` | `string` | The name of the transition to use while a popover is presented. |
  109. * | `popoverLeave` | `string` | The name of the transition to use while a popover is dismissed.
  110. * | `scrollAssist` | `boolean` | Used to avoid the input to be hidden by the keyboard if it's near the bottom of the page.
  111. * | `scrollPadding` | `boolean` | Used to remove the extra padding on ion-content when keyboard is displayed.
  112. * | `spinner` | `string` | The default spinner to use when a name is not defined. |
  113. * | `statusbarPadding` | `boolean` | Whether to hide extra padding for statusbar. |
  114. * | `swipeBackEnabled` | `boolean` | Whether native iOS swipe to go back functionality is enabled. |
  115. * | `tabsHighlight` | `boolean` | Whether to show a highlight line under the tab when it is selected. |
  116. * | `tabsLayout` | `string` | The layout to use for all tabs. Available options: `"icon-top"`, `"icon-start"`, `"icon-end"`, `"icon-bottom"`, `"icon-hide"`, `"title-hide"`. |
  117. * | `tabsPlacement` | `string` | The position of the tabs relative to the content. Available options: `"top"`, `"bottom"` |
  118. * | `tabsHideOnSubPages` | `boolean` | Whether to hide the tabs on child pages or not. If `true` it will not show the tabs on child pages. |
  119. * | `toastEnter` | `string` | The name of the transition to use while a toast is presented. |
  120. * | `toastLeave` | `string` | The name of the transition to use while a toast is dismissed. |
  121. *
  122. **/
  123. export class Config {
  124. constructor() {
  125. this._c = {};
  126. this._s = {};
  127. this._modes = {};
  128. this._trns = {};
  129. }
  130. /**
  131. * @hidden
  132. */
  133. init(config, plt) {
  134. this._s = config && isObject(config) && !isArray(config) ? config : {};
  135. this.plt = plt;
  136. }
  137. /**
  138. * @name get
  139. * @description
  140. * Returns a single config value, given a key.
  141. *
  142. * @param {string} [key] - the key for the config value
  143. * @param {any} [fallbackValue] - a fallback value to use when the config
  144. * value was not found, or is config value is `null`. Fallback value
  145. * defaults to `null`.
  146. */
  147. get(key, fallbackValue = null) {
  148. const platform = this.plt;
  149. if (!isDefined(this._c[key])) {
  150. if (!isDefined(key)) {
  151. throw 'config key is not defined';
  152. }
  153. // if the value was already set this will all be skipped
  154. // if there was no user config then it'll check each of
  155. // the user config's platforms, which already contains
  156. // settings from default platform configs
  157. var userPlatformValue = undefined;
  158. var userDefaultValue = this._s[key];
  159. var userPlatformModeValue = undefined;
  160. var userDefaultModeValue = undefined;
  161. var platformValue = undefined;
  162. var platformModeValue = undefined;
  163. var configObj = null;
  164. if (platform) {
  165. var queryStringValue = platform.getQueryParam('ionic' + key);
  166. if (isDefined(queryStringValue)) {
  167. return this._c[key] = (queryStringValue === 'true' ? true : queryStringValue === 'false' ? false : queryStringValue);
  168. }
  169. // check the platform settings object for this value
  170. // loop though each of the active platforms
  171. // array of active platforms, which also knows the hierarchy,
  172. // with the last one the most important
  173. var activePlatformKeys = platform.platforms();
  174. // loop through all of the active platforms we're on
  175. for (var i = 0, ilen = activePlatformKeys.length; i < ilen; i++) {
  176. // get user defined platform values
  177. if (this._s.platforms) {
  178. configObj = this._s.platforms[activePlatformKeys[i]];
  179. if (configObj) {
  180. if (isDefined(configObj[key])) {
  181. userPlatformValue = configObj[key];
  182. }
  183. configObj = this.getModeConfig(configObj.mode);
  184. if (configObj && isDefined(configObj[key])) {
  185. userPlatformModeValue = configObj[key];
  186. }
  187. }
  188. }
  189. // get default platform's setting
  190. configObj = platform.getPlatformConfig(activePlatformKeys[i]);
  191. if (configObj && configObj.settings) {
  192. if (isDefined(configObj.settings[key])) {
  193. // found a setting for this platform
  194. platformValue = configObj.settings[key];
  195. }
  196. configObj = this.getModeConfig(configObj.settings.mode);
  197. if (configObj && isDefined(configObj[key])) {
  198. // found setting for this platform's mode
  199. platformModeValue = configObj[key];
  200. }
  201. }
  202. }
  203. }
  204. configObj = this.getModeConfig(this._s.mode);
  205. if (configObj && isDefined(configObj[key])) {
  206. userDefaultModeValue = configObj[key];
  207. }
  208. // cache the value
  209. this._c[key] = isDefined(userPlatformValue) ? userPlatformValue :
  210. isDefined(userDefaultValue) ? userDefaultValue :
  211. isDefined(userPlatformModeValue) ? userPlatformModeValue :
  212. isDefined(userDefaultModeValue) ? userDefaultModeValue :
  213. isDefined(platformValue) ? platformValue :
  214. isDefined(platformModeValue) ? platformModeValue :
  215. null;
  216. }
  217. // return key's value
  218. // either it came directly from the user config
  219. // or it was from the users platform configs
  220. // or it was from the default platform configs
  221. // in that order
  222. var rtnVal = this._c[key];
  223. if (isFunction(rtnVal)) {
  224. rtnVal = rtnVal(platform);
  225. }
  226. return (rtnVal !== null ? rtnVal : fallbackValue);
  227. }
  228. /**
  229. * @name getBoolean
  230. * @description
  231. * Same as `get()`, however always returns a boolean value. If the
  232. * value from `get()` is `null`, then it'll return the `fallbackValue`
  233. * which defaults to `false`. Otherwise, `getBoolean()` will return
  234. * if the config value is truthy or not. It also returns `true` if
  235. * the config value was the string value `"true"`.
  236. * @param {string} [key] - the key for the config value
  237. * @param {boolean} [fallbackValue] - a fallback value to use when the config
  238. * value was `null`. Fallback value defaults to `false`.
  239. */
  240. getBoolean(key, fallbackValue = false) {
  241. const val = this.get(key);
  242. if (val === null) {
  243. return fallbackValue;
  244. }
  245. if (typeof val === 'string') {
  246. return val === 'true';
  247. }
  248. return !!val;
  249. }
  250. /**
  251. * @name getNumber
  252. * @description
  253. * Same as `get()`, however always returns a number value. Uses `parseFloat()`
  254. * on the value received from `get()`. If the result from the parse is `NaN`,
  255. * then it will return the value passed to `fallbackValue`. If no fallback
  256. * value was provided then it'll default to returning `NaN` when the result
  257. * is not a valid number.
  258. * @param {string} [key] - the key for the config value
  259. * @param {number} [fallbackValue] - a fallback value to use when the config
  260. * value turned out to be `NaN`. Fallback value defaults to `NaN`.
  261. */
  262. getNumber(key, fallbackValue = NaN) {
  263. const val = parseFloat(this.get(key));
  264. return isNaN(val) ? fallbackValue : val;
  265. }
  266. /**
  267. * @name set
  268. * @description
  269. * Sets a single config value.
  270. *
  271. * @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.
  272. * @param {string} [key] - The key used to look up the value at a later point in time.
  273. * @param {string} [value] - The config value being stored.
  274. */
  275. set(...args) {
  276. const arg0 = args[0];
  277. const arg1 = args[1];
  278. switch (args.length) {
  279. case 2:
  280. // set('key', 'value') = set key/value pair
  281. // arg1 = value
  282. this._s[arg0] = arg1;
  283. delete this._c[arg0]; // clear cache
  284. break;
  285. case 3:
  286. // setting('ios', 'key', 'value') = set key/value pair for platform
  287. // arg0 = platform
  288. // arg1 = key
  289. // arg2 = value
  290. this._s.platforms = this._s.platforms || {};
  291. this._s.platforms[arg0] = this._s.platforms[arg0] || {};
  292. this._s.platforms[arg0][arg1] = args[2];
  293. delete this._c[arg1]; // clear cache
  294. break;
  295. }
  296. return this;
  297. }
  298. /**
  299. * @hidden
  300. * @name settings()
  301. * @description
  302. */
  303. settings(arg0, arg1) {
  304. switch (arguments.length) {
  305. case 0:
  306. return this._s;
  307. case 1:
  308. // settings({...})
  309. this._s = arg0;
  310. this._c = {}; // clear cache
  311. break;
  312. case 2:
  313. // settings('ios', {...})
  314. this._s.platforms = this._s.platforms || {};
  315. this._s.platforms[arg0] = arg1;
  316. this._c = {}; // clear cache
  317. break;
  318. }
  319. return this;
  320. }
  321. /**
  322. * @hidden
  323. */
  324. setModeConfig(modeName, modeConfig) {
  325. this._modes[modeName] = modeConfig;
  326. }
  327. /**
  328. * @hidden
  329. */
  330. getModeConfig(modeName) {
  331. return this._modes[modeName] || null;
  332. }
  333. /**
  334. * @hidden
  335. */
  336. setTransition(trnsName, trnsClass) {
  337. this._trns[trnsName] = trnsClass;
  338. }
  339. /**
  340. * @hidden
  341. */
  342. getTransition(trnsName) {
  343. return this._trns[trnsName] || null;
  344. }
  345. }
  346. /**
  347. * @hidden
  348. */
  349. export function setupConfig(userConfig, plt) {
  350. const config = new Config();
  351. config.init(userConfig, plt);
  352. // add the config obj to the window
  353. const win = plt.win();
  354. win['Ionic'] = win['Ionic'] || {};
  355. win['Ionic']['config'] = config;
  356. return config;
  357. }
  358. /**
  359. * @hidden
  360. */
  361. export const ConfigToken = new InjectionToken('USERCONFIG');
  362. //# sourceMappingURL=config.js.map