From 89d0f535699286390dba34f7234a071f37a7d8a0 Mon Sep 17 00:00:00 2001 From: Uri Goldshtein Date: Fri, 6 Feb 2015 04:09:59 -0800 Subject: [PATCH] New version that doesn't relay on meteor-bower anymore (too buggy) Fixes - #33 #35 #36 #37 --- .versions | 4 +- dependencies/angular-animate.js | 2137 ++++++ dependencies/angular-sanitize.js | 680 ++ ionic-override.css | 6 - lib/css/ionic.css | 7013 ++++++++++++++++++ lib/fonts/ionicons.eot | Bin 0 -> 101984 bytes lib/fonts/ionicons.svg | 1899 +++++ lib/fonts/ionicons.ttf | Bin 0 -> 164548 bytes lib/fonts/ionicons.woff | Bin 0 -> 57276 bytes lib/js/ionic-angular.js | 11486 +++++++++++++++++++++++++++++ lib/js/ionic.js | 7811 ++++++++++++++++++++ init.js => override-fastclick.js | 0 package.js | 27 +- smart.json | 16 - 14 files changed, 31045 insertions(+), 34 deletions(-) create mode 100644 dependencies/angular-animate.js create mode 100644 dependencies/angular-sanitize.js delete mode 100644 ionic-override.css create mode 100755 lib/css/ionic.css create mode 100755 lib/fonts/ionicons.eot create mode 100755 lib/fonts/ionicons.svg create mode 100755 lib/fonts/ionicons.ttf create mode 100755 lib/fonts/ionicons.woff create mode 100755 lib/js/ionic-angular.js create mode 100755 lib/js/ionic.js rename init.js => override-fastclick.js (100%) delete mode 100644 smart.json diff --git a/.versions b/.versions index 75675c64..6a20a259 100644 --- a/.versions +++ b/.versions @@ -1,4 +1,4 @@ +angularui:angular-ui-router@0.2.13 meteor@1.1.4 -mquandalle:bower@0.1.11 underscore@1.0.2 -urigo:ionic@0.2.1 +urigo:ionic@0.3.0 diff --git a/dependencies/angular-animate.js b/dependencies/angular-animate.js new file mode 100644 index 00000000..98e39bc1 --- /dev/null +++ b/dependencies/angular-animate.js @@ -0,0 +1,2137 @@ +/** + * @license AngularJS v1.3.12 + * (c) 2010-2014 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, angular, undefined) {'use strict'; + +/* jshint maxlen: false */ + +/** + * @ngdoc module + * @name ngAnimate + * @description + * + * The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives. + * + *
+ * + * # Usage + * + * To see animations in action, all that is required is to define the appropriate CSS classes + * or to register a JavaScript animation via the `myModule.animation()` function. The directives that support animation automatically are: + * `ngRepeat`, `ngInclude`, `ngIf`, `ngSwitch`, `ngShow`, `ngHide`, `ngView` and `ngClass`. Custom directives can take advantage of animation + * by using the `$animate` service. + * + * Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives: + * + * | Directive | Supported Animations | + * |----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------| + * | {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave and move | + * | {@link ngRoute.directive:ngView#animations ngView} | enter and leave | + * | {@link ng.directive:ngInclude#animations ngInclude} | enter and leave | + * | {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave | + * | {@link ng.directive:ngIf#animations ngIf} | enter and leave | + * | {@link ng.directive:ngClass#animations ngClass} | add and remove (the CSS class(es) present) | + * | {@link ng.directive:ngShow#animations ngShow} & {@link ng.directive:ngHide#animations ngHide} | add and remove (the ng-hide class value) | + * | {@link ng.directive:form#animation-hooks form} & {@link ng.directive:ngModel#animation-hooks ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) | + * | {@link module:ngMessages#animations ngMessages} | add and remove (ng-active & ng-inactive) | + * | {@link module:ngMessages#animations ngMessage} | enter and leave | + * + * You can find out more information about animations upon visiting each directive page. + * + * Below is an example of how to apply animations to a directive that supports animation hooks: + * + * ```html + * + * + * + * + * ``` + * + * Keep in mind that, by default, if an animation is running, any child elements cannot be animated + * until the parent element's animation has completed. This blocking feature can be overridden by + * placing the `ng-animate-children` attribute on a parent container tag. + * + * ```html + *
+ *
+ *
+ * ... + *
+ *
+ *
+ * ``` + * + * When the `on` expression value changes and an animation is triggered then each of the elements within + * will all animate without the block being applied to child elements. + * + * ## Are animations run when the application starts? + * No they are not. When an application is bootstrapped Angular will disable animations from running to avoid + * a frenzy of animations from being triggered as soon as the browser has rendered the screen. For this to work, + * Angular will wait for two digest cycles until enabling animations. From there on, any animation-triggering + * layout changes in the application will trigger animations as normal. + * + * In addition, upon bootstrap, if the routing system or any directives or load remote data (via $http) then Angular + * will automatically extend the wait time to enable animations once **all** of the outbound HTTP requests + * are complete. + * + * ## CSS-defined Animations + * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes + * are designed to contain the start and end CSS styling. Both CSS transitions and keyframe animations are supported + * and can be used to play along with this naming structure. + * + * The following code below demonstrates how to perform animations using **CSS transitions** with Angular: + * + * ```html + * + * + *
+ *
+ *
+ * ``` + * + * The following code below demonstrates how to perform animations using **CSS animations** with Angular: + * + * ```html + * + * + *
+ *
+ *
+ * ``` + * + * Both CSS3 animations and transitions can be used together and the animate service will figure out the correct duration and delay timing. + * + * Upon DOM mutation, the event class is added first (something like `ng-enter`), then the browser prepares itself to add + * the active class (in this case `ng-enter-active`) which then triggers the animation. The animation module will automatically + * detect the CSS code to determine when the animation ends. Once the animation is over then both CSS classes will be + * removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end + * immediately resulting in a DOM element that is at its final state. This final state is when the DOM element + * has no CSS transition/animation classes applied to it. + * + * ### Structural transition animations + * + * Structural transitions (such as enter, leave and move) will always apply a `0s none` transition + * value to force the browser into rendering the styles defined in the setup (`.ng-enter`, `.ng-leave` + * or `.ng-move`) class. This means that any active transition animations operating on the element + * will be cut off to make way for the enter, leave or move animation. + * + * ### Class-based transition animations + * + * Class-based transitions refer to transition animations that are triggered when a CSS class is + * added to or removed from the element (via `$animate.addClass`, `$animate.removeClass`, + * `$animate.setClass`, or by directives such as `ngClass`, `ngModel` and `form`). + * They are different when compared to structural animations since they **do not cancel existing + * animations** nor do they **block successive transitions** from rendering on the same element. + * This distinction allows for **multiple class-based transitions** to be performed on the same element. + * + * In addition to ngAnimate supporting the default (natural) functionality of class-based transition + * animations, ngAnimate also decorates the element with starting and ending CSS classes to aid the + * developer in further styling the element throughout the transition animation. Earlier versions + * of ngAnimate may have caused natural CSS transitions to break and not render properly due to + * $animate temporarily blocking transitions using `0s none` in order to allow the setup CSS class + * (the `-add` or `-remove` class) to be applied without triggering an animation. However, as of + * **version 1.3**, this workaround has been removed with ngAnimate and all non-ngAnimate CSS + * class transitions are compatible with ngAnimate. + * + * There is, however, one special case when dealing with class-based transitions in ngAnimate. + * When rendering class-based transitions that make use of the setup and active CSS classes + * (e.g. `.fade-add` and `.fade-add-active` for when `.fade` is added) be sure to define + * the transition value **on the active CSS class** and not the setup class. + * + * ```css + * .fade-add { + * /* remember to place a 0s transition here + * to ensure that the styles are applied instantly + * even if the element already has a transition style */ + * transition:0s linear all; + * + * /* starting CSS styles */ + * opacity:1; + * } + * .fade-add.fade-add-active { + * /* this will be the length of the animation */ + * transition:1s linear all; + * opacity:0; + * } + * ``` + * + * The setup CSS class (in this case `.fade-add`) also has a transition style property, however, it + * has a duration of zero. This may not be required, however, incase the browser is unable to render + * the styling present in this CSS class instantly then it could be that the browser is attempting + * to perform an unnecessary transition. + * + * This workaround, however, does not apply to standard class-based transitions that are rendered + * when a CSS class containing a transition is applied to an element: + * + * ```css + * /* this works as expected */ + * .fade { + * transition:1s linear all; + * opacity:0; + * } + * ``` + * + * Please keep this in mind when coding the CSS markup that will be used within class-based transitions. + * Also, try not to mix the two class-based animation flavors together since the CSS code may become + * overly complex. + * + * + * ### Preventing Collisions With Third Party Libraries + * + * Some third-party frameworks place animation duration defaults across many element or className + * selectors in order to make their code small and reuseable. This can lead to issues with ngAnimate, which + * is expecting actual animations on these elements and has to wait for their completion. + * + * You can prevent this unwanted behavior by using a prefix on all your animation classes: + * + * ```css + * /* prefixed with animate- */ + * .animate-fade-add.animate-fade-add-active { + * transition:1s linear all; + * opacity:0; + * } + * ``` + * + * You then configure `$animate` to enforce this prefix: + * + * ```js + * $animateProvider.classNameFilter(/animate-/); + * ``` + * + * + * ### CSS Staggering Animations + * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a + * curtain-like effect. The ngAnimate module (versions >=1.2) supports staggering animations and the stagger effect can be + * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for + * the animation. The style property expected within the stagger class can either be a **transition-delay** or an + * **animation-delay** property (or both if your animation contains both transitions and keyframe animations). + * + * ```css + * .my-animation.ng-enter { + * /* standard transition code */ + * -webkit-transition: 1s linear all; + * transition: 1s linear all; + * opacity:0; + * } + * .my-animation.ng-enter-stagger { + * /* this will have a 100ms delay between each successive leave animation */ + * -webkit-transition-delay: 0.1s; + * transition-delay: 0.1s; + * + * /* in case the stagger doesn't work then these two values + * must be set to 0 to avoid an accidental CSS inheritance */ + * -webkit-transition-duration: 0s; + * transition-duration: 0s; + * } + * .my-animation.ng-enter.ng-enter-active { + * /* standard transition styles */ + * opacity:1; + * } + * ``` + * + * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations + * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this + * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation + * will also be reset if more than 10ms has passed after the last animation has been fired. + * + * The following code will issue the **ng-leave-stagger** event on the element provided: + * + * ```js + * var kids = parent.children(); + * + * $animate.leave(kids[0]); //stagger index=0 + * $animate.leave(kids[1]); //stagger index=1 + * $animate.leave(kids[2]); //stagger index=2 + * $animate.leave(kids[3]); //stagger index=3 + * $animate.leave(kids[4]); //stagger index=4 + * + * $timeout(function() { + * //stagger has reset itself + * $animate.leave(kids[5]); //stagger index=0 + * $animate.leave(kids[6]); //stagger index=1 + * }, 100, false); + * ``` + * + * Stagger animations are currently only supported within CSS-defined animations. + * + * ## JavaScript-defined Animations + * In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations on browsers that do not + * yet support CSS transitions/animations, then you can make use of JavaScript animations defined inside of your AngularJS module. + * + * ```js + * //!annotate="YourApp" Your AngularJS Module|Replace this or ngModule with the module that you used to define your application. + * var ngModule = angular.module('YourApp', ['ngAnimate']); + * ngModule.animation('.my-crazy-animation', function() { + * return { + * enter: function(element, done) { + * //run the animation here and call done when the animation is complete + * return function(cancelled) { + * //this (optional) function will be called when the animation + * //completes or when the animation is cancelled (the cancelled + * //flag will be set to true if cancelled). + * }; + * }, + * leave: function(element, done) { }, + * move: function(element, done) { }, + * + * //animation that can be triggered before the class is added + * beforeAddClass: function(element, className, done) { }, + * + * //animation that can be triggered after the class is added + * addClass: function(element, className, done) { }, + * + * //animation that can be triggered before the class is removed + * beforeRemoveClass: function(element, className, done) { }, + * + * //animation that can be triggered after the class is removed + * removeClass: function(element, className, done) { } + * }; + * }); + * ``` + * + * JavaScript-defined animations are created with a CSS-like class selector and a collection of events which are set to run + * a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits + * the element's CSS class attribute value and then run the matching animation event function (if found). + * In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function will + * be executed. It should be also noted that only simple, single class selectors are allowed (compound class selectors are not supported). + * + * Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned. + * As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run, + * and the JavaScript animation is found, then the enter callback will handle that animation (in addition to the CSS keyframe animation + * or transition code that is defined via a stylesheet). + * + * + * ### Applying Directive-specific Styles to an Animation + * In some cases a directive or service may want to provide `$animate` with extra details that the animation will + * include into its animation. Let's say for example we wanted to render an animation that animates an element + * towards the mouse coordinates as to where the user clicked last. By collecting the X/Y coordinates of the click + * (via the event parameter) we can set the `top` and `left` styles into an object and pass that into our function + * call to `$animate.addClass`. + * + * ```js + * canvas.on('click', function(e) { + * $animate.addClass(element, 'on', { + * to: { + * left : e.client.x + 'px', + * top : e.client.y + 'px' + * } + * }): + * }); + * ``` + * + * Now when the animation runs, and a transition or keyframe animation is picked up, then the animation itself will + * also include and transition the styling of the `left` and `top` properties into its running animation. If we want + * to provide some starting animation values then we can do so by placing the starting animations styles into an object + * called `from` in the same object as the `to` animations. + * + * ```js + * canvas.on('click', function(e) { + * $animate.addClass(element, 'on', { + * from: { + * position: 'absolute', + * left: '0px', + * top: '0px' + * }, + * to: { + * left : e.client.x + 'px', + * top : e.client.y + 'px' + * } + * }): + * }); + * ``` + * + * Once the animation is complete or cancelled then the union of both the before and after styles are applied to the + * element. If `ngAnimate` is not present then the styles will be applied immediately. + * + */ + +angular.module('ngAnimate', ['ng']) + + /** + * @ngdoc provider + * @name $animateProvider + * @description + * + * The `$animateProvider` allows developers to register JavaScript animation event handlers directly inside of a module. + * When an animation is triggered, the $animate service will query the $animate service to find any animations that match + * the provided name value. + * + * Requires the {@link ngAnimate `ngAnimate`} module to be installed. + * + * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application. + * + */ + .directive('ngAnimateChildren', function() { + var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren'; + return function(scope, element, attrs) { + var val = attrs.ngAnimateChildren; + if (angular.isString(val) && val.length === 0) { //empty attribute + element.data(NG_ANIMATE_CHILDREN, true); + } else { + scope.$watch(val, function(value) { + element.data(NG_ANIMATE_CHILDREN, !!value); + }); + } + }; + }) + + //this private service is only used within CSS-enabled animations + //IE8 + IE9 do not support rAF natively, but that is fine since they + //also don't support transitions and keyframes which means that the code + //below will never be used by the two browsers. + .factory('$$animateReflow', ['$$rAF', '$document', function($$rAF, $document) { + var bod = $document[0].body; + return function(fn) { + //the returned function acts as the cancellation function + return $$rAF(function() { + //the line below will force the browser to perform a repaint + //so that all the animated elements within the animation frame + //will be properly updated and drawn on screen. This is + //required to perform multi-class CSS based animations with + //Firefox. DO NOT REMOVE THIS LINE. + var a = bod.offsetWidth + 1; + fn(); + }); + }; + }]) + + .config(['$provide', '$animateProvider', function($provide, $animateProvider) { + var noop = angular.noop; + var forEach = angular.forEach; + var selectors = $animateProvider.$$selectors; + var isArray = angular.isArray; + var isString = angular.isString; + var isObject = angular.isObject; + + var ELEMENT_NODE = 1; + var NG_ANIMATE_STATE = '$$ngAnimateState'; + var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren'; + var NG_ANIMATE_CLASS_NAME = 'ng-animate'; + var rootAnimateState = {running: true}; + + function extractElementNode(element) { + for (var i = 0; i < element.length; i++) { + var elm = element[i]; + if (elm.nodeType == ELEMENT_NODE) { + return elm; + } + } + } + + function prepareElement(element) { + return element && angular.element(element); + } + + function stripCommentsFromElement(element) { + return angular.element(extractElementNode(element)); + } + + function isMatchingElement(elm1, elm2) { + return extractElementNode(elm1) == extractElementNode(elm2); + } + var $$jqLite; + $provide.decorator('$animate', + ['$delegate', '$$q', '$injector', '$sniffer', '$rootElement', '$$asyncCallback', '$rootScope', '$document', '$templateRequest', '$$jqLite', + function($delegate, $$q, $injector, $sniffer, $rootElement, $$asyncCallback, $rootScope, $document, $templateRequest, $$$jqLite) { + + $$jqLite = $$$jqLite; + $rootElement.data(NG_ANIMATE_STATE, rootAnimateState); + + // Wait until all directive and route-related templates are downloaded and + // compiled. The $templateRequest.totalPendingRequests variable keeps track of + // all of the remote templates being currently downloaded. If there are no + // templates currently downloading then the watcher will still fire anyway. + var deregisterWatch = $rootScope.$watch( + function() { return $templateRequest.totalPendingRequests; }, + function(val, oldVal) { + if (val !== 0) return; + deregisterWatch(); + + // Now that all templates have been downloaded, $animate will wait until + // the post digest queue is empty before enabling animations. By having two + // calls to $postDigest calls we can ensure that the flag is enabled at the + // very end of the post digest queue. Since all of the animations in $animate + // use $postDigest, it's important that the code below executes at the end. + // This basically means that the page is fully downloaded and compiled before + // any animations are triggered. + $rootScope.$$postDigest(function() { + $rootScope.$$postDigest(function() { + rootAnimateState.running = false; + }); + }); + } + ); + + var globalAnimationCounter = 0; + var classNameFilter = $animateProvider.classNameFilter(); + var isAnimatableClassName = !classNameFilter + ? function() { return true; } + : function(className) { + return classNameFilter.test(className); + }; + + function classBasedAnimationsBlocked(element, setter) { + var data = element.data(NG_ANIMATE_STATE) || {}; + if (setter) { + data.running = true; + data.structural = true; + element.data(NG_ANIMATE_STATE, data); + } + return data.disabled || (data.running && data.structural); + } + + function runAnimationPostDigest(fn) { + var cancelFn, defer = $$q.defer(); + defer.promise.$$cancelFn = function() { + cancelFn && cancelFn(); + }; + $rootScope.$$postDigest(function() { + cancelFn = fn(function() { + defer.resolve(); + }); + }); + return defer.promise; + } + + function parseAnimateOptions(options) { + // some plugin code may still be passing in the callback + // function as the last param for the $animate methods so + // it's best to only allow string or array values for now + if (isObject(options)) { + if (options.tempClasses && isString(options.tempClasses)) { + options.tempClasses = options.tempClasses.split(/\s+/); + } + return options; + } + } + + function resolveElementClasses(element, cache, runningAnimations) { + runningAnimations = runningAnimations || {}; + + var lookup = {}; + forEach(runningAnimations, function(data, selector) { + forEach(selector.split(' '), function(s) { + lookup[s]=data; + }); + }); + + var hasClasses = Object.create(null); + forEach((element.attr('class') || '').split(/\s+/), function(className) { + hasClasses[className] = true; + }); + + var toAdd = [], toRemove = []; + forEach((cache && cache.classes) || [], function(status, className) { + var hasClass = hasClasses[className]; + var matchingAnimation = lookup[className] || {}; + + // When addClass and removeClass is called then $animate will check to + // see if addClass and removeClass cancel each other out. When there are + // more calls to removeClass than addClass then the count falls below 0 + // and then the removeClass animation will be allowed. Otherwise if the + // count is above 0 then that means an addClass animation will commence. + // Once an animation is allowed then the code will also check to see if + // there exists any on-going animation that is already adding or remvoing + // the matching CSS class. + if (status === false) { + //does it have the class or will it have the class + if (hasClass || matchingAnimation.event == 'addClass') { + toRemove.push(className); + } + } else if (status === true) { + //is the class missing or will it be removed? + if (!hasClass || matchingAnimation.event == 'removeClass') { + toAdd.push(className); + } + } + }); + + return (toAdd.length + toRemove.length) > 0 && [toAdd.join(' '), toRemove.join(' ')]; + } + + function lookup(name) { + if (name) { + var matches = [], + flagMap = {}, + classes = name.substr(1).split('.'); + + //the empty string value is the default animation + //operation which performs CSS transition and keyframe + //animations sniffing. This is always included for each + //element animation procedure if the browser supports + //transitions and/or keyframe animations. The default + //animation is added to the top of the list to prevent + //any previous animations from affecting the element styling + //prior to the element being animated. + if ($sniffer.transitions || $sniffer.animations) { + matches.push($injector.get(selectors[''])); + } + + for (var i=0; i < classes.length; i++) { + var klass = classes[i], + selectorFactoryName = selectors[klass]; + if (selectorFactoryName && !flagMap[klass]) { + matches.push($injector.get(selectorFactoryName)); + flagMap[klass] = true; + } + } + return matches; + } + } + + function animationRunner(element, animationEvent, className, options) { + //transcluded directives may sometimes fire an animation using only comment nodes + //best to catch this early on to prevent any animation operations from occurring + var node = element[0]; + if (!node) { + return; + } + + if (options) { + options.to = options.to || {}; + options.from = options.from || {}; + } + + var classNameAdd; + var classNameRemove; + if (isArray(className)) { + classNameAdd = className[0]; + classNameRemove = className[1]; + if (!classNameAdd) { + className = classNameRemove; + animationEvent = 'removeClass'; + } else if (!classNameRemove) { + className = classNameAdd; + animationEvent = 'addClass'; + } else { + className = classNameAdd + ' ' + classNameRemove; + } + } + + var isSetClassOperation = animationEvent == 'setClass'; + var isClassBased = isSetClassOperation + || animationEvent == 'addClass' + || animationEvent == 'removeClass' + || animationEvent == 'animate'; + + var currentClassName = element.attr('class'); + var classes = currentClassName + ' ' + className; + if (!isAnimatableClassName(classes)) { + return; + } + + var beforeComplete = noop, + beforeCancel = [], + before = [], + afterComplete = noop, + afterCancel = [], + after = []; + + var animationLookup = (' ' + classes).replace(/\s+/g,'.'); + forEach(lookup(animationLookup), function(animationFactory) { + var created = registerAnimation(animationFactory, animationEvent); + if (!created && isSetClassOperation) { + registerAnimation(animationFactory, 'addClass'); + registerAnimation(animationFactory, 'removeClass'); + } + }); + + function registerAnimation(animationFactory, event) { + var afterFn = animationFactory[event]; + var beforeFn = animationFactory['before' + event.charAt(0).toUpperCase() + event.substr(1)]; + if (afterFn || beforeFn) { + if (event == 'leave') { + beforeFn = afterFn; + //when set as null then animation knows to skip this phase + afterFn = null; + } + after.push({ + event: event, fn: afterFn + }); + before.push({ + event: event, fn: beforeFn + }); + return true; + } + } + + function run(fns, cancellations, allCompleteFn) { + var animations = []; + forEach(fns, function(animation) { + animation.fn && animations.push(animation); + }); + + var count = 0; + function afterAnimationComplete(index) { + if (cancellations) { + (cancellations[index] || noop)(); + if (++count < animations.length) return; + cancellations = null; + } + allCompleteFn(); + } + + //The code below adds directly to the array in order to work with + //both sync and async animations. Sync animations are when the done() + //operation is called right away. DO NOT REFACTOR! + forEach(animations, function(animation, index) { + var progress = function() { + afterAnimationComplete(index); + }; + switch (animation.event) { + case 'setClass': + cancellations.push(animation.fn(element, classNameAdd, classNameRemove, progress, options)); + break; + case 'animate': + cancellations.push(animation.fn(element, className, options.from, options.to, progress)); + break; + case 'addClass': + cancellations.push(animation.fn(element, classNameAdd || className, progress, options)); + break; + case 'removeClass': + cancellations.push(animation.fn(element, classNameRemove || className, progress, options)); + break; + default: + cancellations.push(animation.fn(element, progress, options)); + break; + } + }); + + if (cancellations && cancellations.length === 0) { + allCompleteFn(); + } + } + + return { + node: node, + event: animationEvent, + className: className, + isClassBased: isClassBased, + isSetClassOperation: isSetClassOperation, + applyStyles: function() { + if (options) { + element.css(angular.extend(options.from || {}, options.to || {})); + } + }, + before: function(allCompleteFn) { + beforeComplete = allCompleteFn; + run(before, beforeCancel, function() { + beforeComplete = noop; + allCompleteFn(); + }); + }, + after: function(allCompleteFn) { + afterComplete = allCompleteFn; + run(after, afterCancel, function() { + afterComplete = noop; + allCompleteFn(); + }); + }, + cancel: function() { + if (beforeCancel) { + forEach(beforeCancel, function(cancelFn) { + (cancelFn || noop)(true); + }); + beforeComplete(true); + } + if (afterCancel) { + forEach(afterCancel, function(cancelFn) { + (cancelFn || noop)(true); + }); + afterComplete(true); + } + } + }; + } + + /** + * @ngdoc service + * @name $animate + * @kind object + * + * @description + * The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) as well as during addClass and removeClass operations. + * When any of these operations are run, the $animate service + * will examine any JavaScript-defined animations (which are defined by using the $animateProvider provider object) + * as well as any CSS-defined animations against the CSS classes present on the element once the DOM operation is run. + * + * The `$animate` service is used behind the scenes with pre-existing directives and animation with these directives + * will work out of the box without any extra configuration. + * + * Requires the {@link ngAnimate `ngAnimate`} module to be installed. + * + * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application. + * ## Callback Promises + * With AngularJS 1.3, each of the animation methods, on the `$animate` service, return a promise when called. The + * promise itself is then resolved once the animation has completed itself, has been cancelled or has been + * skipped due to animations being disabled. (Note that even if the animation is cancelled it will still + * call the resolve function of the animation.) + * + * ```js + * $animate.enter(element, container).then(function() { + * //...this is called once the animation is complete... + * }); + * ``` + * + * Also note that, due to the nature of the callback promise, if any Angular-specific code (like changing the scope, + * location of the page, etc...) is executed within the callback promise then be sure to wrap the code using + * `$scope.$apply(...)`; + * + * ```js + * $animate.leave(element).then(function() { + * $scope.$apply(function() { + * $location.path('/new-page'); + * }); + * }); + * ``` + * + * An animation can also be cancelled by calling the `$animate.cancel(promise)` method with the provided + * promise that was returned when the animation was started. + * + * ```js + * var promise = $animate.addClass(element, 'super-long-animation'); + * promise.then(function() { + * //this will still be called even if cancelled + * }); + * + * element.on('click', function() { + * //tooo lazy to wait for the animation to end + * $animate.cancel(promise); + * }); + * ``` + * + * (Keep in mind that the promise cancellation is unique to `$animate` since promises in + * general cannot be cancelled.) + * + */ + return { + /** + * @ngdoc method + * @name $animate#animate + * @kind function + * + * @description + * Performs an inline animation on the element which applies the provided `to` and `from` CSS styles to the element. + * If any detected CSS transition, keyframe or JavaScript matches the provided `className` value then the animation + * will take on the provided styles. For example, if a transition animation is set for the given className then the + * provided `from` and `to` styles will be applied alongside the given transition. If a JavaScript animation is + * detected then the provided styles will be given in as function paramters. + * + * ```js + * ngModule.animation('.my-inline-animation', function() { + * return { + * animate : function(element, className, from, to, done) { + * //styles + * } + * } + * }); + * ``` + * + * Below is a breakdown of each step that occurs during the `animate` animation: + * + * | Animation Step | What the element class attribute looks like | + * |-----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------| + * | 1. `$animate.animate(...)` is called | `class="my-animation"` | + * | 2. `$animate` waits for the next digest to start the animation | `class="my-animation ng-animate"` | + * | 3. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 4. the `className` class value is added to the element | `class="my-animation ng-animate className"` | + * | 5. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate className"` | + * | 6. `$animate` blocks all CSS transitions on the element to ensure the `.className` class styling is applied right away| `class="my-animation ng-animate className"` | + * | 7. `$animate` applies the provided collection of `from` CSS styles to the element | `class="my-animation ng-animate className"` | + * | 8. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate className"` | + * | 9. `$animate` removes the CSS transition block placed on the element | `class="my-animation ng-animate className"` | + * | 10. the `className-active` class is added (this triggers the CSS transition/animation) | `class="my-animation ng-animate className className-active"` | + * | 11. `$animate` applies the collection of `to` CSS styles to the element which are then handled by the transition | `class="my-animation ng-animate className className-active"` | + * | 12. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate className className-active"` | + * | 13. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 14. The returned promise is resolved. | `class="my-animation"` | + * + * @param {DOMElement} element the element that will be the focus of the enter animation + * @param {object} from a collection of CSS styles that will be applied to the element at the start of the animation + * @param {object} to a collection of CSS styles that the element will animate towards + * @param {string=} className an optional CSS class that will be added to the element for the duration of the animation (the default class is `ng-inline-animate`) + * @param {object=} options an optional collection of options that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + animate: function(element, from, to, className, options) { + className = className || 'ng-inline-animate'; + options = parseAnimateOptions(options) || {}; + options.from = to ? from : null; + options.to = to ? to : from; + + return runAnimationPostDigest(function(done) { + return performAnimation('animate', className, stripCommentsFromElement(element), null, null, noop, options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#enter + * @kind function + * + * @description + * Appends the element to the parentElement element that resides in the document and then runs the enter animation. Once + * the animation is started, the following CSS classes will be present on the element for the duration of the animation: + * + * Below is a breakdown of each step that occurs during enter animation: + * + * | Animation Step | What the element class attribute looks like | + * |-----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------| + * | 1. `$animate.enter(...)` is called | `class="my-animation"` | + * | 2. element is inserted into the `parentElement` element or beside the `afterElement` element | `class="my-animation"` | + * | 3. `$animate` waits for the next digest to start the animation | `class="my-animation ng-animate"` | + * | 4. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 5. the `.ng-enter` class is added to the element | `class="my-animation ng-animate ng-enter"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate ng-enter"` | + * | 7. `$animate` blocks all CSS transitions on the element to ensure the `.ng-enter` class styling is applied right away | `class="my-animation ng-animate ng-enter"` | + * | 8. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate ng-enter"` | + * | 9. `$animate` removes the CSS transition block placed on the element | `class="my-animation ng-animate ng-enter"` | + * | 10. the `.ng-enter-active` class is added (this triggers the CSS transition/animation) | `class="my-animation ng-animate ng-enter ng-enter-active"` | + * | 11. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate ng-enter ng-enter-active"` | + * | 12. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 13. The returned promise is resolved. | `class="my-animation"` | + * + * @param {DOMElement} element the element that will be the focus of the enter animation + * @param {DOMElement} parentElement the parent element of the element that will be the focus of the enter animation + * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation + * @param {object=} options an optional collection of options that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + enter: function(element, parentElement, afterElement, options) { + options = parseAnimateOptions(options); + element = angular.element(element); + parentElement = prepareElement(parentElement); + afterElement = prepareElement(afterElement); + + classBasedAnimationsBlocked(element, true); + $delegate.enter(element, parentElement, afterElement); + return runAnimationPostDigest(function(done) { + return performAnimation('enter', 'ng-enter', stripCommentsFromElement(element), parentElement, afterElement, noop, options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#leave + * @kind function + * + * @description + * Runs the leave animation operation and, upon completion, removes the element from the DOM. Once + * the animation is started, the following CSS classes will be added for the duration of the animation: + * + * Below is a breakdown of each step that occurs during leave animation: + * + * | Animation Step | What the element class attribute looks like | + * |-----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------| + * | 1. `$animate.leave(...)` is called | `class="my-animation"` | + * | 2. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 3. `$animate` waits for the next digest to start the animation | `class="my-animation ng-animate"` | + * | 4. the `.ng-leave` class is added to the element | `class="my-animation ng-animate ng-leave"` | + * | 5. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate ng-leave"` | + * | 6. `$animate` blocks all CSS transitions on the element to ensure the `.ng-leave` class styling is applied right away | `class="my-animation ng-animate ng-leave"` | + * | 7. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate ng-leave"` | + * | 8. `$animate` removes the CSS transition block placed on the element | `class="my-animation ng-animate ng-leave"` | + * | 9. the `.ng-leave-active` class is added (this triggers the CSS transition/animation) | `class="my-animation ng-animate ng-leave ng-leave-active"` | + * | 10. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate ng-leave ng-leave-active"` | + * | 11. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 12. The element is removed from the DOM | ... | + * | 13. The returned promise is resolved. | ... | + * + * @param {DOMElement} element the element that will be the focus of the leave animation + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + leave: function(element, options) { + options = parseAnimateOptions(options); + element = angular.element(element); + + cancelChildAnimations(element); + classBasedAnimationsBlocked(element, true); + return runAnimationPostDigest(function(done) { + return performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() { + $delegate.leave(element); + }, options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#move + * @kind function + * + * @description + * Fires the move DOM operation. Just before the animation starts, the animate service will either append it into the parentElement container or + * add the element directly after the afterElement element if present. Then the move animation will be run. Once + * the animation is started, the following CSS classes will be added for the duration of the animation: + * + * Below is a breakdown of each step that occurs during move animation: + * + * | Animation Step | What the element class attribute looks like | + * |----------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------| + * | 1. `$animate.move(...)` is called | `class="my-animation"` | + * | 2. element is moved into the parentElement element or beside the afterElement element | `class="my-animation"` | + * | 3. `$animate` waits for the next digest to start the animation | `class="my-animation ng-animate"` | + * | 4. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 5. the `.ng-move` class is added to the element | `class="my-animation ng-animate ng-move"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate ng-move"` | + * | 7. `$animate` blocks all CSS transitions on the element to ensure the `.ng-move` class styling is applied right away | `class="my-animation ng-animate ng-move"` | + * | 8. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate ng-move"` | + * | 9. `$animate` removes the CSS transition block placed on the element | `class="my-animation ng-animate ng-move"` | + * | 10. the `.ng-move-active` class is added (this triggers the CSS transition/animation) | `class="my-animation ng-animate ng-move ng-move-active"` | + * | 11. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate ng-move ng-move-active"` | + * | 12. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 13. The returned promise is resolved. | `class="my-animation"` | + * + * @param {DOMElement} element the element that will be the focus of the move animation + * @param {DOMElement} parentElement the parentElement element of the element that will be the focus of the move animation + * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + move: function(element, parentElement, afterElement, options) { + options = parseAnimateOptions(options); + element = angular.element(element); + parentElement = prepareElement(parentElement); + afterElement = prepareElement(afterElement); + + cancelChildAnimations(element); + classBasedAnimationsBlocked(element, true); + $delegate.move(element, parentElement, afterElement); + return runAnimationPostDigest(function(done) { + return performAnimation('move', 'ng-move', stripCommentsFromElement(element), parentElement, afterElement, noop, options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#addClass + * + * @description + * Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class. + * Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide + * the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions + * or keyframes are defined on the -add-active or base CSS class). + * + * Below is a breakdown of each step that occurs during addClass animation: + * + * | Animation Step | What the element class attribute looks like | + * |--------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------| + * | 1. `$animate.addClass(element, 'super')` is called | `class="my-animation"` | + * | 2. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 3. the `.super-add` class is added to the element | `class="my-animation ng-animate super-add"` | + * | 4. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate super-add"` | + * | 5. the `.super` and `.super-add-active` classes are added (this triggers the CSS transition/animation) | `class="my-animation ng-animate super super-add super-add-active"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate super super-add super-add-active"` | + * | 7. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate super super-add super-add-active"` | + * | 8. The animation ends and all generated CSS classes are removed from the element | `class="my-animation super"` | + * | 9. The super class is kept on the element | `class="my-animation super"` | + * | 10. The returned promise is resolved. | `class="my-animation super"` | + * + * @param {DOMElement} element the element that will be animated + * @param {string} className the CSS class that will be added to the element and then animated + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + addClass: function(element, className, options) { + return this.setClass(element, className, [], options); + }, + + /** + * @ngdoc method + * @name $animate#removeClass + * + * @description + * Triggers a custom animation event based off the className variable and then removes the CSS class provided by the className value + * from the element. Unlike the other animation methods, the animate service will suffix the className value with {@type -remove} in + * order to provide the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if + * no CSS transitions or keyframes are defined on the -remove or base CSS classes). + * + * Below is a breakdown of each step that occurs during removeClass animation: + * + * | Animation Step | What the element class attribute looks like | + * |----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------| + * | 1. `$animate.removeClass(element, 'super')` is called | `class="my-animation super"` | + * | 2. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation super ng-animate"` | + * | 3. the `.super-remove` class is added to the element | `class="my-animation super ng-animate super-remove"` | + * | 4. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation super ng-animate super-remove"` | + * | 5. the `.super-remove-active` classes are added and `.super` is removed (this triggers the CSS transition/animation) | `class="my-animation ng-animate super-remove super-remove-active"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate super-remove super-remove-active"` | + * | 7. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate super-remove super-remove-active"` | + * | 8. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 9. The returned promise is resolved. | `class="my-animation"` | + * + * + * @param {DOMElement} element the element that will be animated + * @param {string} className the CSS class that will be animated and then removed from the element + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + removeClass: function(element, className, options) { + return this.setClass(element, [], className, options); + }, + + /** + * + * @ngdoc method + * @name $animate#setClass + * + * @description Adds and/or removes the given CSS classes to and from the element. + * Once complete, the `done()` callback will be fired (if provided). + * + * | Animation Step | What the element class attribute looks like | + * |----------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------| + * | 1. `$animate.setClass(element, 'on', 'off')` is called | `class="my-animation off"` | + * | 2. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate off"` | + * | 3. the `.on-add` and `.off-remove` classes are added to the element | `class="my-animation ng-animate on-add off-remove off"` | + * | 4. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate on-add off-remove off"` | + * | 5. the `.on`, `.on-add-active` and `.off-remove-active` classes are added and `.off` is removed (this triggers the CSS transition/animation) | `class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active"` | + * | 7. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active"` | + * | 8. The animation ends and all generated CSS classes are removed from the element | `class="my-animation on"` | + * | 9. The returned promise is resolved. | `class="my-animation on"` | + * + * @param {DOMElement} element the element which will have its CSS classes changed + * removed from it + * @param {string} add the CSS classes which will be added to the element + * @param {string} remove the CSS class which will be removed from the element + * CSS classes have been set on the element + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + setClass: function(element, add, remove, options) { + options = parseAnimateOptions(options); + + var STORAGE_KEY = '$$animateClasses'; + element = angular.element(element); + element = stripCommentsFromElement(element); + + if (classBasedAnimationsBlocked(element)) { + return $delegate.$$setClassImmediately(element, add, remove, options); + } + + // we're using a combined array for both the add and remove + // operations since the ORDER OF addClass and removeClass matters + var classes, cache = element.data(STORAGE_KEY); + var hasCache = !!cache; + if (!cache) { + cache = {}; + cache.classes = {}; + } + classes = cache.classes; + + add = isArray(add) ? add : add.split(' '); + forEach(add, function(c) { + if (c && c.length) { + classes[c] = true; + } + }); + + remove = isArray(remove) ? remove : remove.split(' '); + forEach(remove, function(c) { + if (c && c.length) { + classes[c] = false; + } + }); + + if (hasCache) { + if (options && cache.options) { + cache.options = angular.extend(cache.options || {}, options); + } + + //the digest cycle will combine all the animations into one function + return cache.promise; + } else { + element.data(STORAGE_KEY, cache = { + classes: classes, + options: options + }); + } + + return cache.promise = runAnimationPostDigest(function(done) { + var parentElement = element.parent(); + var elementNode = extractElementNode(element); + var parentNode = elementNode.parentNode; + // TODO(matsko): move this code into the animationsDisabled() function once #8092 is fixed + if (!parentNode || parentNode['$$NG_REMOVED'] || elementNode['$$NG_REMOVED']) { + done(); + return; + } + + var cache = element.data(STORAGE_KEY); + element.removeData(STORAGE_KEY); + + var state = element.data(NG_ANIMATE_STATE) || {}; + var classes = resolveElementClasses(element, cache, state.active); + return !classes + ? done() + : performAnimation('setClass', classes, element, parentElement, null, function() { + if (classes[0]) $delegate.$$addClassImmediately(element, classes[0]); + if (classes[1]) $delegate.$$removeClassImmediately(element, classes[1]); + }, cache.options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#cancel + * @kind function + * + * @param {Promise} animationPromise The animation promise that is returned when an animation is started. + * + * @description + * Cancels the provided animation. + */ + cancel: function(promise) { + promise.$$cancelFn(); + }, + + /** + * @ngdoc method + * @name $animate#enabled + * @kind function + * + * @param {boolean=} value If provided then set the animation on or off. + * @param {DOMElement=} element If provided then the element will be used to represent the enable/disable operation + * @return {boolean} Current animation state. + * + * @description + * Globally enables/disables animations. + * + */ + enabled: function(value, element) { + switch (arguments.length) { + case 2: + if (value) { + cleanup(element); + } else { + var data = element.data(NG_ANIMATE_STATE) || {}; + data.disabled = true; + element.data(NG_ANIMATE_STATE, data); + } + break; + + case 1: + rootAnimateState.disabled = !value; + break; + + default: + value = !rootAnimateState.disabled; + break; + } + return !!value; + } + }; + + /* + all animations call this shared animation triggering function internally. + The animationEvent variable refers to the JavaScript animation event that will be triggered + and the className value is the name of the animation that will be applied within the + CSS code. Element, `parentElement` and `afterElement` are provided DOM elements for the animation + and the onComplete callback will be fired once the animation is fully complete. + */ + function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, options, doneCallback) { + var noopCancel = noop; + var runner = animationRunner(element, animationEvent, className, options); + if (!runner) { + fireDOMOperation(); + fireBeforeCallbackAsync(); + fireAfterCallbackAsync(); + closeAnimation(); + return noopCancel; + } + + animationEvent = runner.event; + className = runner.className; + var elementEvents = angular.element._data(runner.node); + elementEvents = elementEvents && elementEvents.events; + + if (!parentElement) { + parentElement = afterElement ? afterElement.parent() : element.parent(); + } + + //skip the animation if animations are disabled, a parent is already being animated, + //the element is not currently attached to the document body or then completely close + //the animation if any matching animations are not found at all. + //NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case an animation was found. + if (animationsDisabled(element, parentElement)) { + fireDOMOperation(); + fireBeforeCallbackAsync(); + fireAfterCallbackAsync(); + closeAnimation(); + return noopCancel; + } + + var ngAnimateState = element.data(NG_ANIMATE_STATE) || {}; + var runningAnimations = ngAnimateState.active || {}; + var totalActiveAnimations = ngAnimateState.totalActive || 0; + var lastAnimation = ngAnimateState.last; + var skipAnimation = false; + + if (totalActiveAnimations > 0) { + var animationsToCancel = []; + if (!runner.isClassBased) { + if (animationEvent == 'leave' && runningAnimations['ng-leave']) { + skipAnimation = true; + } else { + //cancel all animations when a structural animation takes place + for (var klass in runningAnimations) { + animationsToCancel.push(runningAnimations[klass]); + } + ngAnimateState = {}; + cleanup(element, true); + } + } else if (lastAnimation.event == 'setClass') { + animationsToCancel.push(lastAnimation); + cleanup(element, className); + } else if (runningAnimations[className]) { + var current = runningAnimations[className]; + if (current.event == animationEvent) { + skipAnimation = true; + } else { + animationsToCancel.push(current); + cleanup(element, className); + } + } + + if (animationsToCancel.length > 0) { + forEach(animationsToCancel, function(operation) { + operation.cancel(); + }); + } + } + + if (runner.isClassBased + && !runner.isSetClassOperation + && animationEvent != 'animate' + && !skipAnimation) { + skipAnimation = (animationEvent == 'addClass') == element.hasClass(className); //opposite of XOR + } + + if (skipAnimation) { + fireDOMOperation(); + fireBeforeCallbackAsync(); + fireAfterCallbackAsync(); + fireDoneCallbackAsync(); + return noopCancel; + } + + runningAnimations = ngAnimateState.active || {}; + totalActiveAnimations = ngAnimateState.totalActive || 0; + + if (animationEvent == 'leave') { + //there's no need to ever remove the listener since the element + //will be removed (destroyed) after the leave animation ends or + //is cancelled midway + element.one('$destroy', function(e) { + var element = angular.element(this); + var state = element.data(NG_ANIMATE_STATE); + if (state) { + var activeLeaveAnimation = state.active['ng-leave']; + if (activeLeaveAnimation) { + activeLeaveAnimation.cancel(); + cleanup(element, 'ng-leave'); + } + } + }); + } + + //the ng-animate class does nothing, but it's here to allow for + //parent animations to find and cancel child animations when needed + $$jqLite.addClass(element, NG_ANIMATE_CLASS_NAME); + if (options && options.tempClasses) { + forEach(options.tempClasses, function(className) { + $$jqLite.addClass(element, className); + }); + } + + var localAnimationCount = globalAnimationCounter++; + totalActiveAnimations++; + runningAnimations[className] = runner; + + element.data(NG_ANIMATE_STATE, { + last: runner, + active: runningAnimations, + index: localAnimationCount, + totalActive: totalActiveAnimations + }); + + //first we run the before animations and when all of those are complete + //then we perform the DOM operation and run the next set of animations + fireBeforeCallbackAsync(); + runner.before(function(cancelled) { + var data = element.data(NG_ANIMATE_STATE); + cancelled = cancelled || + !data || !data.active[className] || + (runner.isClassBased && data.active[className].event != animationEvent); + + fireDOMOperation(); + if (cancelled === true) { + closeAnimation(); + } else { + fireAfterCallbackAsync(); + runner.after(closeAnimation); + } + }); + + return runner.cancel; + + function fireDOMCallback(animationPhase) { + var eventName = '$animate:' + animationPhase; + if (elementEvents && elementEvents[eventName] && elementEvents[eventName].length > 0) { + $$asyncCallback(function() { + element.triggerHandler(eventName, { + event: animationEvent, + className: className + }); + }); + } + } + + function fireBeforeCallbackAsync() { + fireDOMCallback('before'); + } + + function fireAfterCallbackAsync() { + fireDOMCallback('after'); + } + + function fireDoneCallbackAsync() { + fireDOMCallback('close'); + doneCallback(); + } + + //it is less complicated to use a flag than managing and canceling + //timeouts containing multiple callbacks. + function fireDOMOperation() { + if (!fireDOMOperation.hasBeenRun) { + fireDOMOperation.hasBeenRun = true; + domOperation(); + } + } + + function closeAnimation() { + if (!closeAnimation.hasBeenRun) { + if (runner) { //the runner doesn't exist if it fails to instantiate + runner.applyStyles(); + } + + closeAnimation.hasBeenRun = true; + if (options && options.tempClasses) { + forEach(options.tempClasses, function(className) { + $$jqLite.removeClass(element, className); + }); + } + + var data = element.data(NG_ANIMATE_STATE); + if (data) { + + /* only structural animations wait for reflow before removing an + animation, but class-based animations don't. An example of this + failing would be when a parent HTML tag has a ng-class attribute + causing ALL directives below to skip animations during the digest */ + if (runner && runner.isClassBased) { + cleanup(element, className); + } else { + $$asyncCallback(function() { + var data = element.data(NG_ANIMATE_STATE) || {}; + if (localAnimationCount == data.index) { + cleanup(element, className, animationEvent); + } + }); + element.data(NG_ANIMATE_STATE, data); + } + } + fireDoneCallbackAsync(); + } + } + } + + function cancelChildAnimations(element) { + var node = extractElementNode(element); + if (node) { + var nodes = angular.isFunction(node.getElementsByClassName) ? + node.getElementsByClassName(NG_ANIMATE_CLASS_NAME) : + node.querySelectorAll('.' + NG_ANIMATE_CLASS_NAME); + forEach(nodes, function(element) { + element = angular.element(element); + var data = element.data(NG_ANIMATE_STATE); + if (data && data.active) { + forEach(data.active, function(runner) { + runner.cancel(); + }); + } + }); + } + } + + function cleanup(element, className) { + if (isMatchingElement(element, $rootElement)) { + if (!rootAnimateState.disabled) { + rootAnimateState.running = false; + rootAnimateState.structural = false; + } + } else if (className) { + var data = element.data(NG_ANIMATE_STATE) || {}; + + var removeAnimations = className === true; + if (!removeAnimations && data.active && data.active[className]) { + data.totalActive--; + delete data.active[className]; + } + + if (removeAnimations || !data.totalActive) { + $$jqLite.removeClass(element, NG_ANIMATE_CLASS_NAME); + element.removeData(NG_ANIMATE_STATE); + } + } + } + + function animationsDisabled(element, parentElement) { + if (rootAnimateState.disabled) { + return true; + } + + if (isMatchingElement(element, $rootElement)) { + return rootAnimateState.running; + } + + var allowChildAnimations, parentRunningAnimation, hasParent; + do { + //the element did not reach the root element which means that it + //is not apart of the DOM. Therefore there is no reason to do + //any animations on it + if (parentElement.length === 0) break; + + var isRoot = isMatchingElement(parentElement, $rootElement); + var state = isRoot ? rootAnimateState : (parentElement.data(NG_ANIMATE_STATE) || {}); + if (state.disabled) { + return true; + } + + //no matter what, for an animation to work it must reach the root element + //this implies that the element is attached to the DOM when the animation is run + if (isRoot) { + hasParent = true; + } + + //once a flag is found that is strictly false then everything before + //it will be discarded and all child animations will be restricted + if (allowChildAnimations !== false) { + var animateChildrenFlag = parentElement.data(NG_ANIMATE_CHILDREN); + if (angular.isDefined(animateChildrenFlag)) { + allowChildAnimations = animateChildrenFlag; + } + } + + parentRunningAnimation = parentRunningAnimation || + state.running || + (state.last && !state.last.isClassBased); + } + while (parentElement = parentElement.parent()); + + return !hasParent || (!allowChildAnimations && parentRunningAnimation); + } + }]); + + $animateProvider.register('', ['$window', '$sniffer', '$timeout', '$$animateReflow', + function($window, $sniffer, $timeout, $$animateReflow) { + // Detect proper transitionend/animationend event names. + var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT; + + // If unprefixed events are not supported but webkit-prefixed are, use the latter. + // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them. + // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend` + // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`. + // Register both events in case `window.onanimationend` is not supported because of that, + // do the same for `transitionend` as Safari is likely to exhibit similar behavior. + // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit + // therefore there is no reason to test anymore for other vendor prefixes: http://caniuse.com/#search=transition + if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) { + CSS_PREFIX = '-webkit-'; + TRANSITION_PROP = 'WebkitTransition'; + TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend'; + } else { + TRANSITION_PROP = 'transition'; + TRANSITIONEND_EVENT = 'transitionend'; + } + + if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) { + CSS_PREFIX = '-webkit-'; + ANIMATION_PROP = 'WebkitAnimation'; + ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend'; + } else { + ANIMATION_PROP = 'animation'; + ANIMATIONEND_EVENT = 'animationend'; + } + + var DURATION_KEY = 'Duration'; + var PROPERTY_KEY = 'Property'; + var DELAY_KEY = 'Delay'; + var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount'; + var ANIMATION_PLAYSTATE_KEY = 'PlayState'; + var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey'; + var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data'; + var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3; + var CLOSING_TIME_BUFFER = 1.5; + var ONE_SECOND = 1000; + + var lookupCache = {}; + var parentCounter = 0; + var animationReflowQueue = []; + var cancelAnimationReflow; + function clearCacheAfterReflow() { + if (!cancelAnimationReflow) { + cancelAnimationReflow = $$animateReflow(function() { + animationReflowQueue = []; + cancelAnimationReflow = null; + lookupCache = {}; + }); + } + } + + function afterReflow(element, callback) { + if (cancelAnimationReflow) { + cancelAnimationReflow(); + } + animationReflowQueue.push(callback); + cancelAnimationReflow = $$animateReflow(function() { + forEach(animationReflowQueue, function(fn) { + fn(); + }); + + animationReflowQueue = []; + cancelAnimationReflow = null; + lookupCache = {}; + }); + } + + var closingTimer = null; + var closingTimestamp = 0; + var animationElementQueue = []; + function animationCloseHandler(element, totalTime) { + var node = extractElementNode(element); + element = angular.element(node); + + //this item will be garbage collected by the closing + //animation timeout + animationElementQueue.push(element); + + //but it may not need to cancel out the existing timeout + //if the timestamp is less than the previous one + var futureTimestamp = Date.now() + totalTime; + if (futureTimestamp <= closingTimestamp) { + return; + } + + $timeout.cancel(closingTimer); + + closingTimestamp = futureTimestamp; + closingTimer = $timeout(function() { + closeAllAnimations(animationElementQueue); + animationElementQueue = []; + }, totalTime, false); + } + + function closeAllAnimations(elements) { + forEach(elements, function(element) { + var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY); + if (elementData) { + forEach(elementData.closeAnimationFns, function(fn) { + fn(); + }); + } + }); + } + + function getElementAnimationDetails(element, cacheKey) { + var data = cacheKey ? lookupCache[cacheKey] : null; + if (!data) { + var transitionDuration = 0; + var transitionDelay = 0; + var animationDuration = 0; + var animationDelay = 0; + + //we want all the styles defined before and after + forEach(element, function(element) { + if (element.nodeType == ELEMENT_NODE) { + var elementStyles = $window.getComputedStyle(element) || {}; + + var transitionDurationStyle = elementStyles[TRANSITION_PROP + DURATION_KEY]; + transitionDuration = Math.max(parseMaxTime(transitionDurationStyle), transitionDuration); + + var transitionDelayStyle = elementStyles[TRANSITION_PROP + DELAY_KEY]; + transitionDelay = Math.max(parseMaxTime(transitionDelayStyle), transitionDelay); + + var animationDelayStyle = elementStyles[ANIMATION_PROP + DELAY_KEY]; + animationDelay = Math.max(parseMaxTime(elementStyles[ANIMATION_PROP + DELAY_KEY]), animationDelay); + + var aDuration = parseMaxTime(elementStyles[ANIMATION_PROP + DURATION_KEY]); + + if (aDuration > 0) { + aDuration *= parseInt(elementStyles[ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY], 10) || 1; + } + animationDuration = Math.max(aDuration, animationDuration); + } + }); + data = { + total: 0, + transitionDelay: transitionDelay, + transitionDuration: transitionDuration, + animationDelay: animationDelay, + animationDuration: animationDuration + }; + if (cacheKey) { + lookupCache[cacheKey] = data; + } + } + return data; + } + + function parseMaxTime(str) { + var maxValue = 0; + var values = isString(str) ? + str.split(/\s*,\s*/) : + []; + forEach(values, function(value) { + maxValue = Math.max(parseFloat(value) || 0, maxValue); + }); + return maxValue; + } + + function getCacheKey(element) { + var parentElement = element.parent(); + var parentID = parentElement.data(NG_ANIMATE_PARENT_KEY); + if (!parentID) { + parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter); + parentID = parentCounter; + } + return parentID + '-' + extractElementNode(element).getAttribute('class'); + } + + function animateSetup(animationEvent, element, className, styles) { + var structural = ['ng-enter','ng-leave','ng-move'].indexOf(className) >= 0; + + var cacheKey = getCacheKey(element); + var eventCacheKey = cacheKey + ' ' + className; + var itemIndex = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0; + + var stagger = {}; + if (itemIndex > 0) { + var staggerClassName = className + '-stagger'; + var staggerCacheKey = cacheKey + ' ' + staggerClassName; + var applyClasses = !lookupCache[staggerCacheKey]; + + applyClasses && $$jqLite.addClass(element, staggerClassName); + + stagger = getElementAnimationDetails(element, staggerCacheKey); + + applyClasses && $$jqLite.removeClass(element, staggerClassName); + } + + $$jqLite.addClass(element, className); + + var formerData = element.data(NG_ANIMATE_CSS_DATA_KEY) || {}; + var timings = getElementAnimationDetails(element, eventCacheKey); + var transitionDuration = timings.transitionDuration; + var animationDuration = timings.animationDuration; + + if (structural && transitionDuration === 0 && animationDuration === 0) { + $$jqLite.removeClass(element, className); + return false; + } + + var blockTransition = styles || (structural && transitionDuration > 0); + var blockAnimation = animationDuration > 0 && + stagger.animationDelay > 0 && + stagger.animationDuration === 0; + + var closeAnimationFns = formerData.closeAnimationFns || []; + element.data(NG_ANIMATE_CSS_DATA_KEY, { + stagger: stagger, + cacheKey: eventCacheKey, + running: formerData.running || 0, + itemIndex: itemIndex, + blockTransition: blockTransition, + closeAnimationFns: closeAnimationFns + }); + + var node = extractElementNode(element); + + if (blockTransition) { + blockTransitions(node, true); + if (styles) { + element.css(styles); + } + } + + if (blockAnimation) { + blockAnimations(node, true); + } + + return true; + } + + function animateRun(animationEvent, element, className, activeAnimationComplete, styles) { + var node = extractElementNode(element); + var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY); + if (node.getAttribute('class').indexOf(className) == -1 || !elementData) { + activeAnimationComplete(); + return; + } + + var activeClassName = ''; + var pendingClassName = ''; + forEach(className.split(' '), function(klass, i) { + var prefix = (i > 0 ? ' ' : '') + klass; + activeClassName += prefix + '-active'; + pendingClassName += prefix + '-pending'; + }); + + var style = ''; + var appliedStyles = []; + var itemIndex = elementData.itemIndex; + var stagger = elementData.stagger; + var staggerTime = 0; + if (itemIndex > 0) { + var transitionStaggerDelay = 0; + if (stagger.transitionDelay > 0 && stagger.transitionDuration === 0) { + transitionStaggerDelay = stagger.transitionDelay * itemIndex; + } + + var animationStaggerDelay = 0; + if (stagger.animationDelay > 0 && stagger.animationDuration === 0) { + animationStaggerDelay = stagger.animationDelay * itemIndex; + appliedStyles.push(CSS_PREFIX + 'animation-play-state'); + } + + staggerTime = Math.round(Math.max(transitionStaggerDelay, animationStaggerDelay) * 100) / 100; + } + + if (!staggerTime) { + $$jqLite.addClass(element, activeClassName); + if (elementData.blockTransition) { + blockTransitions(node, false); + } + } + + var eventCacheKey = elementData.cacheKey + ' ' + activeClassName; + var timings = getElementAnimationDetails(element, eventCacheKey); + var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration); + if (maxDuration === 0) { + $$jqLite.removeClass(element, activeClassName); + animateClose(element, className); + activeAnimationComplete(); + return; + } + + if (!staggerTime && styles && Object.keys(styles).length > 0) { + if (!timings.transitionDuration) { + element.css('transition', timings.animationDuration + 's linear all'); + appliedStyles.push('transition'); + } + element.css(styles); + } + + var maxDelay = Math.max(timings.transitionDelay, timings.animationDelay); + var maxDelayTime = maxDelay * ONE_SECOND; + + if (appliedStyles.length > 0) { + //the element being animated may sometimes contain comment nodes in + //the jqLite object, so we're safe to use a single variable to house + //the styles since there is always only one element being animated + var oldStyle = node.getAttribute('style') || ''; + if (oldStyle.charAt(oldStyle.length - 1) !== ';') { + oldStyle += ';'; + } + node.setAttribute('style', oldStyle + ' ' + style); + } + + var startTime = Date.now(); + var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT; + var animationTime = (maxDelay + maxDuration) * CLOSING_TIME_BUFFER; + var totalTime = (staggerTime + animationTime) * ONE_SECOND; + + var staggerTimeout; + if (staggerTime > 0) { + $$jqLite.addClass(element, pendingClassName); + staggerTimeout = $timeout(function() { + staggerTimeout = null; + + if (timings.transitionDuration > 0) { + blockTransitions(node, false); + } + if (timings.animationDuration > 0) { + blockAnimations(node, false); + } + + $$jqLite.addClass(element, activeClassName); + $$jqLite.removeClass(element, pendingClassName); + + if (styles) { + if (timings.transitionDuration === 0) { + element.css('transition', timings.animationDuration + 's linear all'); + } + element.css(styles); + appliedStyles.push('transition'); + } + }, staggerTime * ONE_SECOND, false); + } + + element.on(css3AnimationEvents, onAnimationProgress); + elementData.closeAnimationFns.push(function() { + onEnd(); + activeAnimationComplete(); + }); + + elementData.running++; + animationCloseHandler(element, totalTime); + return onEnd; + + // This will automatically be called by $animate so + // there is no need to attach this internally to the + // timeout done method. + function onEnd() { + element.off(css3AnimationEvents, onAnimationProgress); + $$jqLite.removeClass(element, activeClassName); + $$jqLite.removeClass(element, pendingClassName); + if (staggerTimeout) { + $timeout.cancel(staggerTimeout); + } + animateClose(element, className); + var node = extractElementNode(element); + for (var i in appliedStyles) { + node.style.removeProperty(appliedStyles[i]); + } + } + + function onAnimationProgress(event) { + event.stopPropagation(); + var ev = event.originalEvent || event; + var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now(); + + /* Firefox (or possibly just Gecko) likes to not round values up + * when a ms measurement is used for the animation */ + var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES)); + + /* $manualTimeStamp is a mocked timeStamp value which is set + * within browserTrigger(). This is only here so that tests can + * mock animations properly. Real events fallback to event.timeStamp, + * or, if they don't, then a timeStamp is automatically created for them. + * We're checking to see if the timeStamp surpasses the expected delay, + * but we're using elapsedTime instead of the timeStamp on the 2nd + * pre-condition since animations sometimes close off early */ + if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) { + activeAnimationComplete(); + } + } + } + + function blockTransitions(node, bool) { + node.style[TRANSITION_PROP + PROPERTY_KEY] = bool ? 'none' : ''; + } + + function blockAnimations(node, bool) { + node.style[ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY] = bool ? 'paused' : ''; + } + + function animateBefore(animationEvent, element, className, styles) { + if (animateSetup(animationEvent, element, className, styles)) { + return function(cancelled) { + cancelled && animateClose(element, className); + }; + } + } + + function animateAfter(animationEvent, element, className, afterAnimationComplete, styles) { + if (element.data(NG_ANIMATE_CSS_DATA_KEY)) { + return animateRun(animationEvent, element, className, afterAnimationComplete, styles); + } else { + animateClose(element, className); + afterAnimationComplete(); + } + } + + function animate(animationEvent, element, className, animationComplete, options) { + //If the animateSetup function doesn't bother returning a + //cancellation function then it means that there is no animation + //to perform at all + var preReflowCancellation = animateBefore(animationEvent, element, className, options.from); + if (!preReflowCancellation) { + clearCacheAfterReflow(); + animationComplete(); + return; + } + + //There are two cancellation functions: one is before the first + //reflow animation and the second is during the active state + //animation. The first function will take care of removing the + //data from the element which will not make the 2nd animation + //happen in the first place + var cancel = preReflowCancellation; + afterReflow(element, function() { + //once the reflow is complete then we point cancel to + //the new cancellation function which will remove all of the + //animation properties from the active animation + cancel = animateAfter(animationEvent, element, className, animationComplete, options.to); + }); + + return function(cancelled) { + (cancel || noop)(cancelled); + }; + } + + function animateClose(element, className) { + $$jqLite.removeClass(element, className); + var data = element.data(NG_ANIMATE_CSS_DATA_KEY); + if (data) { + if (data.running) { + data.running--; + } + if (!data.running || data.running === 0) { + element.removeData(NG_ANIMATE_CSS_DATA_KEY); + } + } + } + + return { + animate: function(element, className, from, to, animationCompleted, options) { + options = options || {}; + options.from = from; + options.to = to; + return animate('animate', element, className, animationCompleted, options); + }, + + enter: function(element, animationCompleted, options) { + options = options || {}; + return animate('enter', element, 'ng-enter', animationCompleted, options); + }, + + leave: function(element, animationCompleted, options) { + options = options || {}; + return animate('leave', element, 'ng-leave', animationCompleted, options); + }, + + move: function(element, animationCompleted, options) { + options = options || {}; + return animate('move', element, 'ng-move', animationCompleted, options); + }, + + beforeSetClass: function(element, add, remove, animationCompleted, options) { + options = options || {}; + var className = suffixClasses(remove, '-remove') + ' ' + + suffixClasses(add, '-add'); + var cancellationMethod = animateBefore('setClass', element, className, options.from); + if (cancellationMethod) { + afterReflow(element, animationCompleted); + return cancellationMethod; + } + clearCacheAfterReflow(); + animationCompleted(); + }, + + beforeAddClass: function(element, className, animationCompleted, options) { + options = options || {}; + var cancellationMethod = animateBefore('addClass', element, suffixClasses(className, '-add'), options.from); + if (cancellationMethod) { + afterReflow(element, animationCompleted); + return cancellationMethod; + } + clearCacheAfterReflow(); + animationCompleted(); + }, + + beforeRemoveClass: function(element, className, animationCompleted, options) { + options = options || {}; + var cancellationMethod = animateBefore('removeClass', element, suffixClasses(className, '-remove'), options.from); + if (cancellationMethod) { + afterReflow(element, animationCompleted); + return cancellationMethod; + } + clearCacheAfterReflow(); + animationCompleted(); + }, + + setClass: function(element, add, remove, animationCompleted, options) { + options = options || {}; + remove = suffixClasses(remove, '-remove'); + add = suffixClasses(add, '-add'); + var className = remove + ' ' + add; + return animateAfter('setClass', element, className, animationCompleted, options.to); + }, + + addClass: function(element, className, animationCompleted, options) { + options = options || {}; + return animateAfter('addClass', element, suffixClasses(className, '-add'), animationCompleted, options.to); + }, + + removeClass: function(element, className, animationCompleted, options) { + options = options || {}; + return animateAfter('removeClass', element, suffixClasses(className, '-remove'), animationCompleted, options.to); + } + }; + + function suffixClasses(classes, suffix) { + var className = ''; + classes = isArray(classes) ? classes : classes.split(/\s+/); + forEach(classes, function(klass, i) { + if (klass && klass.length > 0) { + className += (i > 0 ? ' ' : '') + klass + suffix; + } + }); + return className; + } + }]); + }]); + + +})(window, window.angular); diff --git a/dependencies/angular-sanitize.js b/dependencies/angular-sanitize.js new file mode 100644 index 00000000..d0366949 --- /dev/null +++ b/dependencies/angular-sanitize.js @@ -0,0 +1,680 @@ +/** + * @license AngularJS v1.3.12 + * (c) 2010-2014 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, angular, undefined) {'use strict'; + +var $sanitizeMinErr = angular.$$minErr('$sanitize'); + +/** + * @ngdoc module + * @name ngSanitize + * @description + * + * # ngSanitize + * + * The `ngSanitize` module provides functionality to sanitize HTML. + * + * + *
+ * + * See {@link ngSanitize.$sanitize `$sanitize`} for usage. + */ + +/* + * HTML Parser By Misko Hevery (misko@hevery.com) + * based on: HTML Parser By John Resig (ejohn.org) + * Original code by Erik Arvidsson, Mozilla Public License + * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js + * + * // Use like so: + * htmlParser(htmlString, { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * }); + * + */ + + +/** + * @ngdoc service + * @name $sanitize + * @kind function + * + * @description + * The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are + * then serialized back to properly escaped html string. This means that no unsafe input can make + * it into the returned string, however, since our parser is more strict than a typical browser + * parser, it's possible that some obscure input, which would be recognized as valid HTML by a + * browser, won't make it through the sanitizer. The input may also contain SVG markup. + * The whitelist is configured using the functions `aHrefSanitizationWhitelist` and + * `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}. + * + * @param {string} html HTML input. + * @returns {string} Sanitized HTML. + * + * @example + + + +
+ Snippet: + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectiveHowSourceRendered
ng-bind-htmlAutomatically uses $sanitize
<div ng-bind-html="snippet">
</div>
ng-bind-htmlBypass $sanitize by explicitly trusting the dangerous value +
<div ng-bind-html="deliberatelyTrustDangerousSnippet()">
+</div>
+
ng-bindAutomatically escapes
<div ng-bind="snippet">
</div>
+
+
+ + it('should sanitize the html snippet by default', function() { + expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). + toBe('

an html\nclick here\nsnippet

'); + }); + + it('should inline raw snippet if bound to a trusted value', function() { + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()). + toBe("

an html\n" + + "click here\n" + + "snippet

"); + }); + + it('should escape snippet without any filter', function() { + expect(element(by.css('#bind-default div')).getInnerHtml()). + toBe("<p style=\"color:blue\">an html\n" + + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + + "snippet</p>"); + }); + + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new text'); + expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). + toBe('new text'); + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe( + 'new text'); + expect(element(by.css('#bind-default div')).getInnerHtml()).toBe( + "new <b onclick=\"alert(1)\">text</b>"); + }); +
+
+ */ +function $SanitizeProvider() { + this.$get = ['$$sanitizeUri', function($$sanitizeUri) { + return function(html) { + var buf = []; + htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) { + return !/^unsafe/.test($$sanitizeUri(uri, isImage)); + })); + return buf.join(''); + }; + }]; +} + +function sanitizeText(chars) { + var buf = []; + var writer = htmlSanitizeWriter(buf, angular.noop); + writer.chars(chars); + return buf.join(''); +} + + +// Regular Expressions for parsing tags and attributes +var START_TAG_REGEXP = + /^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/, + END_TAG_REGEXP = /^<\/\s*([\w:-]+)[^>]*>/, + ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, + BEGIN_TAG_REGEXP = /^/g, + DOCTYPE_REGEXP = /]*?)>/i, + CDATA_REGEXP = //g, + SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, + // Match everything outside of normal chars and " (quote character) + NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; + + +// Good source of info about elements and attributes +// http://dev.w3.org/html5/spec/Overview.html#semantics +// http://simon.html5.org/html-elements + +// Safe Void Elements - HTML5 +// http://dev.w3.org/html5/spec/Overview.html#void-elements +var voidElements = makeMap("area,br,col,hr,img,wbr"); + +// Elements that you can, intentionally, leave open (and which close themselves) +// http://dev.w3.org/html5/spec/Overview.html#optional-tags +var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"), + optionalEndTagInlineElements = makeMap("rp,rt"), + optionalEndTagElements = angular.extend({}, + optionalEndTagInlineElements, + optionalEndTagBlockElements); + +// Safe Block Elements - HTML5 +var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," + + "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," + + "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")); + +// Inline Elements - HTML5 +var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," + + "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," + + "samp,small,span,strike,strong,sub,sup,time,tt,u,var")); + +// SVG Elements +// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements +var svgElements = makeMap("animate,animateColor,animateMotion,animateTransform,circle,defs," + + "desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient," + + "line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,set," + + "stop,svg,switch,text,title,tspan,use"); + +// Special Elements (can contain anything) +var specialElements = makeMap("script,style"); + +var validElements = angular.extend({}, + voidElements, + blockElements, + inlineElements, + optionalEndTagElements, + svgElements); + +//Attributes that have href and hence need to be sanitized +var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap,xlink:href"); + +var htmlAttrs = makeMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' + + 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' + + 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' + + 'scope,scrolling,shape,size,span,start,summary,target,title,type,' + + 'valign,value,vspace,width'); + +// SVG attributes (without "id" and "name" attributes) +// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes +var svgAttrs = makeMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' + + 'attributeName,attributeType,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,' + + 'color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,' + + 'font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,' + + 'gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,' + + 'keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,' + + 'markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,' + + 'overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,' + + 'repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,' + + 'stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,' + + 'stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,' + + 'stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,' + + 'underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,' + + 'viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,' + + 'xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,' + + 'zoomAndPan'); + +var validAttrs = angular.extend({}, + uriAttrs, + svgAttrs, + htmlAttrs); + +function makeMap(str) { + var obj = {}, items = str.split(','), i; + for (i = 0; i < items.length; i++) obj[items[i]] = true; + return obj; +} + + +/** + * @example + * htmlParser(htmlString, { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * }); + * + * @param {string} html string + * @param {object} handler + */ +function htmlParser(html, handler) { + if (typeof html !== 'string') { + if (html === null || typeof html === 'undefined') { + html = ''; + } else { + html = '' + html; + } + } + var index, chars, match, stack = [], last = html, text; + stack.last = function() { return stack[stack.length - 1]; }; + + while (html) { + text = ''; + chars = true; + + // Make sure we're not in a script or style element + if (!stack.last() || !specialElements[stack.last()]) { + + // Comment + if (html.indexOf("", index) === index) { + if (handler.comment) handler.comment(html.substring(4, index)); + html = html.substring(index + 3); + chars = false; + } + // DOCTYPE + } else if (DOCTYPE_REGEXP.test(html)) { + match = html.match(DOCTYPE_REGEXP); + + if (match) { + html = html.replace(match[0], ''); + chars = false; + } + // end tag + } else if (BEGING_END_TAGE_REGEXP.test(html)) { + match = html.match(END_TAG_REGEXP); + + if (match) { + html = html.substring(match[0].length); + match[0].replace(END_TAG_REGEXP, parseEndTag); + chars = false; + } + + // start tag + } else if (BEGIN_TAG_REGEXP.test(html)) { + match = html.match(START_TAG_REGEXP); + + if (match) { + // We only have a valid start-tag if there is a '>'. + if (match[4]) { + html = html.substring(match[0].length); + match[0].replace(START_TAG_REGEXP, parseStartTag); + } + chars = false; + } else { + // no ending tag found --- this piece should be encoded as an entity. + text += '<'; + html = html.substring(1); + } + } + + if (chars) { + index = html.indexOf("<"); + + text += index < 0 ? html : html.substring(0, index); + html = index < 0 ? "" : html.substring(index); + + if (handler.chars) handler.chars(decodeEntities(text)); + } + + } else { + html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'), + function(all, text) { + text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1"); + + if (handler.chars) handler.chars(decodeEntities(text)); + + return ""; + }); + + parseEndTag("", stack.last()); + } + + if (html == last) { + throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " + + "of html: {0}", html); + } + last = html; + } + + // Clean up any remaining tags + parseEndTag(); + + function parseStartTag(tag, tagName, rest, unary) { + tagName = angular.lowercase(tagName); + if (blockElements[tagName]) { + while (stack.last() && inlineElements[stack.last()]) { + parseEndTag("", stack.last()); + } + } + + if (optionalEndTagElements[tagName] && stack.last() == tagName) { + parseEndTag("", tagName); + } + + unary = voidElements[tagName] || !!unary; + + if (!unary) + stack.push(tagName); + + var attrs = {}; + + rest.replace(ATTR_REGEXP, + function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) { + var value = doubleQuotedValue + || singleQuotedValue + || unquotedValue + || ''; + + attrs[name] = decodeEntities(value); + }); + if (handler.start) handler.start(tagName, attrs, unary); + } + + function parseEndTag(tag, tagName) { + var pos = 0, i; + tagName = angular.lowercase(tagName); + if (tagName) + // Find the closest opened tag of the same type + for (pos = stack.length - 1; pos >= 0; pos--) + if (stack[pos] == tagName) + break; + + if (pos >= 0) { + // Close all the open elements, up the stack + for (i = stack.length - 1; i >= pos; i--) + if (handler.end) handler.end(stack[i]); + + // Remove the open elements from the stack + stack.length = pos; + } + } +} + +var hiddenPre=document.createElement("pre"); +var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/; +/** + * decodes all entities into regular string + * @param value + * @returns {string} A string with decoded entities. + */ +function decodeEntities(value) { + if (!value) { return ''; } + + // Note: IE8 does not preserve spaces at the start/end of innerHTML + // so we must capture them and reattach them afterward + var parts = spaceRe.exec(value); + var spaceBefore = parts[1]; + var spaceAfter = parts[3]; + var content = parts[2]; + if (content) { + hiddenPre.innerHTML=content.replace(//g, '>'); +} + +/** + * create an HTML/XML writer which writes to buffer + * @param {Array} buf use buf.jain('') to get out sanitized html string + * @returns {object} in the form of { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * } + */ +function htmlSanitizeWriter(buf, uriValidator) { + var ignore = false; + var out = angular.bind(buf, buf.push); + return { + start: function(tag, attrs, unary) { + tag = angular.lowercase(tag); + if (!ignore && specialElements[tag]) { + ignore = tag; + } + if (!ignore && validElements[tag] === true) { + out('<'); + out(tag); + angular.forEach(attrs, function(value, key) { + var lkey=angular.lowercase(key); + var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background'); + if (validAttrs[lkey] === true && + (uriAttrs[lkey] !== true || uriValidator(value, isImage))) { + out(' '); + out(key); + out('="'); + out(encodeEntities(value)); + out('"'); + } + }); + out(unary ? '/>' : '>'); + } + }, + end: function(tag) { + tag = angular.lowercase(tag); + if (!ignore && validElements[tag] === true) { + out(''); + } + if (tag == ignore) { + ignore = false; + } + }, + chars: function(chars) { + if (!ignore) { + out(encodeEntities(chars)); + } + } + }; +} + + +// define ngSanitize module and register $sanitize service +angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider); + +/* global sanitizeText: false */ + +/** + * @ngdoc filter + * @name linky + * @kind function + * + * @description + * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and + * plain email address links. + * + * Requires the {@link ngSanitize `ngSanitize`} module to be installed. + * + * @param {string} text Input text. + * @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in. + * @returns {string} Html-linkified text. + * + * @usage + + * + * @example + + + +
+ Snippet: + + + + + + + + + + + + + + + + + + + + + +
FilterSourceRendered
linky filter +
<div ng-bind-html="snippet | linky">
</div>
+
+
+
linky target +
<div ng-bind-html="snippetWithTarget | linky:'_blank'">
</div>
+
+
+
no filter
<div ng-bind="snippet">
</div>
+ + + it('should linkify the snippet with urls', function() { + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(4); + }); + + it('should not linkify snippet without the linky filter', function() { + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#escaped-html a')).count()).toEqual(0); + }); + + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new http://link.'); + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('new http://link.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(1); + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()) + .toBe('new http://link.'); + }); + + it('should work with the target property', function() { + expect(element(by.id('linky-target')). + element(by.binding("snippetWithTarget | linky:'_blank'")).getText()). + toBe('http://angularjs.org/'); + expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank'); + }); + + + */ +angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { + var LINKY_URL_REGEXP = + /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"”’]/, + MAILTO_REGEXP = /^mailto:/; + + return function(text, target) { + if (!text) return text; + var match; + var raw = text; + var html = []; + var url; + var i; + while ((match = raw.match(LINKY_URL_REGEXP))) { + // We can not end in these as they are sometimes found at the end of the sentence + url = match[0]; + // if we did not match ftp/http/www/mailto then assume mailto + if (!match[2] && !match[4]) { + url = (match[3] ? 'http://' : 'mailto:') + url; + } + i = match.index; + addText(raw.substr(0, i)); + addLink(url, match[0].replace(MAILTO_REGEXP, '')); + raw = raw.substring(i + match[0].length); + } + addText(raw); + return $sanitize(html.join('')); + + function addText(text) { + if (!text) { + return; + } + html.push(sanitizeText(text)); + } + + function addLink(url, text) { + html.push(''); + addText(text); + html.push(''); + } + }; +}]); + + +})(window, window.angular); diff --git a/ionic-override.css b/ionic-override.css deleted file mode 100644 index 9ea8a56f..00000000 --- a/ionic-override.css +++ /dev/null @@ -1,6 +0,0 @@ -@font-face { - font-family: "Ionicons"; - src: url("/packages/urigo_ionic/packages/bower/ionic/release/fonts/ionicons.eot"); - src: url("/packages/urigo_ionic/packages/bower/ionic/release/fonts/ionicons.eot?v=1.5.2") format("embedded-opentype"), url("/packages/urigo_ionic/packages/bower/ionic/release/fonts/ionicons.ttf") format("truetype"), url("/packages/urigo_ionic/packages/bower/ionic/release/fonts/ionicons.woff") format("woff"), url("/packages/urigo_ionic/packages/bower/ionic/release/fonts/ionicons.svg") format("svg"); - font-weight: normal; - font-style: normal; } \ No newline at end of file diff --git a/lib/css/ionic.css b/lib/css/ionic.css new file mode 100755 index 00000000..49207090 --- /dev/null +++ b/lib/css/ionic.css @@ -0,0 +1,7013 @@ +/*! + * Copyright 2014 Drifty Co. + * http://drifty.com/ + * + * Ionic, v1.0.0-beta.14 + * A powerful HTML5 mobile app framework. + * http://ionicframework.com/ + * + * By @maxlynch, @benjsperry, @adamdbradley <3 + * + * Licensed under the MIT license. Please see LICENSE for more information. + * + */ +/*! + Ionicons, v1.5.2 + Created by Ben Sperry for the Ionic Framework, http://ionicons.com/ + https://twitter.com/benjsperry https://twitter.com/ionicframework + MIT License: https://github.com/driftyco/ionicons +*/ +@font-face { + font-family: "Ionicons"; + src: url("../fonts/ionicons.eot?v=1.5.2"); + src: url("../fonts/ionicons.eot?v=1.5.2#iefix") format("embedded-opentype"), url("../fonts/ionicons.ttf?v=1.5.2") format("truetype"), url("../fonts/ionicons.woff?v=1.5.2") format("woff"), url("../fonts/ionicons.svg?v=1.5.2#Ionicons") format("svg"); + font-weight: normal; + font-style: normal; } + +.ion, .ion-loading-a, .ion-loading-b, .ion-loading-c, .ion-loading-d, .ion-looping, .ion-refreshing, .ion-ios7-reloading, .ionicons, .ion-alert:before, .ion-alert-circled:before, .ion-android-add:before, .ion-android-add-contact:before, .ion-android-alarm:before, .ion-android-archive:before, .ion-android-arrow-back:before, .ion-android-arrow-down-left:before, .ion-android-arrow-down-right:before, .ion-android-arrow-forward:before, .ion-android-arrow-up-left:before, .ion-android-arrow-up-right:before, .ion-android-battery:before, .ion-android-book:before, .ion-android-calendar:before, .ion-android-call:before, .ion-android-camera:before, .ion-android-chat:before, .ion-android-checkmark:before, .ion-android-clock:before, .ion-android-close:before, .ion-android-contact:before, .ion-android-contacts:before, .ion-android-data:before, .ion-android-developer:before, .ion-android-display:before, .ion-android-download:before, .ion-android-drawer:before, .ion-android-dropdown:before, .ion-android-earth:before, .ion-android-folder:before, .ion-android-forums:before, .ion-android-friends:before, .ion-android-hand:before, .ion-android-image:before, .ion-android-inbox:before, .ion-android-information:before, .ion-android-keypad:before, .ion-android-lightbulb:before, .ion-android-locate:before, .ion-android-location:before, .ion-android-mail:before, .ion-android-microphone:before, .ion-android-mixer:before, .ion-android-more:before, .ion-android-note:before, .ion-android-playstore:before, .ion-android-printer:before, .ion-android-promotion:before, .ion-android-reminder:before, .ion-android-remove:before, .ion-android-search:before, .ion-android-send:before, .ion-android-settings:before, .ion-android-share:before, .ion-android-social:before, .ion-android-social-user:before, .ion-android-sort:before, .ion-android-stair-drawer:before, .ion-android-star:before, .ion-android-stopwatch:before, .ion-android-storage:before, .ion-android-system-back:before, .ion-android-system-home:before, .ion-android-system-windows:before, .ion-android-timer:before, .ion-android-trash:before, .ion-android-user-menu:before, .ion-android-volume:before, .ion-android-wifi:before, .ion-aperture:before, .ion-archive:before, .ion-arrow-down-a:before, .ion-arrow-down-b:before, .ion-arrow-down-c:before, .ion-arrow-expand:before, .ion-arrow-graph-down-left:before, .ion-arrow-graph-down-right:before, .ion-arrow-graph-up-left:before, .ion-arrow-graph-up-right:before, .ion-arrow-left-a:before, .ion-arrow-left-b:before, .ion-arrow-left-c:before, .ion-arrow-move:before, .ion-arrow-resize:before, .ion-arrow-return-left:before, .ion-arrow-return-right:before, .ion-arrow-right-a:before, .ion-arrow-right-b:before, .ion-arrow-right-c:before, .ion-arrow-shrink:before, .ion-arrow-swap:before, .ion-arrow-up-a:before, .ion-arrow-up-b:before, .ion-arrow-up-c:before, .ion-asterisk:before, .ion-at:before, .ion-bag:before, .ion-battery-charging:before, .ion-battery-empty:before, .ion-battery-full:before, .ion-battery-half:before, .ion-battery-low:before, .ion-beaker:before, .ion-beer:before, .ion-bluetooth:before, .ion-bonfire:before, .ion-bookmark:before, .ion-briefcase:before, .ion-bug:before, .ion-calculator:before, .ion-calendar:before, .ion-camera:before, .ion-card:before, .ion-cash:before, .ion-chatbox:before, .ion-chatbox-working:before, .ion-chatboxes:before, .ion-chatbubble:before, .ion-chatbubble-working:before, .ion-chatbubbles:before, .ion-checkmark:before, .ion-checkmark-circled:before, .ion-checkmark-round:before, .ion-chevron-down:before, .ion-chevron-left:before, .ion-chevron-right:before, .ion-chevron-up:before, .ion-clipboard:before, .ion-clock:before, .ion-close:before, .ion-close-circled:before, .ion-close-round:before, .ion-closed-captioning:before, .ion-cloud:before, .ion-code:before, .ion-code-download:before, .ion-code-working:before, .ion-coffee:before, .ion-compass:before, .ion-compose:before, .ion-connection-bars:before, .ion-contrast:before, .ion-cube:before, .ion-disc:before, .ion-document:before, .ion-document-text:before, .ion-drag:before, .ion-earth:before, .ion-edit:before, .ion-egg:before, .ion-eject:before, .ion-email:before, .ion-eye:before, .ion-eye-disabled:before, .ion-female:before, .ion-filing:before, .ion-film-marker:before, .ion-fireball:before, .ion-flag:before, .ion-flame:before, .ion-flash:before, .ion-flash-off:before, .ion-flask:before, .ion-folder:before, .ion-fork:before, .ion-fork-repo:before, .ion-forward:before, .ion-funnel:before, .ion-game-controller-a:before, .ion-game-controller-b:before, .ion-gear-a:before, .ion-gear-b:before, .ion-grid:before, .ion-hammer:before, .ion-happy:before, .ion-headphone:before, .ion-heart:before, .ion-heart-broken:before, .ion-help:before, .ion-help-buoy:before, .ion-help-circled:before, .ion-home:before, .ion-icecream:before, .ion-icon-social-google-plus:before, .ion-icon-social-google-plus-outline:before, .ion-image:before, .ion-images:before, .ion-information:before, .ion-information-circled:before, .ion-ionic:before, .ion-ios7-alarm:before, .ion-ios7-alarm-outline:before, .ion-ios7-albums:before, .ion-ios7-albums-outline:before, .ion-ios7-americanfootball:before, .ion-ios7-americanfootball-outline:before, .ion-ios7-analytics:before, .ion-ios7-analytics-outline:before, .ion-ios7-arrow-back:before, .ion-ios7-arrow-down:before, .ion-ios7-arrow-forward:before, .ion-ios7-arrow-left:before, .ion-ios7-arrow-right:before, .ion-ios7-arrow-thin-down:before, .ion-ios7-arrow-thin-left:before, .ion-ios7-arrow-thin-right:before, .ion-ios7-arrow-thin-up:before, .ion-ios7-arrow-up:before, .ion-ios7-at:before, .ion-ios7-at-outline:before, .ion-ios7-barcode:before, .ion-ios7-barcode-outline:before, .ion-ios7-baseball:before, .ion-ios7-baseball-outline:before, .ion-ios7-basketball:before, .ion-ios7-basketball-outline:before, .ion-ios7-bell:before, .ion-ios7-bell-outline:before, .ion-ios7-bolt:before, .ion-ios7-bolt-outline:before, .ion-ios7-bookmarks:before, .ion-ios7-bookmarks-outline:before, .ion-ios7-box:before, .ion-ios7-box-outline:before, .ion-ios7-briefcase:before, .ion-ios7-briefcase-outline:before, .ion-ios7-browsers:before, .ion-ios7-browsers-outline:before, .ion-ios7-calculator:before, .ion-ios7-calculator-outline:before, .ion-ios7-calendar:before, .ion-ios7-calendar-outline:before, .ion-ios7-camera:before, .ion-ios7-camera-outline:before, .ion-ios7-cart:before, .ion-ios7-cart-outline:before, .ion-ios7-chatboxes:before, .ion-ios7-chatboxes-outline:before, .ion-ios7-chatbubble:before, .ion-ios7-chatbubble-outline:before, .ion-ios7-checkmark:before, .ion-ios7-checkmark-empty:before, .ion-ios7-checkmark-outline:before, .ion-ios7-circle-filled:before, .ion-ios7-circle-outline:before, .ion-ios7-clock:before, .ion-ios7-clock-outline:before, .ion-ios7-close:before, .ion-ios7-close-empty:before, .ion-ios7-close-outline:before, .ion-ios7-cloud:before, .ion-ios7-cloud-download:before, .ion-ios7-cloud-download-outline:before, .ion-ios7-cloud-outline:before, .ion-ios7-cloud-upload:before, .ion-ios7-cloud-upload-outline:before, .ion-ios7-cloudy:before, .ion-ios7-cloudy-night:before, .ion-ios7-cloudy-night-outline:before, .ion-ios7-cloudy-outline:before, .ion-ios7-cog:before, .ion-ios7-cog-outline:before, .ion-ios7-compose:before, .ion-ios7-compose-outline:before, .ion-ios7-contact:before, .ion-ios7-contact-outline:before, .ion-ios7-copy:before, .ion-ios7-copy-outline:before, .ion-ios7-download:before, .ion-ios7-download-outline:before, .ion-ios7-drag:before, .ion-ios7-email:before, .ion-ios7-email-outline:before, .ion-ios7-expand:before, .ion-ios7-eye:before, .ion-ios7-eye-outline:before, .ion-ios7-fastforward:before, .ion-ios7-fastforward-outline:before, .ion-ios7-filing:before, .ion-ios7-filing-outline:before, .ion-ios7-film:before, .ion-ios7-film-outline:before, .ion-ios7-flag:before, .ion-ios7-flag-outline:before, .ion-ios7-folder:before, .ion-ios7-folder-outline:before, .ion-ios7-football:before, .ion-ios7-football-outline:before, .ion-ios7-gear:before, .ion-ios7-gear-outline:before, .ion-ios7-glasses:before, .ion-ios7-glasses-outline:before, .ion-ios7-heart:before, .ion-ios7-heart-outline:before, .ion-ios7-help:before, .ion-ios7-help-empty:before, .ion-ios7-help-outline:before, .ion-ios7-home:before, .ion-ios7-home-outline:before, .ion-ios7-infinite:before, .ion-ios7-infinite-outline:before, .ion-ios7-information:before, .ion-ios7-information-empty:before, .ion-ios7-information-outline:before, .ion-ios7-ionic-outline:before, .ion-ios7-keypad:before, .ion-ios7-keypad-outline:before, .ion-ios7-lightbulb:before, .ion-ios7-lightbulb-outline:before, .ion-ios7-location:before, .ion-ios7-location-outline:before, .ion-ios7-locked:before, .ion-ios7-locked-outline:before, .ion-ios7-loop:before, .ion-ios7-loop-strong:before, .ion-ios7-medkit:before, .ion-ios7-medkit-outline:before, .ion-ios7-mic:before, .ion-ios7-mic-off:before, .ion-ios7-mic-outline:before, .ion-ios7-minus:before, .ion-ios7-minus-empty:before, .ion-ios7-minus-outline:before, .ion-ios7-monitor:before, .ion-ios7-monitor-outline:before, .ion-ios7-moon:before, .ion-ios7-moon-outline:before, .ion-ios7-more:before, .ion-ios7-more-outline:before, .ion-ios7-musical-note:before, .ion-ios7-musical-notes:before, .ion-ios7-navigate:before, .ion-ios7-navigate-outline:before, .ion-ios7-paper:before, .ion-ios7-paper-outline:before, .ion-ios7-paperplane:before, .ion-ios7-paperplane-outline:before, .ion-ios7-partlysunny:before, .ion-ios7-partlysunny-outline:before, .ion-ios7-pause:before, .ion-ios7-pause-outline:before, .ion-ios7-paw:before, .ion-ios7-paw-outline:before, .ion-ios7-people:before, .ion-ios7-people-outline:before, .ion-ios7-person:before, .ion-ios7-person-outline:before, .ion-ios7-personadd:before, .ion-ios7-personadd-outline:before, .ion-ios7-photos:before, .ion-ios7-photos-outline:before, .ion-ios7-pie:before, .ion-ios7-pie-outline:before, .ion-ios7-play:before, .ion-ios7-play-outline:before, .ion-ios7-plus:before, .ion-ios7-plus-empty:before, .ion-ios7-plus-outline:before, .ion-ios7-pricetag:before, .ion-ios7-pricetag-outline:before, .ion-ios7-pricetags:before, .ion-ios7-pricetags-outline:before, .ion-ios7-printer:before, .ion-ios7-printer-outline:before, .ion-ios7-pulse:before, .ion-ios7-pulse-strong:before, .ion-ios7-rainy:before, .ion-ios7-rainy-outline:before, .ion-ios7-recording:before, .ion-ios7-recording-outline:before, .ion-ios7-redo:before, .ion-ios7-redo-outline:before, .ion-ios7-refresh:before, .ion-ios7-refresh-empty:before, .ion-ios7-refresh-outline:before, .ion-ios7-reload:before, .ion-ios7-reloading:before, .ion-ios7-reverse-camera:before, .ion-ios7-reverse-camera-outline:before, .ion-ios7-rewind:before, .ion-ios7-rewind-outline:before, .ion-ios7-search:before, .ion-ios7-search-strong:before, .ion-ios7-settings:before, .ion-ios7-settings-strong:before, .ion-ios7-shrink:before, .ion-ios7-skipbackward:before, .ion-ios7-skipbackward-outline:before, .ion-ios7-skipforward:before, .ion-ios7-skipforward-outline:before, .ion-ios7-snowy:before, .ion-ios7-speedometer:before, .ion-ios7-speedometer-outline:before, .ion-ios7-star:before, .ion-ios7-star-half:before, .ion-ios7-star-outline:before, .ion-ios7-stopwatch:before, .ion-ios7-stopwatch-outline:before, .ion-ios7-sunny:before, .ion-ios7-sunny-outline:before, .ion-ios7-telephone:before, .ion-ios7-telephone-outline:before, .ion-ios7-tennisball:before, .ion-ios7-tennisball-outline:before, .ion-ios7-thunderstorm:before, .ion-ios7-thunderstorm-outline:before, .ion-ios7-time:before, .ion-ios7-time-outline:before, .ion-ios7-timer:before, .ion-ios7-timer-outline:before, .ion-ios7-toggle:before, .ion-ios7-toggle-outline:before, .ion-ios7-trash:before, .ion-ios7-trash-outline:before, .ion-ios7-undo:before, .ion-ios7-undo-outline:before, .ion-ios7-unlocked:before, .ion-ios7-unlocked-outline:before, .ion-ios7-upload:before, .ion-ios7-upload-outline:before, .ion-ios7-videocam:before, .ion-ios7-videocam-outline:before, .ion-ios7-volume-high:before, .ion-ios7-volume-low:before, .ion-ios7-wineglass:before, .ion-ios7-wineglass-outline:before, .ion-ios7-world:before, .ion-ios7-world-outline:before, .ion-ipad:before, .ion-iphone:before, .ion-ipod:before, .ion-jet:before, .ion-key:before, .ion-knife:before, .ion-laptop:before, .ion-leaf:before, .ion-levels:before, .ion-lightbulb:before, .ion-link:before, .ion-load-a:before, .ion-loading-a:before, .ion-load-b:before, .ion-loading-b:before, .ion-load-c:before, .ion-loading-c:before, .ion-load-d:before, .ion-loading-d:before, .ion-location:before, .ion-locked:before, .ion-log-in:before, .ion-log-out:before, .ion-loop:before, .ion-looping:before, .ion-magnet:before, .ion-male:before, .ion-man:before, .ion-map:before, .ion-medkit:before, .ion-merge:before, .ion-mic-a:before, .ion-mic-b:before, .ion-mic-c:before, .ion-minus:before, .ion-minus-circled:before, .ion-minus-round:before, .ion-model-s:before, .ion-monitor:before, .ion-more:before, .ion-mouse:before, .ion-music-note:before, .ion-navicon:before, .ion-navicon-round:before, .ion-navigate:before, .ion-network:before, .ion-no-smoking:before, .ion-nuclear:before, .ion-outlet:before, .ion-paper-airplane:before, .ion-paperclip:before, .ion-pause:before, .ion-person:before, .ion-person-add:before, .ion-person-stalker:before, .ion-pie-graph:before, .ion-pin:before, .ion-pinpoint:before, .ion-pizza:before, .ion-plane:before, .ion-planet:before, .ion-play:before, .ion-playstation:before, .ion-plus:before, .ion-plus-circled:before, .ion-plus-round:before, .ion-podium:before, .ion-pound:before, .ion-power:before, .ion-pricetag:before, .ion-pricetags:before, .ion-printer:before, .ion-pull-request:before, .ion-qr-scanner:before, .ion-quote:before, .ion-radio-waves:before, .ion-record:before, .ion-refresh:before, .ion-refreshing:before, .ion-reply:before, .ion-reply-all:before, .ion-ribbon-a:before, .ion-ribbon-b:before, .ion-sad:before, .ion-scissors:before, .ion-search:before, .ion-settings:before, .ion-share:before, .ion-shuffle:before, .ion-skip-backward:before, .ion-skip-forward:before, .ion-social-android:before, .ion-social-android-outline:before, .ion-social-apple:before, .ion-social-apple-outline:before, .ion-social-bitcoin:before, .ion-social-bitcoin-outline:before, .ion-social-buffer:before, .ion-social-buffer-outline:before, .ion-social-designernews:before, .ion-social-designernews-outline:before, .ion-social-dribbble:before, .ion-social-dribbble-outline:before, .ion-social-dropbox:before, .ion-social-dropbox-outline:before, .ion-social-facebook:before, .ion-social-facebook-outline:before, .ion-social-foursquare:before, .ion-social-foursquare-outline:before, .ion-social-freebsd-devil:before, .ion-social-github:before, .ion-social-github-outline:before, .ion-social-google:before, .ion-social-google-outline:before, .ion-social-googleplus:before, .ion-social-googleplus-outline:before, .ion-social-hackernews:before, .ion-social-hackernews-outline:before, .ion-social-instagram:before, .ion-social-instagram-outline:before, .ion-social-linkedin:before, .ion-social-linkedin-outline:before, .ion-social-pinterest:before, .ion-social-pinterest-outline:before, .ion-social-reddit:before, .ion-social-reddit-outline:before, .ion-social-rss:before, .ion-social-rss-outline:before, .ion-social-skype:before, .ion-social-skype-outline:before, .ion-social-tumblr:before, .ion-social-tumblr-outline:before, .ion-social-tux:before, .ion-social-twitter:before, .ion-social-twitter-outline:before, .ion-social-usd:before, .ion-social-usd-outline:before, .ion-social-vimeo:before, .ion-social-vimeo-outline:before, .ion-social-windows:before, .ion-social-windows-outline:before, .ion-social-wordpress:before, .ion-social-wordpress-outline:before, .ion-social-yahoo:before, .ion-social-yahoo-outline:before, .ion-social-youtube:before, .ion-social-youtube-outline:before, .ion-speakerphone:before, .ion-speedometer:before, .ion-spoon:before, .ion-star:before, .ion-stats-bars:before, .ion-steam:before, .ion-stop:before, .ion-thermometer:before, .ion-thumbsdown:before, .ion-thumbsup:before, .ion-toggle:before, .ion-toggle-filled:before, .ion-trash-a:before, .ion-trash-b:before, .ion-trophy:before, .ion-umbrella:before, .ion-university:before, .ion-unlocked:before, .ion-upload:before, .ion-usb:before, .ion-videocamera:before, .ion-volume-high:before, .ion-volume-low:before, .ion-volume-medium:before, .ion-volume-mute:before, .ion-wand:before, .ion-waterdrop:before, .ion-wifi:before, .ion-wineglass:before, .ion-woman:before, .ion-wrench:before, .ion-xbox:before { + display: inline-block; + font-family: "Ionicons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + text-rendering: auto; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } + +.ion-spin, .ion-loading-a, .ion-loading-b, .ion-loading-c, .ion-loading-d, .ion-looping, .ion-refreshing, .ion-ios7-reloading { + -webkit-animation: spin 1s infinite linear; + -moz-animation: spin 1s infinite linear; + -o-animation: spin 1s infinite linear; + animation: spin 1s infinite linear; } + +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); } + + 100% { + -moz-transform: rotate(359deg); } } + +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); } + + 100% { + -webkit-transform: rotate(359deg); } } + +@-o-keyframes spin { + 0% { + -o-transform: rotate(0deg); } + + 100% { + -o-transform: rotate(359deg); } } + +@-ms-keyframes spin { + 0% { + -ms-transform: rotate(0deg); } + + 100% { + -ms-transform: rotate(359deg); } } + +@keyframes spin { + 0% { + transform: rotate(0deg); } + + 100% { + transform: rotate(359deg); } } + +.ion-loading-a { + -webkit-animation-timing-function: steps(8, start); + -moz-animation-timing-function: steps(8, start); + animation-timing-function: steps(8, start); } + +.ion-alert:before { + content: "\f101"; } + +.ion-alert-circled:before { + content: "\f100"; } + +.ion-android-add:before { + content: "\f2c7"; } + +.ion-android-add-contact:before { + content: "\f2c6"; } + +.ion-android-alarm:before { + content: "\f2c8"; } + +.ion-android-archive:before { + content: "\f2c9"; } + +.ion-android-arrow-back:before { + content: "\f2ca"; } + +.ion-android-arrow-down-left:before { + content: "\f2cb"; } + +.ion-android-arrow-down-right:before { + content: "\f2cc"; } + +.ion-android-arrow-forward:before { + content: "\f30f"; } + +.ion-android-arrow-up-left:before { + content: "\f2cd"; } + +.ion-android-arrow-up-right:before { + content: "\f2ce"; } + +.ion-android-battery:before { + content: "\f2cf"; } + +.ion-android-book:before { + content: "\f2d0"; } + +.ion-android-calendar:before { + content: "\f2d1"; } + +.ion-android-call:before { + content: "\f2d2"; } + +.ion-android-camera:before { + content: "\f2d3"; } + +.ion-android-chat:before { + content: "\f2d4"; } + +.ion-android-checkmark:before { + content: "\f2d5"; } + +.ion-android-clock:before { + content: "\f2d6"; } + +.ion-android-close:before { + content: "\f2d7"; } + +.ion-android-contact:before { + content: "\f2d8"; } + +.ion-android-contacts:before { + content: "\f2d9"; } + +.ion-android-data:before { + content: "\f2da"; } + +.ion-android-developer:before { + content: "\f2db"; } + +.ion-android-display:before { + content: "\f2dc"; } + +.ion-android-download:before { + content: "\f2dd"; } + +.ion-android-drawer:before { + content: "\f310"; } + +.ion-android-dropdown:before { + content: "\f2de"; } + +.ion-android-earth:before { + content: "\f2df"; } + +.ion-android-folder:before { + content: "\f2e0"; } + +.ion-android-forums:before { + content: "\f2e1"; } + +.ion-android-friends:before { + content: "\f2e2"; } + +.ion-android-hand:before { + content: "\f2e3"; } + +.ion-android-image:before { + content: "\f2e4"; } + +.ion-android-inbox:before { + content: "\f2e5"; } + +.ion-android-information:before { + content: "\f2e6"; } + +.ion-android-keypad:before { + content: "\f2e7"; } + +.ion-android-lightbulb:before { + content: "\f2e8"; } + +.ion-android-locate:before { + content: "\f2e9"; } + +.ion-android-location:before { + content: "\f2ea"; } + +.ion-android-mail:before { + content: "\f2eb"; } + +.ion-android-microphone:before { + content: "\f2ec"; } + +.ion-android-mixer:before { + content: "\f2ed"; } + +.ion-android-more:before { + content: "\f2ee"; } + +.ion-android-note:before { + content: "\f2ef"; } + +.ion-android-playstore:before { + content: "\f2f0"; } + +.ion-android-printer:before { + content: "\f2f1"; } + +.ion-android-promotion:before { + content: "\f2f2"; } + +.ion-android-reminder:before { + content: "\f2f3"; } + +.ion-android-remove:before { + content: "\f2f4"; } + +.ion-android-search:before { + content: "\f2f5"; } + +.ion-android-send:before { + content: "\f2f6"; } + +.ion-android-settings:before { + content: "\f2f7"; } + +.ion-android-share:before { + content: "\f2f8"; } + +.ion-android-social:before { + content: "\f2fa"; } + +.ion-android-social-user:before { + content: "\f2f9"; } + +.ion-android-sort:before { + content: "\f2fb"; } + +.ion-android-stair-drawer:before { + content: "\f311"; } + +.ion-android-star:before { + content: "\f2fc"; } + +.ion-android-stopwatch:before { + content: "\f2fd"; } + +.ion-android-storage:before { + content: "\f2fe"; } + +.ion-android-system-back:before { + content: "\f2ff"; } + +.ion-android-system-home:before { + content: "\f300"; } + +.ion-android-system-windows:before { + content: "\f301"; } + +.ion-android-timer:before { + content: "\f302"; } + +.ion-android-trash:before { + content: "\f303"; } + +.ion-android-user-menu:before { + content: "\f312"; } + +.ion-android-volume:before { + content: "\f304"; } + +.ion-android-wifi:before { + content: "\f305"; } + +.ion-aperture:before { + content: "\f313"; } + +.ion-archive:before { + content: "\f102"; } + +.ion-arrow-down-a:before { + content: "\f103"; } + +.ion-arrow-down-b:before { + content: "\f104"; } + +.ion-arrow-down-c:before { + content: "\f105"; } + +.ion-arrow-expand:before { + content: "\f25e"; } + +.ion-arrow-graph-down-left:before { + content: "\f25f"; } + +.ion-arrow-graph-down-right:before { + content: "\f260"; } + +.ion-arrow-graph-up-left:before { + content: "\f261"; } + +.ion-arrow-graph-up-right:before { + content: "\f262"; } + +.ion-arrow-left-a:before { + content: "\f106"; } + +.ion-arrow-left-b:before { + content: "\f107"; } + +.ion-arrow-left-c:before { + content: "\f108"; } + +.ion-arrow-move:before { + content: "\f263"; } + +.ion-arrow-resize:before { + content: "\f264"; } + +.ion-arrow-return-left:before { + content: "\f265"; } + +.ion-arrow-return-right:before { + content: "\f266"; } + +.ion-arrow-right-a:before { + content: "\f109"; } + +.ion-arrow-right-b:before { + content: "\f10a"; } + +.ion-arrow-right-c:before { + content: "\f10b"; } + +.ion-arrow-shrink:before { + content: "\f267"; } + +.ion-arrow-swap:before { + content: "\f268"; } + +.ion-arrow-up-a:before { + content: "\f10c"; } + +.ion-arrow-up-b:before { + content: "\f10d"; } + +.ion-arrow-up-c:before { + content: "\f10e"; } + +.ion-asterisk:before { + content: "\f314"; } + +.ion-at:before { + content: "\f10f"; } + +.ion-bag:before { + content: "\f110"; } + +.ion-battery-charging:before { + content: "\f111"; } + +.ion-battery-empty:before { + content: "\f112"; } + +.ion-battery-full:before { + content: "\f113"; } + +.ion-battery-half:before { + content: "\f114"; } + +.ion-battery-low:before { + content: "\f115"; } + +.ion-beaker:before { + content: "\f269"; } + +.ion-beer:before { + content: "\f26a"; } + +.ion-bluetooth:before { + content: "\f116"; } + +.ion-bonfire:before { + content: "\f315"; } + +.ion-bookmark:before { + content: "\f26b"; } + +.ion-briefcase:before { + content: "\f26c"; } + +.ion-bug:before { + content: "\f2be"; } + +.ion-calculator:before { + content: "\f26d"; } + +.ion-calendar:before { + content: "\f117"; } + +.ion-camera:before { + content: "\f118"; } + +.ion-card:before { + content: "\f119"; } + +.ion-cash:before { + content: "\f316"; } + +.ion-chatbox:before { + content: "\f11b"; } + +.ion-chatbox-working:before { + content: "\f11a"; } + +.ion-chatboxes:before { + content: "\f11c"; } + +.ion-chatbubble:before { + content: "\f11e"; } + +.ion-chatbubble-working:before { + content: "\f11d"; } + +.ion-chatbubbles:before { + content: "\f11f"; } + +.ion-checkmark:before { + content: "\f122"; } + +.ion-checkmark-circled:before { + content: "\f120"; } + +.ion-checkmark-round:before { + content: "\f121"; } + +.ion-chevron-down:before { + content: "\f123"; } + +.ion-chevron-left:before { + content: "\f124"; } + +.ion-chevron-right:before { + content: "\f125"; } + +.ion-chevron-up:before { + content: "\f126"; } + +.ion-clipboard:before { + content: "\f127"; } + +.ion-clock:before { + content: "\f26e"; } + +.ion-close:before { + content: "\f12a"; } + +.ion-close-circled:before { + content: "\f128"; } + +.ion-close-round:before { + content: "\f129"; } + +.ion-closed-captioning:before { + content: "\f317"; } + +.ion-cloud:before { + content: "\f12b"; } + +.ion-code:before { + content: "\f271"; } + +.ion-code-download:before { + content: "\f26f"; } + +.ion-code-working:before { + content: "\f270"; } + +.ion-coffee:before { + content: "\f272"; } + +.ion-compass:before { + content: "\f273"; } + +.ion-compose:before { + content: "\f12c"; } + +.ion-connection-bars:before { + content: "\f274"; } + +.ion-contrast:before { + content: "\f275"; } + +.ion-cube:before { + content: "\f318"; } + +.ion-disc:before { + content: "\f12d"; } + +.ion-document:before { + content: "\f12f"; } + +.ion-document-text:before { + content: "\f12e"; } + +.ion-drag:before { + content: "\f130"; } + +.ion-earth:before { + content: "\f276"; } + +.ion-edit:before { + content: "\f2bf"; } + +.ion-egg:before { + content: "\f277"; } + +.ion-eject:before { + content: "\f131"; } + +.ion-email:before { + content: "\f132"; } + +.ion-eye:before { + content: "\f133"; } + +.ion-eye-disabled:before { + content: "\f306"; } + +.ion-female:before { + content: "\f278"; } + +.ion-filing:before { + content: "\f134"; } + +.ion-film-marker:before { + content: "\f135"; } + +.ion-fireball:before { + content: "\f319"; } + +.ion-flag:before { + content: "\f279"; } + +.ion-flame:before { + content: "\f31a"; } + +.ion-flash:before { + content: "\f137"; } + +.ion-flash-off:before { + content: "\f136"; } + +.ion-flask:before { + content: "\f138"; } + +.ion-folder:before { + content: "\f139"; } + +.ion-fork:before { + content: "\f27a"; } + +.ion-fork-repo:before { + content: "\f2c0"; } + +.ion-forward:before { + content: "\f13a"; } + +.ion-funnel:before { + content: "\f31b"; } + +.ion-game-controller-a:before { + content: "\f13b"; } + +.ion-game-controller-b:before { + content: "\f13c"; } + +.ion-gear-a:before { + content: "\f13d"; } + +.ion-gear-b:before { + content: "\f13e"; } + +.ion-grid:before { + content: "\f13f"; } + +.ion-hammer:before { + content: "\f27b"; } + +.ion-happy:before { + content: "\f31c"; } + +.ion-headphone:before { + content: "\f140"; } + +.ion-heart:before { + content: "\f141"; } + +.ion-heart-broken:before { + content: "\f31d"; } + +.ion-help:before { + content: "\f143"; } + +.ion-help-buoy:before { + content: "\f27c"; } + +.ion-help-circled:before { + content: "\f142"; } + +.ion-home:before { + content: "\f144"; } + +.ion-icecream:before { + content: "\f27d"; } + +.ion-icon-social-google-plus:before { + content: "\f146"; } + +.ion-icon-social-google-plus-outline:before { + content: "\f145"; } + +.ion-image:before { + content: "\f147"; } + +.ion-images:before { + content: "\f148"; } + +.ion-information:before { + content: "\f14a"; } + +.ion-information-circled:before { + content: "\f149"; } + +.ion-ionic:before { + content: "\f14b"; } + +.ion-ios7-alarm:before { + content: "\f14d"; } + +.ion-ios7-alarm-outline:before { + content: "\f14c"; } + +.ion-ios7-albums:before { + content: "\f14f"; } + +.ion-ios7-albums-outline:before { + content: "\f14e"; } + +.ion-ios7-americanfootball:before { + content: "\f31f"; } + +.ion-ios7-americanfootball-outline:before { + content: "\f31e"; } + +.ion-ios7-analytics:before { + content: "\f321"; } + +.ion-ios7-analytics-outline:before { + content: "\f320"; } + +.ion-ios7-arrow-back:before { + content: "\f150"; } + +.ion-ios7-arrow-down:before { + content: "\f151"; } + +.ion-ios7-arrow-forward:before { + content: "\f152"; } + +.ion-ios7-arrow-left:before { + content: "\f153"; } + +.ion-ios7-arrow-right:before { + content: "\f154"; } + +.ion-ios7-arrow-thin-down:before { + content: "\f27e"; } + +.ion-ios7-arrow-thin-left:before { + content: "\f27f"; } + +.ion-ios7-arrow-thin-right:before { + content: "\f280"; } + +.ion-ios7-arrow-thin-up:before { + content: "\f281"; } + +.ion-ios7-arrow-up:before { + content: "\f155"; } + +.ion-ios7-at:before { + content: "\f157"; } + +.ion-ios7-at-outline:before { + content: "\f156"; } + +.ion-ios7-barcode:before { + content: "\f323"; } + +.ion-ios7-barcode-outline:before { + content: "\f322"; } + +.ion-ios7-baseball:before { + content: "\f325"; } + +.ion-ios7-baseball-outline:before { + content: "\f324"; } + +.ion-ios7-basketball:before { + content: "\f327"; } + +.ion-ios7-basketball-outline:before { + content: "\f326"; } + +.ion-ios7-bell:before { + content: "\f159"; } + +.ion-ios7-bell-outline:before { + content: "\f158"; } + +.ion-ios7-bolt:before { + content: "\f15b"; } + +.ion-ios7-bolt-outline:before { + content: "\f15a"; } + +.ion-ios7-bookmarks:before { + content: "\f15d"; } + +.ion-ios7-bookmarks-outline:before { + content: "\f15c"; } + +.ion-ios7-box:before { + content: "\f15f"; } + +.ion-ios7-box-outline:before { + content: "\f15e"; } + +.ion-ios7-briefcase:before { + content: "\f283"; } + +.ion-ios7-briefcase-outline:before { + content: "\f282"; } + +.ion-ios7-browsers:before { + content: "\f161"; } + +.ion-ios7-browsers-outline:before { + content: "\f160"; } + +.ion-ios7-calculator:before { + content: "\f285"; } + +.ion-ios7-calculator-outline:before { + content: "\f284"; } + +.ion-ios7-calendar:before { + content: "\f163"; } + +.ion-ios7-calendar-outline:before { + content: "\f162"; } + +.ion-ios7-camera:before { + content: "\f165"; } + +.ion-ios7-camera-outline:before { + content: "\f164"; } + +.ion-ios7-cart:before { + content: "\f167"; } + +.ion-ios7-cart-outline:before { + content: "\f166"; } + +.ion-ios7-chatboxes:before { + content: "\f169"; } + +.ion-ios7-chatboxes-outline:before { + content: "\f168"; } + +.ion-ios7-chatbubble:before { + content: "\f16b"; } + +.ion-ios7-chatbubble-outline:before { + content: "\f16a"; } + +.ion-ios7-checkmark:before { + content: "\f16e"; } + +.ion-ios7-checkmark-empty:before { + content: "\f16c"; } + +.ion-ios7-checkmark-outline:before { + content: "\f16d"; } + +.ion-ios7-circle-filled:before { + content: "\f16f"; } + +.ion-ios7-circle-outline:before { + content: "\f170"; } + +.ion-ios7-clock:before { + content: "\f172"; } + +.ion-ios7-clock-outline:before { + content: "\f171"; } + +.ion-ios7-close:before { + content: "\f2bc"; } + +.ion-ios7-close-empty:before { + content: "\f2bd"; } + +.ion-ios7-close-outline:before { + content: "\f2bb"; } + +.ion-ios7-cloud:before { + content: "\f178"; } + +.ion-ios7-cloud-download:before { + content: "\f174"; } + +.ion-ios7-cloud-download-outline:before { + content: "\f173"; } + +.ion-ios7-cloud-outline:before { + content: "\f175"; } + +.ion-ios7-cloud-upload:before { + content: "\f177"; } + +.ion-ios7-cloud-upload-outline:before { + content: "\f176"; } + +.ion-ios7-cloudy:before { + content: "\f17a"; } + +.ion-ios7-cloudy-night:before { + content: "\f308"; } + +.ion-ios7-cloudy-night-outline:before { + content: "\f307"; } + +.ion-ios7-cloudy-outline:before { + content: "\f179"; } + +.ion-ios7-cog:before { + content: "\f17c"; } + +.ion-ios7-cog-outline:before { + content: "\f17b"; } + +.ion-ios7-compose:before { + content: "\f17e"; } + +.ion-ios7-compose-outline:before { + content: "\f17d"; } + +.ion-ios7-contact:before { + content: "\f180"; } + +.ion-ios7-contact-outline:before { + content: "\f17f"; } + +.ion-ios7-copy:before { + content: "\f182"; } + +.ion-ios7-copy-outline:before { + content: "\f181"; } + +.ion-ios7-download:before { + content: "\f184"; } + +.ion-ios7-download-outline:before { + content: "\f183"; } + +.ion-ios7-drag:before { + content: "\f185"; } + +.ion-ios7-email:before { + content: "\f187"; } + +.ion-ios7-email-outline:before { + content: "\f186"; } + +.ion-ios7-expand:before { + content: "\f30d"; } + +.ion-ios7-eye:before { + content: "\f189"; } + +.ion-ios7-eye-outline:before { + content: "\f188"; } + +.ion-ios7-fastforward:before { + content: "\f18b"; } + +.ion-ios7-fastforward-outline:before { + content: "\f18a"; } + +.ion-ios7-filing:before { + content: "\f18d"; } + +.ion-ios7-filing-outline:before { + content: "\f18c"; } + +.ion-ios7-film:before { + content: "\f18f"; } + +.ion-ios7-film-outline:before { + content: "\f18e"; } + +.ion-ios7-flag:before { + content: "\f191"; } + +.ion-ios7-flag-outline:before { + content: "\f190"; } + +.ion-ios7-folder:before { + content: "\f193"; } + +.ion-ios7-folder-outline:before { + content: "\f192"; } + +.ion-ios7-football:before { + content: "\f329"; } + +.ion-ios7-football-outline:before { + content: "\f328"; } + +.ion-ios7-gear:before { + content: "\f195"; } + +.ion-ios7-gear-outline:before { + content: "\f194"; } + +.ion-ios7-glasses:before { + content: "\f197"; } + +.ion-ios7-glasses-outline:before { + content: "\f196"; } + +.ion-ios7-heart:before { + content: "\f199"; } + +.ion-ios7-heart-outline:before { + content: "\f198"; } + +.ion-ios7-help:before { + content: "\f19c"; } + +.ion-ios7-help-empty:before { + content: "\f19a"; } + +.ion-ios7-help-outline:before { + content: "\f19b"; } + +.ion-ios7-home:before { + content: "\f32b"; } + +.ion-ios7-home-outline:before { + content: "\f32a"; } + +.ion-ios7-infinite:before { + content: "\f19e"; } + +.ion-ios7-infinite-outline:before { + content: "\f19d"; } + +.ion-ios7-information:before { + content: "\f1a1"; } + +.ion-ios7-information-empty:before { + content: "\f19f"; } + +.ion-ios7-information-outline:before { + content: "\f1a0"; } + +.ion-ios7-ionic-outline:before { + content: "\f1a2"; } + +.ion-ios7-keypad:before { + content: "\f1a4"; } + +.ion-ios7-keypad-outline:before { + content: "\f1a3"; } + +.ion-ios7-lightbulb:before { + content: "\f287"; } + +.ion-ios7-lightbulb-outline:before { + content: "\f286"; } + +.ion-ios7-location:before { + content: "\f1a6"; } + +.ion-ios7-location-outline:before { + content: "\f1a5"; } + +.ion-ios7-locked:before { + content: "\f1a8"; } + +.ion-ios7-locked-outline:before { + content: "\f1a7"; } + +.ion-ios7-loop:before { + content: "\f32d"; } + +.ion-ios7-loop-strong:before { + content: "\f32c"; } + +.ion-ios7-medkit:before { + content: "\f289"; } + +.ion-ios7-medkit-outline:before { + content: "\f288"; } + +.ion-ios7-mic:before { + content: "\f1ab"; } + +.ion-ios7-mic-off:before { + content: "\f1a9"; } + +.ion-ios7-mic-outline:before { + content: "\f1aa"; } + +.ion-ios7-minus:before { + content: "\f1ae"; } + +.ion-ios7-minus-empty:before { + content: "\f1ac"; } + +.ion-ios7-minus-outline:before { + content: "\f1ad"; } + +.ion-ios7-monitor:before { + content: "\f1b0"; } + +.ion-ios7-monitor-outline:before { + content: "\f1af"; } + +.ion-ios7-moon:before { + content: "\f1b2"; } + +.ion-ios7-moon-outline:before { + content: "\f1b1"; } + +.ion-ios7-more:before { + content: "\f1b4"; } + +.ion-ios7-more-outline:before { + content: "\f1b3"; } + +.ion-ios7-musical-note:before { + content: "\f1b5"; } + +.ion-ios7-musical-notes:before { + content: "\f1b6"; } + +.ion-ios7-navigate:before { + content: "\f1b8"; } + +.ion-ios7-navigate-outline:before { + content: "\f1b7"; } + +.ion-ios7-paper:before { + content: "\f32f"; } + +.ion-ios7-paper-outline:before { + content: "\f32e"; } + +.ion-ios7-paperplane:before { + content: "\f1ba"; } + +.ion-ios7-paperplane-outline:before { + content: "\f1b9"; } + +.ion-ios7-partlysunny:before { + content: "\f1bc"; } + +.ion-ios7-partlysunny-outline:before { + content: "\f1bb"; } + +.ion-ios7-pause:before { + content: "\f1be"; } + +.ion-ios7-pause-outline:before { + content: "\f1bd"; } + +.ion-ios7-paw:before { + content: "\f331"; } + +.ion-ios7-paw-outline:before { + content: "\f330"; } + +.ion-ios7-people:before { + content: "\f1c0"; } + +.ion-ios7-people-outline:before { + content: "\f1bf"; } + +.ion-ios7-person:before { + content: "\f1c2"; } + +.ion-ios7-person-outline:before { + content: "\f1c1"; } + +.ion-ios7-personadd:before { + content: "\f1c4"; } + +.ion-ios7-personadd-outline:before { + content: "\f1c3"; } + +.ion-ios7-photos:before { + content: "\f1c6"; } + +.ion-ios7-photos-outline:before { + content: "\f1c5"; } + +.ion-ios7-pie:before { + content: "\f28b"; } + +.ion-ios7-pie-outline:before { + content: "\f28a"; } + +.ion-ios7-play:before { + content: "\f1c8"; } + +.ion-ios7-play-outline:before { + content: "\f1c7"; } + +.ion-ios7-plus:before { + content: "\f1cb"; } + +.ion-ios7-plus-empty:before { + content: "\f1c9"; } + +.ion-ios7-plus-outline:before { + content: "\f1ca"; } + +.ion-ios7-pricetag:before { + content: "\f28d"; } + +.ion-ios7-pricetag-outline:before { + content: "\f28c"; } + +.ion-ios7-pricetags:before { + content: "\f333"; } + +.ion-ios7-pricetags-outline:before { + content: "\f332"; } + +.ion-ios7-printer:before { + content: "\f1cd"; } + +.ion-ios7-printer-outline:before { + content: "\f1cc"; } + +.ion-ios7-pulse:before { + content: "\f335"; } + +.ion-ios7-pulse-strong:before { + content: "\f334"; } + +.ion-ios7-rainy:before { + content: "\f1cf"; } + +.ion-ios7-rainy-outline:before { + content: "\f1ce"; } + +.ion-ios7-recording:before { + content: "\f1d1"; } + +.ion-ios7-recording-outline:before { + content: "\f1d0"; } + +.ion-ios7-redo:before { + content: "\f1d3"; } + +.ion-ios7-redo-outline:before { + content: "\f1d2"; } + +.ion-ios7-refresh:before { + content: "\f1d6"; } + +.ion-ios7-refresh-empty:before { + content: "\f1d4"; } + +.ion-ios7-refresh-outline:before { + content: "\f1d5"; } + +.ion-ios7-reload:before, .ion-ios7-reloading:before { + content: "\f28e"; } + +.ion-ios7-reverse-camera:before { + content: "\f337"; } + +.ion-ios7-reverse-camera-outline:before { + content: "\f336"; } + +.ion-ios7-rewind:before { + content: "\f1d8"; } + +.ion-ios7-rewind-outline:before { + content: "\f1d7"; } + +.ion-ios7-search:before { + content: "\f1da"; } + +.ion-ios7-search-strong:before { + content: "\f1d9"; } + +.ion-ios7-settings:before { + content: "\f339"; } + +.ion-ios7-settings-strong:before { + content: "\f338"; } + +.ion-ios7-shrink:before { + content: "\f30e"; } + +.ion-ios7-skipbackward:before { + content: "\f1dc"; } + +.ion-ios7-skipbackward-outline:before { + content: "\f1db"; } + +.ion-ios7-skipforward:before { + content: "\f1de"; } + +.ion-ios7-skipforward-outline:before { + content: "\f1dd"; } + +.ion-ios7-snowy:before { + content: "\f309"; } + +.ion-ios7-speedometer:before { + content: "\f290"; } + +.ion-ios7-speedometer-outline:before { + content: "\f28f"; } + +.ion-ios7-star:before { + content: "\f1e0"; } + +.ion-ios7-star-half:before { + content: "\f33a"; } + +.ion-ios7-star-outline:before { + content: "\f1df"; } + +.ion-ios7-stopwatch:before { + content: "\f1e2"; } + +.ion-ios7-stopwatch-outline:before { + content: "\f1e1"; } + +.ion-ios7-sunny:before { + content: "\f1e4"; } + +.ion-ios7-sunny-outline:before { + content: "\f1e3"; } + +.ion-ios7-telephone:before { + content: "\f1e6"; } + +.ion-ios7-telephone-outline:before { + content: "\f1e5"; } + +.ion-ios7-tennisball:before { + content: "\f33c"; } + +.ion-ios7-tennisball-outline:before { + content: "\f33b"; } + +.ion-ios7-thunderstorm:before { + content: "\f1e8"; } + +.ion-ios7-thunderstorm-outline:before { + content: "\f1e7"; } + +.ion-ios7-time:before { + content: "\f292"; } + +.ion-ios7-time-outline:before { + content: "\f291"; } + +.ion-ios7-timer:before { + content: "\f1ea"; } + +.ion-ios7-timer-outline:before { + content: "\f1e9"; } + +.ion-ios7-toggle:before { + content: "\f33e"; } + +.ion-ios7-toggle-outline:before { + content: "\f33d"; } + +.ion-ios7-trash:before { + content: "\f1ec"; } + +.ion-ios7-trash-outline:before { + content: "\f1eb"; } + +.ion-ios7-undo:before { + content: "\f1ee"; } + +.ion-ios7-undo-outline:before { + content: "\f1ed"; } + +.ion-ios7-unlocked:before { + content: "\f1f0"; } + +.ion-ios7-unlocked-outline:before { + content: "\f1ef"; } + +.ion-ios7-upload:before { + content: "\f1f2"; } + +.ion-ios7-upload-outline:before { + content: "\f1f1"; } + +.ion-ios7-videocam:before { + content: "\f1f4"; } + +.ion-ios7-videocam-outline:before { + content: "\f1f3"; } + +.ion-ios7-volume-high:before { + content: "\f1f5"; } + +.ion-ios7-volume-low:before { + content: "\f1f6"; } + +.ion-ios7-wineglass:before { + content: "\f294"; } + +.ion-ios7-wineglass-outline:before { + content: "\f293"; } + +.ion-ios7-world:before { + content: "\f1f8"; } + +.ion-ios7-world-outline:before { + content: "\f1f7"; } + +.ion-ipad:before { + content: "\f1f9"; } + +.ion-iphone:before { + content: "\f1fa"; } + +.ion-ipod:before { + content: "\f1fb"; } + +.ion-jet:before { + content: "\f295"; } + +.ion-key:before { + content: "\f296"; } + +.ion-knife:before { + content: "\f297"; } + +.ion-laptop:before { + content: "\f1fc"; } + +.ion-leaf:before { + content: "\f1fd"; } + +.ion-levels:before { + content: "\f298"; } + +.ion-lightbulb:before { + content: "\f299"; } + +.ion-link:before { + content: "\f1fe"; } + +.ion-load-a:before, .ion-loading-a:before { + content: "\f29a"; } + +.ion-load-b:before, .ion-loading-b:before { + content: "\f29b"; } + +.ion-load-c:before, .ion-loading-c:before { + content: "\f29c"; } + +.ion-load-d:before, .ion-loading-d:before { + content: "\f29d"; } + +.ion-location:before { + content: "\f1ff"; } + +.ion-locked:before { + content: "\f200"; } + +.ion-log-in:before { + content: "\f29e"; } + +.ion-log-out:before { + content: "\f29f"; } + +.ion-loop:before, .ion-looping:before { + content: "\f201"; } + +.ion-magnet:before { + content: "\f2a0"; } + +.ion-male:before { + content: "\f2a1"; } + +.ion-man:before { + content: "\f202"; } + +.ion-map:before { + content: "\f203"; } + +.ion-medkit:before { + content: "\f2a2"; } + +.ion-merge:before { + content: "\f33f"; } + +.ion-mic-a:before { + content: "\f204"; } + +.ion-mic-b:before { + content: "\f205"; } + +.ion-mic-c:before { + content: "\f206"; } + +.ion-minus:before { + content: "\f209"; } + +.ion-minus-circled:before { + content: "\f207"; } + +.ion-minus-round:before { + content: "\f208"; } + +.ion-model-s:before { + content: "\f2c1"; } + +.ion-monitor:before { + content: "\f20a"; } + +.ion-more:before { + content: "\f20b"; } + +.ion-mouse:before { + content: "\f340"; } + +.ion-music-note:before { + content: "\f20c"; } + +.ion-navicon:before { + content: "\f20e"; } + +.ion-navicon-round:before { + content: "\f20d"; } + +.ion-navigate:before { + content: "\f2a3"; } + +.ion-network:before { + content: "\f341"; } + +.ion-no-smoking:before { + content: "\f2c2"; } + +.ion-nuclear:before { + content: "\f2a4"; } + +.ion-outlet:before { + content: "\f342"; } + +.ion-paper-airplane:before { + content: "\f2c3"; } + +.ion-paperclip:before { + content: "\f20f"; } + +.ion-pause:before { + content: "\f210"; } + +.ion-person:before { + content: "\f213"; } + +.ion-person-add:before { + content: "\f211"; } + +.ion-person-stalker:before { + content: "\f212"; } + +.ion-pie-graph:before { + content: "\f2a5"; } + +.ion-pin:before { + content: "\f2a6"; } + +.ion-pinpoint:before { + content: "\f2a7"; } + +.ion-pizza:before { + content: "\f2a8"; } + +.ion-plane:before { + content: "\f214"; } + +.ion-planet:before { + content: "\f343"; } + +.ion-play:before { + content: "\f215"; } + +.ion-playstation:before { + content: "\f30a"; } + +.ion-plus:before { + content: "\f218"; } + +.ion-plus-circled:before { + content: "\f216"; } + +.ion-plus-round:before { + content: "\f217"; } + +.ion-podium:before { + content: "\f344"; } + +.ion-pound:before { + content: "\f219"; } + +.ion-power:before { + content: "\f2a9"; } + +.ion-pricetag:before { + content: "\f2aa"; } + +.ion-pricetags:before { + content: "\f2ab"; } + +.ion-printer:before { + content: "\f21a"; } + +.ion-pull-request:before { + content: "\f345"; } + +.ion-qr-scanner:before { + content: "\f346"; } + +.ion-quote:before { + content: "\f347"; } + +.ion-radio-waves:before { + content: "\f2ac"; } + +.ion-record:before { + content: "\f21b"; } + +.ion-refresh:before, .ion-refreshing:before { + content: "\f21c"; } + +.ion-reply:before { + content: "\f21e"; } + +.ion-reply-all:before { + content: "\f21d"; } + +.ion-ribbon-a:before { + content: "\f348"; } + +.ion-ribbon-b:before { + content: "\f349"; } + +.ion-sad:before { + content: "\f34a"; } + +.ion-scissors:before { + content: "\f34b"; } + +.ion-search:before { + content: "\f21f"; } + +.ion-settings:before { + content: "\f2ad"; } + +.ion-share:before { + content: "\f220"; } + +.ion-shuffle:before { + content: "\f221"; } + +.ion-skip-backward:before { + content: "\f222"; } + +.ion-skip-forward:before { + content: "\f223"; } + +.ion-social-android:before { + content: "\f225"; } + +.ion-social-android-outline:before { + content: "\f224"; } + +.ion-social-apple:before { + content: "\f227"; } + +.ion-social-apple-outline:before { + content: "\f226"; } + +.ion-social-bitcoin:before { + content: "\f2af"; } + +.ion-social-bitcoin-outline:before { + content: "\f2ae"; } + +.ion-social-buffer:before { + content: "\f229"; } + +.ion-social-buffer-outline:before { + content: "\f228"; } + +.ion-social-designernews:before { + content: "\f22b"; } + +.ion-social-designernews-outline:before { + content: "\f22a"; } + +.ion-social-dribbble:before { + content: "\f22d"; } + +.ion-social-dribbble-outline:before { + content: "\f22c"; } + +.ion-social-dropbox:before { + content: "\f22f"; } + +.ion-social-dropbox-outline:before { + content: "\f22e"; } + +.ion-social-facebook:before { + content: "\f231"; } + +.ion-social-facebook-outline:before { + content: "\f230"; } + +.ion-social-foursquare:before { + content: "\f34d"; } + +.ion-social-foursquare-outline:before { + content: "\f34c"; } + +.ion-social-freebsd-devil:before { + content: "\f2c4"; } + +.ion-social-github:before { + content: "\f233"; } + +.ion-social-github-outline:before { + content: "\f232"; } + +.ion-social-google:before { + content: "\f34f"; } + +.ion-social-google-outline:before { + content: "\f34e"; } + +.ion-social-googleplus:before { + content: "\f235"; } + +.ion-social-googleplus-outline:before { + content: "\f234"; } + +.ion-social-hackernews:before { + content: "\f237"; } + +.ion-social-hackernews-outline:before { + content: "\f236"; } + +.ion-social-instagram:before { + content: "\f351"; } + +.ion-social-instagram-outline:before { + content: "\f350"; } + +.ion-social-linkedin:before { + content: "\f239"; } + +.ion-social-linkedin-outline:before { + content: "\f238"; } + +.ion-social-pinterest:before { + content: "\f2b1"; } + +.ion-social-pinterest-outline:before { + content: "\f2b0"; } + +.ion-social-reddit:before { + content: "\f23b"; } + +.ion-social-reddit-outline:before { + content: "\f23a"; } + +.ion-social-rss:before { + content: "\f23d"; } + +.ion-social-rss-outline:before { + content: "\f23c"; } + +.ion-social-skype:before { + content: "\f23f"; } + +.ion-social-skype-outline:before { + content: "\f23e"; } + +.ion-social-tumblr:before { + content: "\f241"; } + +.ion-social-tumblr-outline:before { + content: "\f240"; } + +.ion-social-tux:before { + content: "\f2c5"; } + +.ion-social-twitter:before { + content: "\f243"; } + +.ion-social-twitter-outline:before { + content: "\f242"; } + +.ion-social-usd:before { + content: "\f353"; } + +.ion-social-usd-outline:before { + content: "\f352"; } + +.ion-social-vimeo:before { + content: "\f245"; } + +.ion-social-vimeo-outline:before { + content: "\f244"; } + +.ion-social-windows:before { + content: "\f247"; } + +.ion-social-windows-outline:before { + content: "\f246"; } + +.ion-social-wordpress:before { + content: "\f249"; } + +.ion-social-wordpress-outline:before { + content: "\f248"; } + +.ion-social-yahoo:before { + content: "\f24b"; } + +.ion-social-yahoo-outline:before { + content: "\f24a"; } + +.ion-social-youtube:before { + content: "\f24d"; } + +.ion-social-youtube-outline:before { + content: "\f24c"; } + +.ion-speakerphone:before { + content: "\f2b2"; } + +.ion-speedometer:before { + content: "\f2b3"; } + +.ion-spoon:before { + content: "\f2b4"; } + +.ion-star:before { + content: "\f24e"; } + +.ion-stats-bars:before { + content: "\f2b5"; } + +.ion-steam:before { + content: "\f30b"; } + +.ion-stop:before { + content: "\f24f"; } + +.ion-thermometer:before { + content: "\f2b6"; } + +.ion-thumbsdown:before { + content: "\f250"; } + +.ion-thumbsup:before { + content: "\f251"; } + +.ion-toggle:before { + content: "\f355"; } + +.ion-toggle-filled:before { + content: "\f354"; } + +.ion-trash-a:before { + content: "\f252"; } + +.ion-trash-b:before { + content: "\f253"; } + +.ion-trophy:before { + content: "\f356"; } + +.ion-umbrella:before { + content: "\f2b7"; } + +.ion-university:before { + content: "\f357"; } + +.ion-unlocked:before { + content: "\f254"; } + +.ion-upload:before { + content: "\f255"; } + +.ion-usb:before { + content: "\f2b8"; } + +.ion-videocamera:before { + content: "\f256"; } + +.ion-volume-high:before { + content: "\f257"; } + +.ion-volume-low:before { + content: "\f258"; } + +.ion-volume-medium:before { + content: "\f259"; } + +.ion-volume-mute:before { + content: "\f25a"; } + +.ion-wand:before { + content: "\f358"; } + +.ion-waterdrop:before { + content: "\f25b"; } + +.ion-wifi:before { + content: "\f25c"; } + +.ion-wineglass:before { + content: "\f2b9"; } + +.ion-woman:before { + content: "\f25d"; } + +.ion-wrench:before { + content: "\f2ba"; } + +.ion-xbox:before { + content: "\f30c"; } + +/** + * Resets + * -------------------------------------------------- + * Adapted from normalize.css and some reset.css. We don't care even one + * bit about old IE, so we don't need any hacks for that in here. + * + * There are probably other things we could remove here, as well. + * + * normalize.css v2.1.2 | MIT License | git.io/normalize + + * Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/) + * http://cssreset.com + */ +html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, i, u, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, fieldset, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + vertical-align: baseline; + font: inherit; + font-size: 100%; } + +ol, ul { + list-style: none; } + +blockquote, q { + quotes: none; } + +blockquote:before, blockquote:after, q:before, q:after { + content: ''; + content: none; } + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ +audio:not([controls]) { + display: none; + height: 0; } + +/** + * Hide the `template` element in IE, Safari, and Firefox < 22. + */ +[hidden], template { + display: none; } + +script { + display: none !important; } + +/* ========================================================================== + Base + ========================================================================== */ +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ +html { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + font-family: sans-serif; + /* 1 */ + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; + /* 2 */ + -webkit-text-size-adjust: 100%; + /* 2 */ } + +/** + * Remove default margin. + */ +body { + margin: 0; + line-height: 1; } + +/** + * Remove default outlines. + */ +a, button, :focus, a:focus, button:focus, a:active, a:hover { + outline: 0; } + +/* * + * Remove tap highlight color + */ +a { + -webkit-user-drag: none; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-tap-highlight-color: transparent; } + a[href]:hover { + cursor: pointer; } + +/* ========================================================================== + Typography + ========================================================================== */ +/** + * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. + */ +b, strong { + font-weight: bold; } + +/** + * Address styling not present in Safari 5 and Chrome. + */ +dfn { + font-style: italic; } + +/** + * Address differences between Firefox and other browsers. + */ +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; } + +/** + * Correct font family set oddly in Safari 5 and Chrome. + */ +code, kbd, pre, samp { + font-size: 1em; + font-family: monospace, serif; } + +/** + * Improve readability of pre-formatted text in all browsers. + */ +pre { + white-space: pre-wrap; } + +/** + * Set consistent quote types. + */ +q { + quotes: "\201C" "\201D" "\2018" "\2019"; } + +/** + * Address inconsistent and variable font size in all browsers. + */ +small { + font-size: 80%; } + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ +sub, sup { + position: relative; + vertical-align: baseline; + font-size: 75%; + line-height: 0; } + +sup { + top: -0.5em; } + +sub { + bottom: -0.25em; } + +/** + * Define consistent border, margin, and padding. + */ +fieldset { + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; + border: 1px solid #c0c0c0; } + +/** + * 1. Correct `color` not being inherited in IE 8/9. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ +legend { + padding: 0; + /* 2 */ + border: 0; + /* 1 */ } + +/** + * 1. Correct font family not being inherited in all browsers. + * 2. Correct font size not being inherited in all browsers. + * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. + * 4. Remove any default :focus styles + * 5. Make sure webkit font smoothing is being inherited + * 6. Remove default gradient in Android Firefox / FirefoxOS + */ +button, input, select, textarea { + margin: 0; + /* 3 */ + font-size: 100%; + /* 2 */ + font-family: inherit; + /* 1 */ + outline-offset: 0; + /* 4 */ + outline-style: none; + /* 4 */ + outline-width: 0; + /* 4 */ + -webkit-font-smoothing: inherit; + /* 5 */ + background-image: none; + /* 6 */ } + +/** + * Address Firefox 4+ setting `line-height` on `input` using `importnt` in + * the UA stylesheet. + */ +button, input { + line-height: normal; } + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. + * Correct `select` style inheritance in Firefox 4+ and Opera. + */ +button, select { + text-transform: none; } + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ +button, html input[type="button"], input[type="reset"], input[type="submit"] { + cursor: pointer; + /* 3 */ + -webkit-appearance: button; + /* 2 */ } + +/** + * Re-set default cursor for disabled elements. + */ +button[disabled], html input[disabled] { + cursor: default; } + +/** + * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome + * (include `-moz` to future-proof). + */ +input[type="search"] { + -webkit-box-sizing: content-box; + /* 2 */ + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; + /* 1 */ } + +/** + * Remove inner padding and search cancel button in Safari 5 and Chrome + * on OS X. + */ +input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; } + +/** + * Remove inner padding and border in Firefox 4+. + */ +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; } + +/** + * 1. Remove default vertical scrollbar in IE 8/9. + * 2. Improve readability and alignment in all browsers. + */ +textarea { + overflow: auto; + /* 1 */ + vertical-align: top; + /* 2 */ } + +img { + -webkit-user-drag: none; } + +/* ========================================================================== + Tables + ========================================================================== */ +/** + * Remove most spacing between table cells. + */ +table { + border-spacing: 0; + border-collapse: collapse; } + +/** + * Scaffolding + * -------------------------------------------------- + */ +*, *:before, *:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } + +html { + overflow: hidden; + -ms-touch-action: pan-y; + touch-action: pan-y; } + +body, .ionic-body { + -webkit-touch-callout: none; + -webkit-font-smoothing: antialiased; + font-smoothing: antialiased; + -webkit-text-size-adjust: none; + -moz-text-size-adjust: none; + text-size-adjust: none; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-tap-highlight-color: transparent; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + top: 0; + right: 0; + bottom: 0; + left: 0; + overflow: hidden; + margin: 0; + padding: 0; + color: #000; + word-wrap: break-word; + font-size: 14px; + font-family: "Helvetica Neue", "Roboto", sans-serif; + line-height: 20px; + text-rendering: optimizeLegibility; + -webkit-backface-visibility: hidden; + -webkit-user-drag: none; } + +body.grade-b, body.grade-c { + text-rendering: auto; } + +.content { + position: relative; } + +.scroll-content { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + overflow: hidden; + margin-top: -1px; + padding-top: 1px; + width: auto; + height: auto; } + +.scroll-content-false, .menu .scroll-content.scroll-content-false { + z-index: 11; } + +.scroll-view { + position: relative; + display: block; + overflow: hidden; + margin-top: -1px; } + +/** + * Scroll is the scroll view component available for complex and custom + * scroll view functionality. + */ +.scroll { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-touch-callout: none; + -webkit-text-size-adjust: none; + -moz-text-size-adjust: none; + text-size-adjust: none; + -webkit-transform-origin: left top; + transform-origin: left top; } + +::-webkit-scrollbar { + display: none; } + +.scroll-bar { + position: absolute; + z-index: 9999; } + +.ng-animate .scroll-bar { + visibility: hidden; } + +.scroll-bar-h { + right: 2px; + bottom: 3px; + left: 2px; + height: 3px; } + .scroll-bar-h .scroll-bar-indicator { + height: 100%; } + +.scroll-bar-v { + top: 2px; + right: 3px; + bottom: 2px; + width: 3px; } + .scroll-bar-v .scroll-bar-indicator { + width: 100%; } + +.scroll-bar-indicator { + position: absolute; + border-radius: 4px; + background: rgba(0, 0, 0, 0.3); + opacity: 1; + -webkit-transition: opacity 0.3s linear; + transition: opacity 0.3s linear; } + .scroll-bar-indicator.scroll-bar-fade-out { + opacity: 0; } + +.platform-android .scroll-bar-indicator { + border-radius: 0; } + +.grade-b .scroll-bar-indicator, .grade-c .scroll-bar-indicator { + background: #aaa; } + .grade-b .scroll-bar-indicator.scroll-bar-fade-out, .grade-c .scroll-bar-indicator.scroll-bar-fade-out { + -webkit-transition: none; + transition: none; } + +@keyframes refresh-spin { + 0% { + transform: translate3d(0, 0, 0) rotate(0); } + + 100% { + transform: translate3d(0, 0, 0) rotate(180deg); } } + +@-webkit-keyframes refresh-spin { + 0% { + -webkit-transform: translate3d(0, 0, 0) rotate(0); } + + 100% { + -webkit-transform: translate3d(0, 0, 0) rotate(180deg); } } + +@keyframes refresh-spin-back { + 0% { + transform: translate3d(0, 0, 0) rotate(180deg); } + + 100% { + transform: translate3d(0, 0, 0) rotate(0); } } + +@-webkit-keyframes refresh-spin-back { + 0% { + -webkit-transform: translate3d(0, 0, 0) rotate(180deg); } + + 100% { + -webkit-transform: translate3d(0, 0, 0) rotate(0); } } + +.scroll-refresher { + position: absolute; + top: -60px; + right: 0; + left: 0; + overflow: hidden; + margin: auto; + height: 60px; } + .scroll-refresher .ionic-refresher-content { + position: absolute; + bottom: 15px; + left: 0; + width: 100%; + color: #666666; + text-align: center; + font-size: 30px; } + .scroll-refresher .ionic-refresher-content .text-refreshing, .scroll-refresher .ionic-refresher-content .text-pulling { + font-size: 16px; + line-height: 16px; } + .scroll-refresher .ionic-refresher-content.ionic-refresher-with-text { + bottom: 10px; } + .scroll-refresher .icon-refreshing, .scroll-refresher .icon-pulling { + width: 100%; + -webkit-backface-visibility: hidden; + -webkit-transform-style: preserve-3d; + backface-visibility: hidden; + transform-style: preserve-3d; } + .scroll-refresher .icon-pulling { + -webkit-animation-name: refresh-spin-back; + animation-name: refresh-spin-back; + -webkit-animation-duration: 200ms; + animation-duration: 200ms; + -webkit-animation-timing-function: linear; + animation-timing-function: linear; + -webkit-animation-fill-mode: none; + animation-fill-mode: none; + -webkit-transform: translate3d(0, 0, 0) rotate(0deg); + transform: translate3d(0, 0, 0) rotate(0deg); } + .scroll-refresher .icon-refreshing, .scroll-refresher .text-refreshing { + display: none; } + .scroll-refresher .icon-refreshing { + -webkit-animation-duration: 1.5s; + animation-duration: 1.5s; } + .scroll-refresher.active .icon-pulling:not(.pulling-rotation-disabled) { + -webkit-animation-name: refresh-spin; + animation-name: refresh-spin; + -webkit-transform: translate3d(0, 0, 0) rotate(-180deg); + transform: translate3d(0, 0, 0) rotate(-180deg); } + .scroll-refresher.active.refreshing { + -webkit-transition: transform 0.2s; + transition: transform 0.2s; + -webkit-transition: -webkit-transform 0.2s; + transition: -webkit-transform 0.2s; + -webkit-transform: scale(1, 1); + transform: scale(1, 1); } + .scroll-refresher.active.refreshing .icon-pulling, .scroll-refresher.active.refreshing .text-pulling { + display: none; } + .scroll-refresher.active.refreshing .icon-refreshing, .scroll-refresher.active.refreshing .text-refreshing { + display: block; } + .scroll-refresher.active.refreshing.refreshing-tail { + -webkit-transform: scale(0, 0); + transform: scale(0, 0); } + +ion-infinite-scroll { + height: 60px; + width: 100%; + opacity: 0; + display: block; + -webkit-transition: opacity 0.25s; + transition: opacity 0.25s; + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-direction: normal; + -webkit-box-orient: horizontal; + -webkit-flex-direction: row; + -moz-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + -moz-justify-content: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; } + ion-infinite-scroll .icon { + color: #666666; + font-size: 30px; + color: #666666; } + ion-infinite-scroll.active { + opacity: 1; } + +.overflow-scroll { + overflow-x: hidden; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + top: 0; + right: 0; + bottom: 0; + left: 0; + position: absolute; } + .overflow-scroll .scroll { + position: static; + height: 100%; + -webkit-transform: translate3d(0, 0, 0); } + +/* If you change these, change platform.scss as well */ +.has-header { + top: 44px; } + +.no-header { + top: 0; } + +.has-subheader { + top: 88px; } + +.has-tabs-top { + top: 93px; } + +.has-header.has-subheader.has-tabs-top { + top: 137px; } + +.has-footer { + bottom: 44px; } + +.has-subfooter { + bottom: 88px; } + +.has-tabs, .bar-footer.has-tabs { + bottom: 49px; } + +.has-footer.has-tabs { + bottom: 93px; } + +.pane { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + -webkit-transition-duration: 0; + transition-duration: 0; + z-index: 1; } + +.view { + z-index: 1; } + +.pane, .view { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #fff; + overflow: hidden; } + +.view-container { + position: absolute; + display: block; + width: 100%; + height: 100%; } + +/** + * Typography + * -------------------------------------------------- + */ +p { + margin: 0 0 10px; } + +small { + font-size: 85%; } + +cite { + font-style: normal; } + +.text-left { + text-align: left; } + +.text-right { + text-align: right; } + +.text-center { + text-align: center; } + +h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { + color: #000; + font-weight: 500; + font-family: "Helvetica Neue", "Roboto", sans-serif; + line-height: 1.2; } + h1 small, h2 small, h3 small, h4 small, h5 small, h6 small, .h1 small, .h2 small, .h3 small, .h4 small, .h5 small, .h6 small { + font-weight: normal; + line-height: 1; } + +h1, .h1, h2, .h2, h3, .h3 { + margin-top: 20px; + margin-bottom: 10px; } + h1:first-child, .h1:first-child, h2:first-child, .h2:first-child, h3:first-child, .h3:first-child { + margin-top: 0; } + h1 + h1, h1 + .h1, h1 + h2, h1 + .h2, h1 + h3, h1 + .h3, .h1 + h1, .h1 + .h1, .h1 + h2, .h1 + .h2, .h1 + h3, .h1 + .h3, h2 + h1, h2 + .h1, h2 + h2, h2 + .h2, h2 + h3, h2 + .h3, .h2 + h1, .h2 + .h1, .h2 + h2, .h2 + .h2, .h2 + h3, .h2 + .h3, h3 + h1, h3 + .h1, h3 + h2, h3 + .h2, h3 + h3, h3 + .h3, .h3 + h1, .h3 + .h1, .h3 + h2, .h3 + .h2, .h3 + h3, .h3 + .h3 { + margin-top: 10px; } + +h4, .h4, h5, .h5, h6, .h6 { + margin-top: 10px; + margin-bottom: 10px; } + +h1, .h1 { + font-size: 36px; } + +h2, .h2 { + font-size: 30px; } + +h3, .h3 { + font-size: 24px; } + +h4, .h4 { + font-size: 18px; } + +h5, .h5 { + font-size: 14px; } + +h6, .h6 { + font-size: 12px; } + +h1 small, .h1 small { + font-size: 24px; } + +h2 small, .h2 small { + font-size: 18px; } + +h3 small, .h3 small, h4 small, .h4 small { + font-size: 14px; } + +dl { + margin-bottom: 20px; } + +dt, dd { + line-height: 1.42857; } + +dt { + font-weight: bold; } + +blockquote { + margin: 0 0 20px; + padding: 10px 20px; + border-left: 5px solid gray; } + blockquote p { + font-weight: 300; + font-size: 17.5px; + line-height: 1.25; } + blockquote p:last-child { + margin-bottom: 0; } + blockquote small { + display: block; + line-height: 1.42857; } + blockquote small:before { + content: '\2014 \00A0'; } + +q:before, q:after, blockquote:before, blockquote:after { + content: ""; } + +address { + display: block; + margin-bottom: 20px; + font-style: normal; + line-height: 1.42857; } + +a.subdued { + padding-right: 10px; + color: #888; + text-decoration: none; } + a.subdued:hover { + text-decoration: none; } + a.subdued:last-child { + padding-right: 0; } + +/** + * Action Sheets + * -------------------------------------------------- + */ +.action-sheet-backdrop { + -webkit-transition: background-color 300ms ease-in-out; + transition: background-color 300ms ease-in-out; + position: fixed; + top: 0; + left: 0; + z-index: 11; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0); } + .action-sheet-backdrop.active { + background-color: rgba(0, 0, 0, 0.5); } + +.action-sheet-wrapper { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + -webkit-transition: all ease-in-out 300ms; + transition: all ease-in-out 300ms; + position: absolute; + bottom: 0; + width: 100%; } + +.action-sheet-up { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + +.action-sheet { + margin-left: 15px; + margin-right: 15px; + width: auto; + z-index: 11; + overflow: hidden; } + .action-sheet .button { + display: block; + padding: 1px; + width: 100%; + border-radius: 0; + background-color: transparent; + color: #387ef5; + font-size: 18px; } + .action-sheet .button.destructive { + color: #ef473a; } + +.action-sheet-title { + padding: 10px; + color: #666666; + text-align: center; + font-size: 12px; } + +.action-sheet-group { + margin-bottom: 5px; + border-radius: 3px 3px 3px 3px; + background-color: #fff; } + .action-sheet-group .button { + border-width: 1px 0px 0px 0px; + border-radius: 0; } + .action-sheet-group .button.active { + background-color: transparent; + color: inherit; } + .action-sheet-group .button:first-child:last-child { + border-width: 0; } + +.action-sheet-open { + pointer-events: none; } + .action-sheet-open.modal-open .modal { + pointer-events: none; } + .action-sheet-open .action-sheet-backdrop { + pointer-events: auto; } + +.backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 11; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.4); + visibility: hidden; + opacity: 0; + -webkit-transition: 0.1s opacity linear; + transition: 0.1s opacity linear; } + .backdrop.visible { + visibility: visible; } + .backdrop.active { + opacity: 1; } + +/** + * Bar (Headers and Footers) + * -------------------------------------------------- + */ +.bar { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: absolute; + right: 0; + left: 0; + z-index: 9; + box-sizing: border-box; + padding: 5px; + width: 100%; + height: 44px; + border-width: 0; + border-style: solid; + border-top: 1px solid transparent; + border-bottom: 1px solid #ddd; + background-color: white; + /* border-width: 1px will actually create 2 device pixels on retina */ + /* this nifty trick sets an actual 1px border on hi-res displays */ + background-size: 0; } + @media (min--moz-device-pixel-ratio: 1.5), (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5), (min-resolution: 144dpi), (min-resolution: 1.5dppx) { + .bar { + border: none; + background-image: linear-gradient(0deg, #ddd, #ddd 50%, transparent 50%); + background-position: bottom; + background-size: 100% 1px; + background-repeat: no-repeat; } } + .bar.bar-clear { + border: none; + background: none; + color: #fff; } + .bar.bar-clear .button { + color: #fff; } + .bar.bar-clear .title { + color: #fff; } + .bar.item-input-inset .item-input-wrapper { + margin-top: -1px; } + .bar.item-input-inset .item-input-wrapper input { + padding-left: 8px; + width: 94%; + height: 28px; + background: transparent; } + .bar.bar-light { + border-color: #ddd; + background-color: white; + background-image: linear-gradient(0deg, #ddd, #ddd 50%, transparent 50%); + color: #444; } + .bar.bar-light .title { + color: #444; } + .bar.bar-light.bar-footer { + background-image: linear-gradient(180deg, #ddd, #ddd 50%, transparent 50%); } + .bar.bar-stable { + border-color: #b2b2b2; + background-color: #f8f8f8; + background-image: linear-gradient(0deg, #b2b2b2, #b2b2b2 50%, transparent 50%); + color: #444; } + .bar.bar-stable .title { + color: #444; } + .bar.bar-stable.bar-footer { + background-image: linear-gradient(180deg, #b2b2b2, #b2b2b2 50%, transparent 50%); } + .bar.bar-positive { + border-color: #0c63ee; + background-color: #387ef5; + background-image: linear-gradient(0deg, #0c63ee, #0c63ee 50%, transparent 50%); + color: #fff; } + .bar.bar-positive .title { + color: #fff; } + .bar.bar-positive.bar-footer { + background-image: linear-gradient(180deg, #0c63ee, #0c63ee 50%, transparent 50%); } + .bar.bar-calm { + border-color: #0a9ec7; + background-color: #11c1f3; + background-image: linear-gradient(0deg, #0a9ec7, #0a9ec7 50%, transparent 50%); + color: #fff; } + .bar.bar-calm .title { + color: #fff; } + .bar.bar-calm.bar-footer { + background-image: linear-gradient(180deg, #0a9ec7, #0a9ec7 50%, transparent 50%); } + .bar.bar-assertive { + border-color: #e42012; + background-color: #ef473a; + background-image: linear-gradient(0deg, #e42012, #e42012 50%, transparent 50%); + color: #fff; } + .bar.bar-assertive .title { + color: #fff; } + .bar.bar-assertive.bar-footer { + background-image: linear-gradient(180deg, #e42012, #e42012 50%, transparent 50%); } + .bar.bar-balanced { + border-color: #28a54c; + background-color: #33cd5f; + background-image: linear-gradient(0deg, #28a54c, #28a54c 50%, transparent 50%); + color: #fff; } + .bar.bar-balanced .title { + color: #fff; } + .bar.bar-balanced.bar-footer { + background-image: linear-gradient(180deg, #28a54c, #0c63ee 50%, transparent 50%); } + .bar.bar-energized { + border-color: #e6b400; + background-color: #ffc900; + background-image: linear-gradient(0deg, #e6b400, #e6b400 50%, transparent 50%); + color: #fff; } + .bar.bar-energized .title { + color: #fff; } + .bar.bar-energized.bar-footer { + background-image: linear-gradient(180deg, #e6b400, #e6b400 50%, transparent 50%); } + .bar.bar-royal { + border-color: #6b46e5; + background-color: #886aea; + background-image: linear-gradient(0deg, #6b46e5, #6b46e5 50%, transparent 50%); + color: #fff; } + .bar.bar-royal .title { + color: #fff; } + .bar.bar-royal.bar-footer { + background-image: linear-gradient(180deg, #6b46e5, #6b46e5 50%, transparent 50%); } + .bar.bar-dark { + border-color: #111; + background-color: #444444; + background-image: linear-gradient(0deg, #111, #111 50%, transparent 50%); + color: #fff; } + .bar.bar-dark .title { + color: #fff; } + .bar.bar-dark.bar-footer { + background-image: linear-gradient(180deg, #111, #111 50%, transparent 50%); } + .bar .title { + position: absolute; + top: 0; + right: 0; + left: 0; + z-index: 0; + overflow: hidden; + margin: 0 10px; + min-width: 30px; + height: 43px; + text-align: center; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 17px; + font-weight: 500; + line-height: 44px; } + .bar .title.title-left { + text-align: left; } + .bar .title.title-right { + text-align: right; } + .bar .title a { + color: inherit; } + .bar .button { + z-index: 1; + padding: 0 8px; + min-width: initial; + min-height: 31px; + font-weight: 400; + font-size: 13px; + line-height: 32px; } + .bar .button.button-icon:before, .bar .button .icon:before, .bar .button.icon:before, .bar .button.icon-left:before, .bar .button.icon-right:before { + padding-right: 2px; + padding-left: 2px; + font-size: 20px; + line-height: 32px; } + .bar .button.button-icon { + font-size: 17px; } + .bar .button.button-icon .icon:before, .bar .button.button-icon:before, .bar .button.button-icon.icon-left:before, .bar .button.button-icon.icon-right:before { + vertical-align: top; + font-size: 32px; + line-height: 32px; } + .bar .button.button-clear { + padding-right: 2px; + padding-left: 2px; + font-weight: 300; + font-size: 17px; } + .bar .button.button-clear .icon:before, .bar .button.button-clear.icon:before, .bar .button.button-clear.icon-left:before, .bar .button.button-clear.icon-right:before { + font-size: 32px; + line-height: 32px; } + .bar .button.back-button { + display: block; + margin-right: 5px; + padding: 0; + white-space: nowrap; + font-weight: 400; } + .bar .button.back-button.active, .bar .button.back-button.activated { + opacity: 0.2; } + .bar .button-bar > .button, .bar .buttons > .button { + min-height: 31px; + line-height: 32px; } + .bar .button-bar + .button, .bar .button + .button-bar { + margin-left: 5px; } + .bar .buttons, .bar .buttons.primary-buttons, .bar .buttons.secondary-buttons { + display: inherit; } + .bar .buttons span { + display: inline-block; } + .bar .buttons-left span { + margin-right: 5px; } + .bar .buttons-right span { + margin-left: 5px; } + .bar .title + .button:last-child, .bar > .button + .button:last-child, .bar > .button.pull-right, .bar .buttons.pull-right, .bar .title + .buttons { + position: absolute; + top: 5px; + right: 5px; + bottom: 5px; } + +.bar-light .button { + border-color: #ddd; + background-color: white; + color: #444; } + .bar-light .button:hover { + color: #444; + text-decoration: none; } + .bar-light .button.active, .bar-light .button.activated { + border-color: #ccc; + background-color: #fafafa; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .bar-light .button.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #444; + font-size: 17px; } + .bar-light .button.button-icon { + border-color: transparent; + background: none; } + +.bar-stable .button { + border-color: #b2b2b2; + background-color: #f8f8f8; + color: #444; } + .bar-stable .button:hover { + color: #444; + text-decoration: none; } + .bar-stable .button.active, .bar-stable .button.activated { + border-color: #a2a2a2; + background-color: #e5e5e5; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .bar-stable .button.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #444; + font-size: 17px; } + .bar-stable .button.button-icon { + border-color: transparent; + background: none; } + +.bar-positive .button { + border-color: #0c63ee; + background-color: #387ef5; + color: #fff; } + .bar-positive .button:hover { + color: #fff; + text-decoration: none; } + .bar-positive .button.active, .bar-positive .button.activated { + border-color: #0c63ee; + background-color: #0c63ee; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .bar-positive .button.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-positive .button.button-icon { + border-color: transparent; + background: none; } + +.bar-calm .button { + border-color: #0a9ec7; + background-color: #11c1f3; + color: #fff; } + .bar-calm .button:hover { + color: #fff; + text-decoration: none; } + .bar-calm .button.active, .bar-calm .button.activated { + border-color: #0a9ec7; + background-color: #0a9ec7; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .bar-calm .button.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-calm .button.button-icon { + border-color: transparent; + background: none; } + +.bar-assertive .button { + border-color: #e42012; + background-color: #ef473a; + color: #fff; } + .bar-assertive .button:hover { + color: #fff; + text-decoration: none; } + .bar-assertive .button.active, .bar-assertive .button.activated { + border-color: #e42012; + background-color: #e42012; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .bar-assertive .button.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-assertive .button.button-icon { + border-color: transparent; + background: none; } + +.bar-balanced .button { + border-color: #28a54c; + background-color: #33cd5f; + color: #fff; } + .bar-balanced .button:hover { + color: #fff; + text-decoration: none; } + .bar-balanced .button.active, .bar-balanced .button.activated { + border-color: #28a54c; + background-color: #28a54c; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .bar-balanced .button.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-balanced .button.button-icon { + border-color: transparent; + background: none; } + +.bar-energized .button { + border-color: #e6b400; + background-color: #ffc900; + color: #fff; } + .bar-energized .button:hover { + color: #fff; + text-decoration: none; } + .bar-energized .button.active, .bar-energized .button.activated { + border-color: #e6b400; + background-color: #e6b400; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .bar-energized .button.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-energized .button.button-icon { + border-color: transparent; + background: none; } + +.bar-royal .button { + border-color: #6b46e5; + background-color: #886aea; + color: #fff; } + .bar-royal .button:hover { + color: #fff; + text-decoration: none; } + .bar-royal .button.active, .bar-royal .button.activated { + border-color: #6b46e5; + background-color: #6b46e5; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .bar-royal .button.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-royal .button.button-icon { + border-color: transparent; + background: none; } + +.bar-dark .button { + border-color: #111; + background-color: #444444; + color: #fff; } + .bar-dark .button:hover { + color: #fff; + text-decoration: none; } + .bar-dark .button.active, .bar-dark .button.activated { + border-color: #000; + background-color: #262626; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .bar-dark .button.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #fff; + font-size: 17px; } + .bar-dark .button.button-icon { + border-color: transparent; + background: none; } + +.bar-header { + top: 0; + border-top-width: 0; + border-bottom-width: 1px; } + .bar-header.has-tabs-top { + border-bottom-width: 0px; + background-image: none; } + +.bar-footer { + bottom: 0; + border-top-width: 1px; + border-bottom-width: 0; + background-position: top; + height: 44px; } + .bar-footer.item-input-inset { + position: absolute; } + +.bar-tabs { + padding: 0; } + +.bar-subheader { + top: 44px; + display: block; + height: 44px; } + +.bar-subfooter { + bottom: 44px; + display: block; + height: 44px; } + +.nav-bar-block { + position: absolute; + top: 0; + right: 0; + left: 0; + z-index: 9; } + +.bar .back-button.hide, .bar .buttons .hide { + display: none; } + +/** + * Tabs + * -------------------------------------------------- + * A navigation bar with any number of tab items supported. + */ +.tabs { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-direction: normal; + -webkit-box-orient: horizontal; + -webkit-flex-direction: horizontal; + -moz-flex-direction: horizontal; + -ms-flex-direction: horizontal; + flex-direction: horizontal; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + -moz-justify-content: center; + justify-content: center; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + border-color: #b2b2b2; + background-color: #f8f8f8; + background-image: linear-gradient(0deg, #b2b2b2, #b2b2b2 50%, transparent 50%); + color: #444; + position: absolute; + bottom: 0; + z-index: 5; + width: 100%; + height: 49px; + border-style: solid; + border-top-width: 1px; + background-size: 0; + line-height: 49px; } + .tabs .tab-item .badge { + background-color: #444; + color: #f8f8f8; } + @media (min--moz-device-pixel-ratio: 1.5), (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5), (min-resolution: 144dpi), (min-resolution: 1.5dppx) { + .tabs { + padding-top: 2px; + border-top: none !important; + border-bottom: none; + background-position: top; + background-size: 100% 1px; + background-repeat: no-repeat; } } + +/* Allow parent element of tabs to define color, or just the tab itself */ +.tabs-light > .tabs, .tabs.tabs-light { + border-color: #ddd; + background-color: #fff; + background-image: linear-gradient(0deg, #ddd, #ddd 50%, transparent 50%); + color: #444; } + .tabs-light > .tabs .tab-item .badge, .tabs.tabs-light .tab-item .badge { + background-color: #444; + color: #fff; } + +.tabs-stable > .tabs, .tabs.tabs-stable { + border-color: #b2b2b2; + background-color: #f8f8f8; + background-image: linear-gradient(0deg, #b2b2b2, #b2b2b2 50%, transparent 50%); + color: #444; } + .tabs-stable > .tabs .tab-item .badge, .tabs.tabs-stable .tab-item .badge { + background-color: #444; + color: #f8f8f8; } + +.tabs-positive > .tabs, .tabs.tabs-positive { + border-color: #0c63ee; + background-color: #387ef5; + background-image: linear-gradient(0deg, #0c63ee, #0c63ee 50%, transparent 50%); + color: #fff; } + .tabs-positive > .tabs .tab-item .badge, .tabs.tabs-positive .tab-item .badge { + background-color: #fff; + color: #387ef5; } + +.tabs-calm > .tabs, .tabs.tabs-calm { + border-color: #0a9ec7; + background-color: #11c1f3; + background-image: linear-gradient(0deg, #0a9ec7, #0a9ec7 50%, transparent 50%); + color: #fff; } + .tabs-calm > .tabs .tab-item .badge, .tabs.tabs-calm .tab-item .badge { + background-color: #fff; + color: #11c1f3; } + +.tabs-assertive > .tabs, .tabs.tabs-assertive { + border-color: #e42012; + background-color: #ef473a; + background-image: linear-gradient(0deg, #e42012, #e42012 50%, transparent 50%); + color: #fff; } + .tabs-assertive > .tabs .tab-item .badge, .tabs.tabs-assertive .tab-item .badge { + background-color: #fff; + color: #ef473a; } + +.tabs-balanced > .tabs, .tabs.tabs-balanced { + border-color: #28a54c; + background-color: #33cd5f; + background-image: linear-gradient(0deg, #28a54c, #28a54c 50%, transparent 50%); + color: #fff; } + .tabs-balanced > .tabs .tab-item .badge, .tabs.tabs-balanced .tab-item .badge { + background-color: #fff; + color: #33cd5f; } + +.tabs-energized > .tabs, .tabs.tabs-energized { + border-color: #e6b400; + background-color: #ffc900; + background-image: linear-gradient(0deg, #e6b400, #e6b400 50%, transparent 50%); + color: #fff; } + .tabs-energized > .tabs .tab-item .badge, .tabs.tabs-energized .tab-item .badge { + background-color: #fff; + color: #ffc900; } + +.tabs-royal > .tabs, .tabs.tabs-royal { + border-color: #6b46e5; + background-color: #886aea; + background-image: linear-gradient(0deg, #6b46e5, #6b46e5 50%, transparent 50%); + color: #fff; } + .tabs-royal > .tabs .tab-item .badge, .tabs.tabs-royal .tab-item .badge { + background-color: #fff; + color: #886aea; } + +.tabs-dark > .tabs, .tabs.tabs-dark { + border-color: #111; + background-color: #444; + background-image: linear-gradient(0deg, #111, #111 50%, transparent 50%); + color: #fff; } + .tabs-dark > .tabs .tab-item .badge, .tabs.tabs-dark .tab-item .badge { + background-color: #fff; + color: #444; } + +.tabs-striped .tabs { + background-color: white; + background-image: none; + border: none; + border-bottom: 1px solid #ddd; + padding-top: 2px; } +.tabs-striped .tab-item.tab-item-active, .tabs-striped .tab-item.active, .tabs-striped .tab-item.activated { + margin-top: -2px; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #444; } + .tabs-striped .tab-item.tab-item-active .badge, .tabs-striped .tab-item.active .badge, .tabs-striped .tab-item.activated .badge { + top: 2px; + opacity: 1; } +.tabs-striped.tabs-light .tabs { + background-color: #fff; } +.tabs-striped.tabs-light .tab-item { + color: rgba(68, 68, 68, 0.4); + opacity: 1; } + .tabs-striped.tabs-light .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-light .tab-item.tab-item-active, .tabs-striped.tabs-light .tab-item.active, .tabs-striped.tabs-light .tab-item.activated { + margin-top: -2px; + color: #444; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #444; } +.tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } +.tabs-striped.tabs-stable .tabs { + background-color: #f8f8f8; } +.tabs-striped.tabs-stable .tab-item { + color: rgba(68, 68, 68, 0.4); + opacity: 1; } + .tabs-striped.tabs-stable .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-stable .tab-item.tab-item-active, .tabs-striped.tabs-stable .tab-item.active, .tabs-striped.tabs-stable .tab-item.activated { + margin-top: -2px; + color: #444; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #444; } +.tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } +.tabs-striped.tabs-positive .tabs { + background-color: #387ef5; } +.tabs-striped.tabs-positive .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-positive .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-positive .tab-item.tab-item-active, .tabs-striped.tabs-positive .tab-item.active, .tabs-striped.tabs-positive .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } +.tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } +.tabs-striped.tabs-calm .tabs { + background-color: #11c1f3; } +.tabs-striped.tabs-calm .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-calm .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-calm .tab-item.tab-item-active, .tabs-striped.tabs-calm .tab-item.active, .tabs-striped.tabs-calm .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } +.tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } +.tabs-striped.tabs-assertive .tabs { + background-color: #ef473a; } +.tabs-striped.tabs-assertive .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-assertive .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-assertive .tab-item.tab-item-active, .tabs-striped.tabs-assertive .tab-item.active, .tabs-striped.tabs-assertive .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } +.tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } +.tabs-striped.tabs-balanced .tabs { + background-color: #33cd5f; } +.tabs-striped.tabs-balanced .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-balanced .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-balanced .tab-item.tab-item-active, .tabs-striped.tabs-balanced .tab-item.active, .tabs-striped.tabs-balanced .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } +.tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } +.tabs-striped.tabs-energized .tabs { + background-color: #ffc900; } +.tabs-striped.tabs-energized .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-energized .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-energized .tab-item.tab-item-active, .tabs-striped.tabs-energized .tab-item.active, .tabs-striped.tabs-energized .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } +.tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } +.tabs-striped.tabs-royal .tabs { + background-color: #886aea; } +.tabs-striped.tabs-royal .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-royal .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-royal .tab-item.tab-item-active, .tabs-striped.tabs-royal .tab-item.active, .tabs-striped.tabs-royal .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } +.tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } +.tabs-striped.tabs-dark .tabs { + background-color: #444; } +.tabs-striped.tabs-dark .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-dark .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-dark .tab-item.tab-item-active, .tabs-striped.tabs-dark .tab-item.active, .tabs-striped.tabs-dark .tab-item.activated { + margin-top: -2px; + color: #fff; + border-style: solid; + border-width: 2px 0 0 0; + border-color: #fff; } +.tabs-striped.tabs-top .tab-item.tab-item-active .badge, .tabs-striped.tabs-top .tab-item.active .badge, .tabs-striped.tabs-top .tab-item.activated .badge { + top: 4%; } +.tabs-striped.tabs-background-light .tabs { + background-color: #fff; + background-image: none; } +.tabs-striped.tabs-background-stable .tabs { + background-color: #f8f8f8; + background-image: none; } +.tabs-striped.tabs-background-positive .tabs { + background-color: #387ef5; + background-image: none; } +.tabs-striped.tabs-background-calm .tabs { + background-color: #11c1f3; + background-image: none; } +.tabs-striped.tabs-background-assertive .tabs { + background-color: #ef473a; + background-image: none; } +.tabs-striped.tabs-background-balanced .tabs { + background-color: #33cd5f; + background-image: none; } +.tabs-striped.tabs-background-energized .tabs { + background-color: #ffc900; + background-image: none; } +.tabs-striped.tabs-background-royal .tabs { + background-color: #886aea; + background-image: none; } +.tabs-striped.tabs-background-dark .tabs { + background-color: #444; + background-image: none; } +.tabs-striped.tabs-color-light .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-light .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-light .tab-item.tab-item-active, .tabs-striped.tabs-color-light .tab-item.active, .tabs-striped.tabs-color-light .tab-item.activated { + margin-top: -2px; + color: #fff; + border: 0 solid #fff; + border-top-width: 2px; } + .tabs-striped.tabs-color-light .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-light .tab-item.active .badge, .tabs-striped.tabs-color-light .tab-item.activated .badge { + top: 2px; + opacity: 1; } +.tabs-striped.tabs-color-stable .tab-item { + color: rgba(248, 248, 248, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-stable .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-stable .tab-item.tab-item-active, .tabs-striped.tabs-color-stable .tab-item.active, .tabs-striped.tabs-color-stable .tab-item.activated { + margin-top: -2px; + color: #f8f8f8; + border: 0 solid #f8f8f8; + border-top-width: 2px; } + .tabs-striped.tabs-color-stable .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-stable .tab-item.active .badge, .tabs-striped.tabs-color-stable .tab-item.activated .badge { + top: 2px; + opacity: 1; } +.tabs-striped.tabs-color-positive .tab-item { + color: rgba(56, 126, 245, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-positive .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-positive .tab-item.tab-item-active, .tabs-striped.tabs-color-positive .tab-item.active, .tabs-striped.tabs-color-positive .tab-item.activated { + margin-top: -2px; + color: #387ef5; + border: 0 solid #387ef5; + border-top-width: 2px; } + .tabs-striped.tabs-color-positive .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-positive .tab-item.active .badge, .tabs-striped.tabs-color-positive .tab-item.activated .badge { + top: 2px; + opacity: 1; } +.tabs-striped.tabs-color-calm .tab-item { + color: rgba(17, 193, 243, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-calm .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-calm .tab-item.tab-item-active, .tabs-striped.tabs-color-calm .tab-item.active, .tabs-striped.tabs-color-calm .tab-item.activated { + margin-top: -2px; + color: #11c1f3; + border: 0 solid #11c1f3; + border-top-width: 2px; } + .tabs-striped.tabs-color-calm .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-calm .tab-item.active .badge, .tabs-striped.tabs-color-calm .tab-item.activated .badge { + top: 2px; + opacity: 1; } +.tabs-striped.tabs-color-assertive .tab-item { + color: rgba(239, 71, 58, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-assertive .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-assertive .tab-item.tab-item-active, .tabs-striped.tabs-color-assertive .tab-item.active, .tabs-striped.tabs-color-assertive .tab-item.activated { + margin-top: -2px; + color: #ef473a; + border: 0 solid #ef473a; + border-top-width: 2px; } + .tabs-striped.tabs-color-assertive .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-assertive .tab-item.active .badge, .tabs-striped.tabs-color-assertive .tab-item.activated .badge { + top: 2px; + opacity: 1; } +.tabs-striped.tabs-color-balanced .tab-item { + color: rgba(51, 205, 95, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-balanced .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-balanced .tab-item.tab-item-active, .tabs-striped.tabs-color-balanced .tab-item.active, .tabs-striped.tabs-color-balanced .tab-item.activated { + margin-top: -2px; + color: #33cd5f; + border: 0 solid #33cd5f; + border-top-width: 2px; } + .tabs-striped.tabs-color-balanced .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-balanced .tab-item.active .badge, .tabs-striped.tabs-color-balanced .tab-item.activated .badge { + top: 2px; + opacity: 1; } +.tabs-striped.tabs-color-energized .tab-item { + color: rgba(255, 201, 0, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-energized .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-energized .tab-item.tab-item-active, .tabs-striped.tabs-color-energized .tab-item.active, .tabs-striped.tabs-color-energized .tab-item.activated { + margin-top: -2px; + color: #ffc900; + border: 0 solid #ffc900; + border-top-width: 2px; } + .tabs-striped.tabs-color-energized .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-energized .tab-item.active .badge, .tabs-striped.tabs-color-energized .tab-item.activated .badge { + top: 2px; + opacity: 1; } +.tabs-striped.tabs-color-royal .tab-item { + color: rgba(136, 106, 234, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-royal .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-royal .tab-item.tab-item-active, .tabs-striped.tabs-color-royal .tab-item.active, .tabs-striped.tabs-color-royal .tab-item.activated { + margin-top: -2px; + color: #886aea; + border: 0 solid #886aea; + border-top-width: 2px; } + .tabs-striped.tabs-color-royal .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-royal .tab-item.active .badge, .tabs-striped.tabs-color-royal .tab-item.activated .badge { + top: 2px; + opacity: 1; } +.tabs-striped.tabs-color-dark .tab-item { + color: rgba(68, 68, 68, 0.4); + opacity: 1; } + .tabs-striped.tabs-color-dark .tab-item .badge { + opacity: 0.4; } + .tabs-striped.tabs-color-dark .tab-item.tab-item-active, .tabs-striped.tabs-color-dark .tab-item.active, .tabs-striped.tabs-color-dark .tab-item.activated { + margin-top: -2px; + color: #444; + border: 0 solid #444; + border-top-width: 2px; } + .tabs-striped.tabs-color-dark .tab-item.tab-item-active .badge, .tabs-striped.tabs-color-dark .tab-item.active .badge, .tabs-striped.tabs-color-dark .tab-item.activated .badge { + top: 2px; + opacity: 1; } + +.tabs-background-light .tabs, .tabs-background-light > .tabs { + background-color: #fff; + background-image: linear-gradient(0deg, #ddd, #ddd 50%, transparent 50%); + border-color: #ddd; } + +.tabs-background-stable .tabs, .tabs-background-stable > .tabs { + background-color: #f8f8f8; + background-image: linear-gradient(0deg, #b2b2b2, #b2b2b2 50%, transparent 50%); + border-color: #b2b2b2; } + +.tabs-background-positive .tabs, .tabs-background-positive > .tabs { + background-color: #387ef5; + background-image: linear-gradient(0deg, #0c63ee, #0c63ee 50%, transparent 50%); + border-color: #0c63ee; } + +.tabs-background-calm .tabs, .tabs-background-calm > .tabs { + background-color: #11c1f3; + background-image: linear-gradient(0deg, #0a9ec7, #0a9ec7 50%, transparent 50%); + border-color: #0a9ec7; } + +.tabs-background-assertive .tabs, .tabs-background-assertive > .tabs { + background-color: #ef473a; + background-image: linear-gradient(0deg, #e42012, #e42012 50%, transparent 50%); + border-color: #e42012; } + +.tabs-background-balanced .tabs, .tabs-background-balanced > .tabs { + background-color: #33cd5f; + background-image: linear-gradient(0deg, #28a54c, #28a54c 50%, transparent 50%); + border-color: #28a54c; } + +.tabs-background-energized .tabs, .tabs-background-energized > .tabs { + background-color: #ffc900; + background-image: linear-gradient(0deg, #e6b400, #e6b400 50%, transparent 50%); + border-color: #e6b400; } + +.tabs-background-royal .tabs, .tabs-background-royal > .tabs { + background-color: #886aea; + background-image: linear-gradient(0deg, #6b46e5, #6b46e5 50%, transparent 50%); + border-color: #6b46e5; } + +.tabs-background-dark .tabs, .tabs-background-dark > .tabs { + background-color: #444; + background-image: linear-gradient(0deg, #111, #111 50%, transparent 50%); + border-color: #111; } + +.tabs-color-light .tab-item { + color: rgba(255, 255, 255, 0.4); + opacity: 1; } + .tabs-color-light .tab-item .badge { + opacity: 0.4; } + .tabs-color-light .tab-item.tab-item-active, .tabs-color-light .tab-item.active, .tabs-color-light .tab-item.activated { + color: #fff; + border: 0 solid #fff; } + .tabs-color-light .tab-item.tab-item-active .badge, .tabs-color-light .tab-item.active .badge, .tabs-color-light .tab-item.activated .badge { + opacity: 1; } + +.tabs-color-stable .tab-item { + color: rgba(248, 248, 248, 0.4); + opacity: 1; } + .tabs-color-stable .tab-item .badge { + opacity: 0.4; } + .tabs-color-stable .tab-item.tab-item-active, .tabs-color-stable .tab-item.active, .tabs-color-stable .tab-item.activated { + color: #f8f8f8; + border: 0 solid #f8f8f8; } + .tabs-color-stable .tab-item.tab-item-active .badge, .tabs-color-stable .tab-item.active .badge, .tabs-color-stable .tab-item.activated .badge { + opacity: 1; } + +.tabs-color-positive .tab-item { + color: rgba(56, 126, 245, 0.4); + opacity: 1; } + .tabs-color-positive .tab-item .badge { + opacity: 0.4; } + .tabs-color-positive .tab-item.tab-item-active, .tabs-color-positive .tab-item.active, .tabs-color-positive .tab-item.activated { + color: #387ef5; + border: 0 solid #387ef5; } + .tabs-color-positive .tab-item.tab-item-active .badge, .tabs-color-positive .tab-item.active .badge, .tabs-color-positive .tab-item.activated .badge { + opacity: 1; } + +.tabs-color-calm .tab-item { + color: rgba(17, 193, 243, 0.4); + opacity: 1; } + .tabs-color-calm .tab-item .badge { + opacity: 0.4; } + .tabs-color-calm .tab-item.tab-item-active, .tabs-color-calm .tab-item.active, .tabs-color-calm .tab-item.activated { + color: #11c1f3; + border: 0 solid #11c1f3; } + .tabs-color-calm .tab-item.tab-item-active .badge, .tabs-color-calm .tab-item.active .badge, .tabs-color-calm .tab-item.activated .badge { + opacity: 1; } + +.tabs-color-assertive .tab-item { + color: rgba(239, 71, 58, 0.4); + opacity: 1; } + .tabs-color-assertive .tab-item .badge { + opacity: 0.4; } + .tabs-color-assertive .tab-item.tab-item-active, .tabs-color-assertive .tab-item.active, .tabs-color-assertive .tab-item.activated { + color: #ef473a; + border: 0 solid #ef473a; } + .tabs-color-assertive .tab-item.tab-item-active .badge, .tabs-color-assertive .tab-item.active .badge, .tabs-color-assertive .tab-item.activated .badge { + opacity: 1; } + +.tabs-color-balanced .tab-item { + color: rgba(51, 205, 95, 0.4); + opacity: 1; } + .tabs-color-balanced .tab-item .badge { + opacity: 0.4; } + .tabs-color-balanced .tab-item.tab-item-active, .tabs-color-balanced .tab-item.active, .tabs-color-balanced .tab-item.activated { + color: #33cd5f; + border: 0 solid #33cd5f; } + .tabs-color-balanced .tab-item.tab-item-active .badge, .tabs-color-balanced .tab-item.active .badge, .tabs-color-balanced .tab-item.activated .badge { + opacity: 1; } + +.tabs-color-energized .tab-item { + color: rgba(255, 201, 0, 0.4); + opacity: 1; } + .tabs-color-energized .tab-item .badge { + opacity: 0.4; } + .tabs-color-energized .tab-item.tab-item-active, .tabs-color-energized .tab-item.active, .tabs-color-energized .tab-item.activated { + color: #ffc900; + border: 0 solid #ffc900; } + .tabs-color-energized .tab-item.tab-item-active .badge, .tabs-color-energized .tab-item.active .badge, .tabs-color-energized .tab-item.activated .badge { + opacity: 1; } + +.tabs-color-royal .tab-item { + color: rgba(136, 106, 234, 0.4); + opacity: 1; } + .tabs-color-royal .tab-item .badge { + opacity: 0.4; } + .tabs-color-royal .tab-item.tab-item-active, .tabs-color-royal .tab-item.active, .tabs-color-royal .tab-item.activated { + color: #886aea; + border: 0 solid #886aea; } + .tabs-color-royal .tab-item.tab-item-active .badge, .tabs-color-royal .tab-item.active .badge, .tabs-color-royal .tab-item.activated .badge { + opacity: 1; } + +.tabs-color-dark .tab-item { + color: rgba(68, 68, 68, 0.4); + opacity: 1; } + .tabs-color-dark .tab-item .badge { + opacity: 0.4; } + .tabs-color-dark .tab-item.tab-item-active, .tabs-color-dark .tab-item.active, .tabs-color-dark .tab-item.activated { + color: #444; + border: 0 solid #444; } + .tabs-color-dark .tab-item.tab-item-active .badge, .tabs-color-dark .tab-item.active .badge, .tabs-color-dark .tab-item.activated .badge { + opacity: 1; } + +ion-tabs.tabs-color-active-light .tab-item { + color: #444; } + ion-tabs.tabs-color-active-light .tab-item.tab-item-active, ion-tabs.tabs-color-active-light .tab-item.active, ion-tabs.tabs-color-active-light .tab-item.activated { + color: #fff; } +ion-tabs.tabs-color-active-stable .tab-item { + color: #444; } + ion-tabs.tabs-color-active-stable .tab-item.tab-item-active, ion-tabs.tabs-color-active-stable .tab-item.active, ion-tabs.tabs-color-active-stable .tab-item.activated { + color: #f8f8f8; } +ion-tabs.tabs-color-active-positive .tab-item { + color: #444; } + ion-tabs.tabs-color-active-positive .tab-item.tab-item-active, ion-tabs.tabs-color-active-positive .tab-item.active, ion-tabs.tabs-color-active-positive .tab-item.activated { + color: #387ef5; } +ion-tabs.tabs-color-active-calm .tab-item { + color: #444; } + ion-tabs.tabs-color-active-calm .tab-item.tab-item-active, ion-tabs.tabs-color-active-calm .tab-item.active, ion-tabs.tabs-color-active-calm .tab-item.activated { + color: #11c1f3; } +ion-tabs.tabs-color-active-assertive .tab-item { + color: #444; } + ion-tabs.tabs-color-active-assertive .tab-item.tab-item-active, ion-tabs.tabs-color-active-assertive .tab-item.active, ion-tabs.tabs-color-active-assertive .tab-item.activated { + color: #ef473a; } +ion-tabs.tabs-color-active-balanced .tab-item { + color: #444; } + ion-tabs.tabs-color-active-balanced .tab-item.tab-item-active, ion-tabs.tabs-color-active-balanced .tab-item.active, ion-tabs.tabs-color-active-balanced .tab-item.activated { + color: #33cd5f; } +ion-tabs.tabs-color-active-energized .tab-item { + color: #444; } + ion-tabs.tabs-color-active-energized .tab-item.tab-item-active, ion-tabs.tabs-color-active-energized .tab-item.active, ion-tabs.tabs-color-active-energized .tab-item.activated { + color: #ffc900; } +ion-tabs.tabs-color-active-royal .tab-item { + color: #444; } + ion-tabs.tabs-color-active-royal .tab-item.tab-item-active, ion-tabs.tabs-color-active-royal .tab-item.active, ion-tabs.tabs-color-active-royal .tab-item.activated { + color: #886aea; } +ion-tabs.tabs-color-active-dark .tab-item { + color: #fff; } + ion-tabs.tabs-color-active-dark .tab-item.tab-item-active, ion-tabs.tabs-color-active-dark .tab-item.active, ion-tabs.tabs-color-active-dark .tab-item.activated { + color: #444; } + +.tabs-top.tabs-striped { + padding-bottom: 0; } + .tabs-top.tabs-striped .tab-item { + background: transparent; + -webkit-transition: all 0.1s ease; + -moz-transition: all 0.1s ease; + -ms-transition: all 0.1s ease; + -o-transition: all 0.1s ease; + transition: all 0.1s ease; } + .tabs-top.tabs-striped .tab-item.tab-item-active, .tabs-top.tabs-striped .tab-item.active, .tabs-top.tabs-striped .tab-item.activated { + margin-top: 0; + margin-bottom: -2px; + border-width: 0px 0px 2px 0px !important; + border-style: solid; } + .tabs-top.tabs-striped .tab-item .badge { + -webkit-transition: all 0.2s ease; + -moz-transition: all 0.2s ease; + -ms-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; } + +/* Allow parent element to have tabs-top */ +/* If you change this, change platform.scss as well */ +.tabs-top > .tabs, .tabs.tabs-top { + top: 44px; + padding-top: 0; + background-position: bottom; + border-top-width: 0; + border-bottom-width: 1px; } + .tabs-top > .tabs .tab-item.tab-item-active .badge, .tabs-top > .tabs .tab-item.active .badge, .tabs-top > .tabs .tab-item.activated .badge, .tabs.tabs-top .tab-item.tab-item-active .badge, .tabs.tabs-top .tab-item.active .badge, .tabs.tabs-top .tab-item.activated .badge { + top: 4%; } + +.tabs-top ~ .bar-header { + border-bottom-width: 0; } + +.tab-item { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + display: block; + overflow: hidden; + max-width: 150px; + height: 100%; + color: inherit; + text-align: center; + text-decoration: none; + text-overflow: ellipsis; + white-space: nowrap; + font-weight: 400; + font-size: 14px; + font-family: "Helvetica Neue", "Roboto", sans-serif; + opacity: 0.7; } + .tab-item:hover { + cursor: pointer; } + .tab-item.tab-hidden { + display: none; } + +.tabs-item-hide > .tabs, .tabs.tabs-item-hide { + display: none; } + +.tabs-icon-top > .tabs .tab-item, .tabs-icon-top.tabs .tab-item, .tabs-icon-bottom > .tabs .tab-item, .tabs-icon-bottom.tabs .tab-item { + font-size: 10px; + line-height: 14px; } + +.tab-item .icon { + display: block; + margin: 0 auto; + height: 32px; + font-size: 32px; } + +.tabs-icon-left.tabs .tab-item, .tabs-icon-left > .tabs .tab-item, .tabs-icon-right.tabs .tab-item, .tabs-icon-right > .tabs .tab-item { + font-size: 10px; } + .tabs-icon-left.tabs .tab-item .icon, .tabs-icon-left > .tabs .tab-item .icon, .tabs-icon-right.tabs .tab-item .icon, .tabs-icon-right > .tabs .tab-item .icon { + display: inline-block; + vertical-align: top; + margin-top: -0.1em; } + .tabs-icon-left.tabs .tab-item .icon:before, .tabs-icon-left > .tabs .tab-item .icon:before, .tabs-icon-right.tabs .tab-item .icon:before, .tabs-icon-right > .tabs .tab-item .icon:before { + font-size: 24px; + line-height: 49px; } + +.tabs-icon-left > .tabs .tab-item .icon, .tabs-icon-left.tabs .tab-item .icon { + padding-right: 3px; } + +.tabs-icon-right > .tabs .tab-item .icon, .tabs-icon-right.tabs .tab-item .icon { + padding-left: 3px; } + +.tabs-icon-only > .tabs .icon, .tabs-icon-only.tabs .icon { + line-height: inherit; } + +.tab-item.has-badge { + position: relative; } + +.tab-item .badge { + position: absolute; + top: 4%; + right: 33%; + right: calc(50% - 26px); + padding: 1px 6px; + height: auto; + font-size: 12px; + line-height: 16px; } + +/* Navigational tab */ +/* Active state for tab */ +.tab-item.tab-item-active, .tab-item.active, .tab-item.activated { + opacity: 1; } + .tab-item.tab-item-active.tab-item-light, .tab-item.active.tab-item-light, .tab-item.activated.tab-item-light { + color: #fff; } + .tab-item.tab-item-active.tab-item-stable, .tab-item.active.tab-item-stable, .tab-item.activated.tab-item-stable { + color: #f8f8f8; } + .tab-item.tab-item-active.tab-item-positive, .tab-item.active.tab-item-positive, .tab-item.activated.tab-item-positive { + color: #387ef5; } + .tab-item.tab-item-active.tab-item-calm, .tab-item.active.tab-item-calm, .tab-item.activated.tab-item-calm { + color: #11c1f3; } + .tab-item.tab-item-active.tab-item-assertive, .tab-item.active.tab-item-assertive, .tab-item.activated.tab-item-assertive { + color: #ef473a; } + .tab-item.tab-item-active.tab-item-balanced, .tab-item.active.tab-item-balanced, .tab-item.activated.tab-item-balanced { + color: #33cd5f; } + .tab-item.tab-item-active.tab-item-energized, .tab-item.active.tab-item-energized, .tab-item.activated.tab-item-energized { + color: #ffc900; } + .tab-item.tab-item-active.tab-item-royal, .tab-item.active.tab-item-royal, .tab-item.activated.tab-item-royal { + color: #886aea; } + .tab-item.tab-item-active.tab-item-dark, .tab-item.active.tab-item-dark, .tab-item.activated.tab-item-dark { + color: #444; } + +.item.tabs { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + padding: 0; } + .item.tabs .icon:before { + position: relative; } + +.tab-item.disabled, .tab-item[disabled] { + opacity: 0.4; + cursor: default; + pointer-events: none; } + +/** + * Menus + * -------------------------------------------------- + * Side panel structure + */ +.menu { + position: absolute; + top: 0; + bottom: 0; + z-index: 0; + overflow: hidden; + min-height: 100%; + max-height: 100%; + width: 275px; + background-color: #fff; } + .menu .scroll-content { + z-index: 10; } + .menu .bar-header { + z-index: 11; } + +.menu-content { + -webkit-transform: none; + transform: none; + box-shadow: -1px 0px 2px rgba(0, 0, 0, 0.2), 1px 0px 2px rgba(0, 0, 0, 0.2); } + +.menu-open .menu-content .pane, .menu-open .menu-content .scroll-content { + pointer-events: none; } + +.grade-b .menu-content, .grade-c .menu-content { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + right: -1px; + left: -1px; + border-right: 1px solid #ccc; + border-left: 1px solid #ccc; + box-shadow: none; } + +.menu-left { + left: 0; } + +.menu-right { + right: 0; } + +.aside-open.aside-resizing .menu-right { + display: none; } + +.menu-animated { + -webkit-transition: -webkit-transform 200ms ease; + transition: transform 200ms ease; } + +/** + * Modals + * -------------------------------------------------- + * Modals are independent windows that slide in from off-screen. + */ +.modal-backdrop { + -webkit-transition: background-color 300ms ease-in-out; + transition: background-color 300ms ease-in-out; + position: fixed; + top: 0; + left: 0; + z-index: 10; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0); } + .modal-backdrop.active { + background-color: rgba(0, 0, 0, 0.5); } + +.modal { + display: block; + position: absolute; + top: 0; + z-index: 10; + overflow: hidden; + min-height: 100%; + width: 100%; + background-color: #fff; } + +@media (min-width: 680px) { + .modal { + top: 20%; + right: 20%; + bottom: 20%; + left: 20%; + overflow: visible; + min-height: 240px; + width: 60%; } + .modal.ng-leave-active { + bottom: 0; } + .platform-ios.platform-cordova .modal-wrapper .modal .bar-header:not(.bar-subheader) { + height: 44px; } + .platform-ios.platform-cordova .modal-wrapper .modal .bar-header:not(.bar-subheader) > * { + margin-top: 0; } + .platform-ios.platform-cordova .modal-wrapper .modal .tabs-top > .tabs, .platform-ios.platform-cordova .modal-wrapper .modal .tabs.tabs-top { + top: 44px; } + .platform-ios.platform-cordova .modal-wrapper .modal .has-header, .platform-ios.platform-cordova .modal-wrapper .modal .bar-subheader { + top: 44px; } + .platform-ios.platform-cordova .modal-wrapper .modal .has-subheader { + top: 88px; } + .platform-ios.platform-cordova .modal-wrapper .modal .has-tabs-top { + top: 93px; } + .platform-ios.platform-cordova .modal-wrapper .modal .has-header.has-subheader.has-tabs-top { + top: 137px; } } + +.modal-open { + pointer-events: none; } + .modal-open .modal, .modal-open .modal-backdrop { + pointer-events: auto; } + .modal-open.loading-active .modal, .modal-open.loading-active .modal-backdrop { + pointer-events: none; } + +/** + * Popovers + * -------------------------------------------------- + * Popovers are independent views which float over content + */ +.popover-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 10; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0); } + .popover-backdrop.active { + background-color: rgba(0, 0, 0, 0.1); } + +.popover { + position: absolute; + top: 25%; + left: 50%; + z-index: 10; + display: block; + margin-top: 12px; + margin-left: -110px; + height: 280px; + width: 220px; + background-color: #fff; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4); + opacity: 0; } + .popover .item:first-child { + border-top: 0; } + .popover .item:last-child { + border-bottom: 0; } + .popover.popover-bottom { + margin-top: -12px; } + +.popover, .popover .bar-header { + border-radius: 2px; } + +.popover .scroll-content { + z-index: 1; + margin: 2px 0; } + +.popover .bar-header { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; } + +.popover .has-header { + border-top-right-radius: 0; + border-top-left-radius: 0; } + +.popover-arrow { + display: none; } + +.platform-ios .popover { + box-shadow: 0 0 40px rgba(0, 0, 0, 0.08); } +.platform-ios .popover, .platform-ios .popover .bar-header { + border-radius: 10px; } +.platform-ios .popover .scroll-content { + margin: 8px 0; + border-radius: 10px; } +.platform-ios .popover .scroll-content.has-header { + margin-top: 0; } +.platform-ios .popover-arrow { + position: absolute; + display: block; + top: -17px; + width: 30px; + height: 19px; + overflow: hidden; } + .platform-ios .popover-arrow:after { + position: absolute; + top: 12px; + left: 5px; + width: 20px; + height: 20px; + background-color: #fff; + border-radius: 3px; + content: ''; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); } +.platform-ios .popover-bottom .popover-arrow { + top: auto; + bottom: -10px; } + .platform-ios .popover-bottom .popover-arrow:after { + top: -6px; } + +.platform-android .popover { + margin-top: -32px; + background-color: #fafafa; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35); } + .platform-android .popover .item { + border-color: #fafafa; + background-color: #fafafa; + color: #4d4d4d; } + .platform-android .popover.popover-bottom { + margin-top: 32px; } +.platform-android .popover-backdrop, .platform-android .popover-backdrop.active { + background-color: transparent; } + +.popover-open { + pointer-events: none; } + .popover-open .popover, .popover-open .popover-backdrop { + pointer-events: auto; } + .popover-open.loading-active .popover, .popover-open.loading-active .popover-backdrop { + pointer-events: none; } + +@media (min-width: 680px) { + .popover { + width: 360px; } } + +/** + * Popups + * -------------------------------------------------- + */ +.popup-container { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: rgba(0, 0, 0, 0); + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + -moz-justify-content: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + z-index: 12; + visibility: hidden; } + .popup-container.popup-showing { + visibility: visible; } + .popup-container.popup-hidden .popup { + -webkit-animation-name: scaleOut; + animation-name: scaleOut; + -webkit-animation-duration: 0.1s; + animation-duration: 0.1s; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; } + .popup-container.active .popup { + -webkit-animation-name: superScaleIn; + animation-name: superScaleIn; + -webkit-animation-duration: 0.2s; + animation-duration: 0.2s; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; } + .popup-container .popup { + width: 250px; + max-width: 100%; + max-height: 90%; + border-radius: 0px; + background-color: rgba(255, 255, 255, 0.9); + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-direction: normal; + -webkit-box-orient: vertical; + -webkit-flex-direction: column; + -moz-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } + +.popup-head { + padding: 15px 10px; + border-bottom: 1px solid #eee; + text-align: center; } + +.popup-title { + margin: 0; + padding: 0; + font-size: 15px; } + +.popup-sub-title { + margin: 5px 0 0 0; + padding: 0; + font-weight: normal; + font-size: 11px; } + +.popup-body { + padding: 10px; + overflow: scroll; } + +.popup-buttons { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-direction: normal; + -webkit-box-orient: horizontal; + -webkit-flex-direction: row; + -moz-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 10px; + min-height: 65px; } + .popup-buttons .button { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + display: block; + min-height: 45px; + border-radius: 2px; + line-height: 20px; + margin-right: 5px; } + .popup-buttons .button:last-child { + margin-right: 0px; } + +.popup-open { + pointer-events: none; } + .popup-open.modal-open .modal { + pointer-events: none; } + .popup-open .popup-backdrop, .popup-open .popup { + pointer-events: auto; } + +/** + * Loading + * -------------------------------------------------- + */ +.loading-container { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + z-index: 13; + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + -moz-justify-content: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + -webkit-transition: 0.2s opacity linear; + transition: 0.2s opacity linear; + visibility: hidden; + opacity: 0; } + .loading-container:not(.visible) .icon { + display: none; } + .loading-container.visible { + visibility: visible; } + .loading-container.active { + opacity: 1; } + .loading-container .loading { + padding: 20px; + border-radius: 5px; + background-color: rgba(0, 0, 0, 0.7); + color: #fff; + text-align: center; + text-overflow: ellipsis; + font-size: 15px; } + .loading-container .loading h1, .loading-container .loading h2, .loading-container .loading h3, .loading-container .loading h4, .loading-container .loading h5, .loading-container .loading h6 { + color: #fff; } + +/** + * Items + * -------------------------------------------------- + */ +.item { + border-color: #ddd; + background-color: #fff; + color: #444; + position: relative; + z-index: 2; + display: block; + margin: -1px; + padding: 16px; + border-width: 1px; + border-style: solid; + font-size: 16px; } + .item h2 { + margin: 0 0 2px 0; + font-size: 16px; + font-weight: normal; } + .item h3 { + margin: 0 0 4px 0; + font-size: 14px; } + .item h4 { + margin: 0 0 4px 0; + font-size: 12px; } + .item h5, .item h6 { + margin: 0 0 3px 0; + font-size: 10px; } + .item p { + color: #666; + font-size: 14px; + margin-bottom: 2px; } + .item h1:last-child, .item h2:last-child, .item h3:last-child, .item h4:last-child, .item h5:last-child, .item h6:last-child, .item p:last-child { + margin-bottom: 0; } + .item .badge { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + position: absolute; + top: 16px; + right: 32px; } + .item.item-button-right .badge { + right: 67px; } + .item.item-divider .badge { + top: 8px; } + .item .badge + .badge { + margin-right: 5px; } + .item.item-light { + border-color: #ddd; + background-color: #fff; + color: #444; } + .item.item-stable { + border-color: #b2b2b2; + background-color: #f8f8f8; + color: #444; } + .item.item-positive { + border-color: #0c63ee; + background-color: #387ef5; + color: #fff; } + .item.item-calm { + border-color: #0a9ec7; + background-color: #11c1f3; + color: #fff; } + .item.item-assertive { + border-color: #e42012; + background-color: #ef473a; + color: #fff; } + .item.item-balanced { + border-color: #28a54c; + background-color: #33cd5f; + color: #fff; } + .item.item-energized { + border-color: #e6b400; + background-color: #ffc900; + color: #fff; } + .item.item-royal { + border-color: #6b46e5; + background-color: #886aea; + color: #fff; } + .item.item-dark { + border-color: #111; + background-color: #444; + color: #fff; } + .item[ng-click]:hover { + cursor: pointer; } + +.list-borderless .item, .item-borderless { + border-width: 0; } + +.item.active, .item.activated, .item-complex.active .item-content, .item-complex.activated .item-content, .item .item-content.active, .item .item-content.activated { + border-color: #ccc; + background-color: #D9D9D9; } + .item.active.item-light, .item.activated.item-light, .item-complex.active .item-content.item-light, .item-complex.activated .item-content.item-light, .item .item-content.active.item-light, .item .item-content.activated.item-light { + border-color: #ccc; + background-color: #fafafa; } + .item.active.item-stable, .item.activated.item-stable, .item-complex.active .item-content.item-stable, .item-complex.activated .item-content.item-stable, .item .item-content.active.item-stable, .item .item-content.activated.item-stable { + border-color: #a2a2a2; + background-color: #e5e5e5; } + .item.active.item-positive, .item.activated.item-positive, .item-complex.active .item-content.item-positive, .item-complex.activated .item-content.item-positive, .item .item-content.active.item-positive, .item .item-content.activated.item-positive { + border-color: #0c63ee; + background-color: #0c63ee; } + .item.active.item-calm, .item.activated.item-calm, .item-complex.active .item-content.item-calm, .item-complex.activated .item-content.item-calm, .item .item-content.active.item-calm, .item .item-content.activated.item-calm { + border-color: #0a9ec7; + background-color: #0a9ec7; } + .item.active.item-assertive, .item.activated.item-assertive, .item-complex.active .item-content.item-assertive, .item-complex.activated .item-content.item-assertive, .item .item-content.active.item-assertive, .item .item-content.activated.item-assertive { + border-color: #e42012; + background-color: #e42012; } + .item.active.item-balanced, .item.activated.item-balanced, .item-complex.active .item-content.item-balanced, .item-complex.activated .item-content.item-balanced, .item .item-content.active.item-balanced, .item .item-content.activated.item-balanced { + border-color: #28a54c; + background-color: #28a54c; } + .item.active.item-energized, .item.activated.item-energized, .item-complex.active .item-content.item-energized, .item-complex.activated .item-content.item-energized, .item .item-content.active.item-energized, .item .item-content.activated.item-energized { + border-color: #e6b400; + background-color: #e6b400; } + .item.active.item-royal, .item.activated.item-royal, .item-complex.active .item-content.item-royal, .item-complex.activated .item-content.item-royal, .item .item-content.active.item-royal, .item .item-content.activated.item-royal { + border-color: #6b46e5; + background-color: #6b46e5; } + .item.active.item-dark, .item.activated.item-dark, .item-complex.active .item-content.item-dark, .item-complex.activated .item-content.item-dark, .item .item-content.active.item-dark, .item .item-content.activated.item-dark { + border-color: #000; + background-color: #262626; } + +.item, .item h1, .item h2, .item h3, .item h4, .item h5, .item h6, .item p, .item-content, .item-content h1, .item-content h2, .item-content h3, .item-content h4, .item-content h5, .item-content h6, .item-content p { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + +a.item { + color: inherit; + text-decoration: none; } + a.item:hover, a.item:focus { + text-decoration: none; } + +/** + * Complex Items + * -------------------------------------------------- + * Adding .item-complex allows the .item to be slidable and + * have options underneath the button, but also requires an + * additional .item-content element inside .item. + * Basically .item-complex removes any default settings which + * .item added, so that .item-content looks them as just .item. + */ +.item-complex, a.item.item-complex, button.item.item-complex { + padding: 0; } + +.item-complex .item-content, .item-radio .item-content { + position: relative; + z-index: 2; + padding: 16px 49px 16px 16px; + border: none; + background-color: white; } + +a.item-content { + display: block; + color: inherit; + text-decoration: none; } + +.item-text-wrap .item, .item-text-wrap .item-content, .item-text-wrap, .item-text-wrap h1, .item-text-wrap h2, .item-text-wrap h3, .item-text-wrap h4, .item-text-wrap h5, .item-text-wrap h6, .item-text-wrap p, .item-complex.item-text-wrap .item-content, .item-body h1, .item-body h2, .item-body h3, .item-body h4, .item-body h5, .item-body h6, .item-body p { + overflow: visible; + white-space: normal; } + +.item-complex.item-text-wrap, .item-complex.item-text-wrap h1, .item-complex.item-text-wrap h2, .item-complex.item-text-wrap h3, .item-complex.item-text-wrap h4, .item-complex.item-text-wrap h5, .item-complex.item-text-wrap h6, .item-complex.item-text-wrap p { + overflow: visible; + white-space: normal; } + +.item-complex.item-light > .item-content { + border-color: #ddd; + background-color: #fff; + color: #444; } + .item-complex.item-light > .item-content.active, .item-complex.item-light > .item-content:active { + border-color: #ccc; + background-color: #fafafa; } +.item-complex.item-stable > .item-content { + border-color: #b2b2b2; + background-color: #f8f8f8; + color: #444; } + .item-complex.item-stable > .item-content.active, .item-complex.item-stable > .item-content:active { + border-color: #a2a2a2; + background-color: #e5e5e5; } +.item-complex.item-positive > .item-content { + border-color: #0c63ee; + background-color: #387ef5; + color: #fff; } + .item-complex.item-positive > .item-content.active, .item-complex.item-positive > .item-content:active { + border-color: #0c63ee; + background-color: #0c63ee; } +.item-complex.item-calm > .item-content { + border-color: #0a9ec7; + background-color: #11c1f3; + color: #fff; } + .item-complex.item-calm > .item-content.active, .item-complex.item-calm > .item-content:active { + border-color: #0a9ec7; + background-color: #0a9ec7; } +.item-complex.item-assertive > .item-content { + border-color: #e42012; + background-color: #ef473a; + color: #fff; } + .item-complex.item-assertive > .item-content.active, .item-complex.item-assertive > .item-content:active { + border-color: #e42012; + background-color: #e42012; } +.item-complex.item-balanced > .item-content { + border-color: #28a54c; + background-color: #33cd5f; + color: #fff; } + .item-complex.item-balanced > .item-content.active, .item-complex.item-balanced > .item-content:active { + border-color: #28a54c; + background-color: #28a54c; } +.item-complex.item-energized > .item-content { + border-color: #e6b400; + background-color: #ffc900; + color: #fff; } + .item-complex.item-energized > .item-content.active, .item-complex.item-energized > .item-content:active { + border-color: #e6b400; + background-color: #e6b400; } +.item-complex.item-royal > .item-content { + border-color: #6b46e5; + background-color: #886aea; + color: #fff; } + .item-complex.item-royal > .item-content.active, .item-complex.item-royal > .item-content:active { + border-color: #6b46e5; + background-color: #6b46e5; } +.item-complex.item-dark > .item-content { + border-color: #111; + background-color: #444; + color: #fff; } + .item-complex.item-dark > .item-content.active, .item-complex.item-dark > .item-content:active { + border-color: #000; + background-color: #262626; } + +/** + * Item Icons + * -------------------------------------------------- + */ +.item-icon-left .icon, .item-icon-right .icon { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: absolute; + top: 0; + height: 100%; + font-size: 32px; } + .item-icon-left .icon:before, .item-icon-right .icon:before { + display: block; + width: 32px; + text-align: center; } + +.item .fill-icon { + min-width: 30px; + min-height: 30px; + font-size: 28px; } + +.item-icon-left { + padding-left: 54px; } + .item-icon-left .icon { + left: 11px; } + +.item-complex.item-icon-left { + padding-left: 0; } + .item-complex.item-icon-left .item-content { + padding-left: 54px; } + +.item-icon-right { + padding-right: 54px; } + .item-icon-right .icon { + right: 11px; } + +.item-complex.item-icon-right { + padding-right: 0; } + .item-complex.item-icon-right .item-content { + padding-right: 54px; } + +.item-icon-left.item-icon-right .icon:first-child { + right: auto; } + +.item-icon-left.item-icon-right .icon:last-child, .item-icon-left .item-delete .icon { + left: auto; } + +.item-icon-left .icon-accessory, .item-icon-right .icon-accessory { + color: #ccc; + font-size: 16px; } + +.item-icon-left .icon-accessory { + left: 3px; } + +.item-icon-right .icon-accessory { + right: 3px; } + +/** + * Item Button + * -------------------------------------------------- + * An item button is a child button inside an .item (not the entire .item) + */ +.item-button-left { + padding-left: 72px; } + +.item-button-left > .button, .item-button-left .item-content > .button { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: absolute; + top: 8px; + left: 11px; + min-width: 34px; + min-height: 34px; + font-size: 18px; + line-height: 32px; } + .item-button-left > .button .icon:before, .item-button-left .item-content > .button .icon:before { + position: relative; + left: auto; + width: auto; + line-height: 31px; } + .item-button-left > .button > .button, .item-button-left .item-content > .button > .button { + margin: 0px 2px; + min-height: 34px; + font-size: 18px; + line-height: 32px; } + +.item-button-right, a.item.item-button-right, button.item.item-button-right { + padding-right: 80px; } + +.item-button-right > .button, .item-button-right .item-content > .button, .item-button-right > .buttons, .item-button-right .item-content > .buttons { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: absolute; + top: 8px; + right: 16px; + min-width: 34px; + min-height: 34px; + font-size: 18px; + line-height: 32px; } + .item-button-right > .button .icon:before, .item-button-right .item-content > .button .icon:before, .item-button-right > .buttons .icon:before, .item-button-right .item-content > .buttons .icon:before { + position: relative; + left: auto; + width: auto; + line-height: 31px; } + .item-button-right > .button > .button, .item-button-right .item-content > .button > .button, .item-button-right > .buttons > .button, .item-button-right .item-content > .buttons > .button { + margin: 0px 2px; + min-width: 34px; + min-height: 34px; + font-size: 18px; + line-height: 32px; } + +.item-avatar, .item-avatar .item-content, .item-avatar-left, .item-avatar-left .item-content { + padding-left: 72px; + min-height: 72px; } + .item-avatar > img:first-child, .item-avatar .item-image, .item-avatar .item-content > img:first-child, .item-avatar .item-content .item-image, .item-avatar-left > img:first-child, .item-avatar-left .item-image, .item-avatar-left .item-content > img:first-child, .item-avatar-left .item-content .item-image { + position: absolute; + top: 16px; + left: 16px; + max-width: 40px; + max-height: 40px; + width: 100%; + border-radius: 50%; } + +.item-avatar-right, .item-avatar-right .item-content { + padding-right: 72px; + min-height: 72px; } + .item-avatar-right > img:first-child, .item-avatar-right .item-image, .item-avatar-right .item-content > img:first-child, .item-avatar-right .item-content .item-image { + position: absolute; + top: 16px; + right: 16px; + max-width: 40px; + max-height: 40px; + width: 100%; + border-radius: 50%; } + +.item-thumbnail-left, .item-thumbnail-left .item-content { + padding-top: 8px; + padding-left: 106px; + min-height: 100px; } + .item-thumbnail-left > img:first-child, .item-thumbnail-left .item-image, .item-thumbnail-left .item-content > img:first-child, .item-thumbnail-left .item-content .item-image { + position: absolute; + top: 10px; + left: 10px; + max-width: 80px; + max-height: 80px; + width: 100%; } + +.item-avatar.item-complex, .item-avatar-left.item-complex, .item-thumbnail-left.item-complex { + padding-top: 0; + padding-left: 0; } + +.item-thumbnail-right, .item-thumbnail-right .item-content { + padding-top: 8px; + padding-right: 106px; + min-height: 100px; } + .item-thumbnail-right > img:first-child, .item-thumbnail-right .item-image, .item-thumbnail-right .item-content > img:first-child, .item-thumbnail-right .item-content .item-image { + position: absolute; + top: 10px; + right: 10px; + max-width: 80px; + max-height: 80px; + width: 100%; } + +.item-avatar-right.item-complex, .item-thumbnail-right.item-complex { + padding-top: 0; + padding-right: 0; } + +.item-image { + padding: 0; + text-align: center; } + .item-image img:first-child, .item-image .list-img { + width: 100%; + vertical-align: middle; } + +.item-body { + overflow: auto; + padding: 16px; + text-overflow: inherit; + white-space: normal; } + .item-body h1, .item-body h2, .item-body h3, .item-body h4, .item-body h5, .item-body h6, .item-body p { + margin-top: 16px; + margin-bottom: 16px; } + +.item-divider { + padding-top: 8px; + padding-bottom: 8px; + min-height: 30px; + background-color: #f5f5f5; + color: #222; + font-weight: 500; } + +.platform-ios .item-divider-platform, .item-divider-ios { + padding-top: 26px; + text-transform: uppercase; + font-weight: 300; + font-size: 13px; + background-color: #efeff4; + color: #555; } + +.platform-android .item-divider-platform, .item-divider-android { + font-weight: 300; + font-size: 13px; } + +.item-note { + float: right; + color: #aaa; + font-size: 14px; } + +.item-left-editable .item-content, .item-right-editable .item-content { + -webkit-transition-duration: 250ms; + transition-duration: 250ms; + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; + -webkit-transition-property: -webkit-transform; + -moz-transition-property: -moz-transform; + transition-property: transform; } + +.list-left-editing .item-left-editable .item-content, .item-left-editing.item-left-editable .item-content { + -webkit-transform: translate3d(50px, 0, 0); + transform: translate3d(50px, 0, 0); } + +.list-right-editing .item-right-editable .item-content, .item-right-editing.item-right-editable .item-content { + -webkit-transform: translate3d(-50px, 0, 0); + transform: translate3d(-50px, 0, 0); } + +.item-remove-animate.ng-leave { + -webkit-transition-duration: 300ms; + transition-duration: 300ms; } +.item-remove-animate.ng-leave .item-content, .item-remove-animate.ng-leave:last-of-type { + -webkit-transition-duration: 300ms; + transition-duration: 300ms; + -webkit-transition-timing-function: ease-in; + transition-timing-function: ease-in; + -webkit-transition-property: all; + transition-property: all; } +.item-remove-animate.ng-leave.ng-leave-active .item-content { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0) !important; + transform: translate3d(-100%, 0, 0) !important; } +.item-remove-animate.ng-leave.ng-leave-active:last-of-type { + opacity: 0; } +.item-remove-animate.ng-leave.ng-leave-active ~ ion-item:not(.ng-leave) { + -webkit-transform: translate3d(0, -webkit-calc(-100% + 1px), 0); + transform: translate3d(0, calc(-100% + 1px), 0); + -webkit-transition-duration: 300ms; + transition-duration: 300ms; + -webkit-transition-timing-function: cubic-bezier(0.25, 0.81, 0.24, 1); + transition-timing-function: cubic-bezier(0.25, 0.81, 0.24, 1); + -webkit-transition-property: all; + transition-property: all; } + +.item-left-edit { + -webkit-transition: all ease-in-out 125ms; + transition: all ease-in-out 125ms; + position: absolute; + top: 0; + left: 0; + z-index: 0; + width: 50px; + height: 100%; + line-height: 100%; + display: none; + opacity: 0; + -webkit-transform: translate3d(-21px, 0, 0); + transform: translate3d(-21px, 0, 0); } + .item-left-edit .button { + height: 100%; } + .item-left-edit .button.icon { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: absolute; + top: 0; + height: 100%; } + .item-left-edit.visible { + display: block; } + .item-left-edit.visible.active { + opacity: 1; + -webkit-transform: translate3d(8px, 0, 0); + transform: translate3d(8px, 0, 0); } + +.list-left-editing .item-left-edit { + -webkit-transition-delay: 125ms; + transition-delay: 125ms; } + +.item-delete .button.icon { + color: #ef473a; + font-size: 24px; } + .item-delete .button.icon:hover { + opacity: 0.7; } + +.item-right-edit { + -webkit-transition: all ease-in-out 125ms; + transition: all ease-in-out 125ms; + position: absolute; + top: 0; + right: 0; + z-index: 0; + width: 75px; + height: 100%; + background: inherit; + padding-left: 20px; + display: none; + opacity: 0; + -webkit-transform: translate3d(25px, 0, 0); + transform: translate3d(25px, 0, 0); } + .item-right-edit .button { + min-width: 50px; + height: 100%; } + .item-right-edit .button.icon { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: absolute; + top: 0; + height: 100%; + font-size: 32px; } + .item-right-edit.visible { + display: block; + z-index: 3; } + .item-right-edit.visible.active { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + +.list-right-editing .item-right-edit { + -webkit-transition-delay: 125ms; + transition-delay: 125ms; } + +.item-reorder .button.icon { + color: #444; + font-size: 32px; } + +.item-reordering { + position: absolute; + left: 0; + top: 0; + z-index: 9; + width: 100%; + box-shadow: 0px 0px 10px 0px #aaa; } + .item-reordering .item-reorder { + z-index: 1; } + +.item-placeholder { + opacity: 0.7; } + +/** + * The hidden right-side buttons that can be exposed under a list item + * with dragging. + */ +.item-options { + position: absolute; + top: 0; + right: 0; + z-index: 1; + height: 100%; } + .item-options .button { + height: 100%; + border: none; + border-radius: 0; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -moz-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; } + .item-options .button:before { + margin: 0 auto; } + +/** + * Lists + * -------------------------------------------------- + */ +.list { + position: relative; + padding-top: 1px; + padding-bottom: 1px; + padding-left: 0; + margin-bottom: 20px; } + +.list:last-child { + margin-bottom: 0px; } + .list:last-child.card { + margin-bottom: 40px; } + +/** + * List Header + * -------------------------------------------------- + */ +.list-header { + margin-top: 20px; + padding: 5px 15px; + background-color: transparent; + color: #222; + font-weight: bold; } + +.card.list .list-item { + padding-right: 1px; + padding-left: 1px; } + +/** + * Cards and Inset Lists + * -------------------------------------------------- + * A card and list-inset are close to the same thing, except a card as a box shadow. + */ +.card, .list-inset { + overflow: hidden; + margin: 20px 10px; + border-radius: 2px; + background-color: #fff; } + +.card { + padding-top: 1px; + padding-bottom: 1px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); } + .card .item { + border-left: 0; + border-right: 0; } + .card .item:first-child { + border-top: 0; } + .card .item:last-child { + border-bottom: 0; } + +.padding .card, .padding .list-inset { + margin-left: 0; + margin-right: 0; } + +.card .item:first-child, .list-inset .item:first-child, .padding > .list .item:first-child { + border-top-left-radius: 2px; + border-top-right-radius: 2px; } + .card .item:first-child .item-content, .list-inset .item:first-child .item-content, .padding > .list .item:first-child .item-content { + border-top-left-radius: 2px; + border-top-right-radius: 2px; } +.card .item:last-child, .list-inset .item:last-child, .padding > .list .item:last-child { + border-bottom-right-radius: 2px; + border-bottom-left-radius: 2px; } + .card .item:last-child .item-content, .list-inset .item:last-child .item-content, .padding > .list .item:last-child .item-content { + border-bottom-right-radius: 2px; + border-bottom-left-radius: 2px; } + +.card .item:last-child, .list-inset .item:last-child { + margin-bottom: -1px; } + +.card .item, .list-inset .item, .padding > .list .item, .padding-horizontal > .list .item { + margin-right: 0; + margin-left: 0; } + .card .item.item-input input, .list-inset .item.item-input input, .padding > .list .item.item-input input, .padding-horizontal > .list .item.item-input input { + padding-right: 44px; } + +.padding-left > .list .item { + margin-left: 0; } + +.padding-right > .list .item { + margin-right: 0; } + +/** + * Badges + * -------------------------------------------------- + */ +.badge { + background-color: transparent; + color: #AAAAAA; + z-index: 1; + display: inline-block; + padding: 3px 8px; + min-width: 10px; + border-radius: 10px; + vertical-align: baseline; + text-align: center; + white-space: nowrap; + font-weight: bold; + font-size: 14px; + line-height: 16px; } + .badge:empty { + display: none; } + +.tabs .tab-item .badge.badge-light, .badge.badge-light { + background-color: #fff; + color: #444; } +.tabs .tab-item .badge.badge-stable, .badge.badge-stable { + background-color: #f8f8f8; + color: #444; } +.tabs .tab-item .badge.badge-positive, .badge.badge-positive { + background-color: #387ef5; + color: #fff; } +.tabs .tab-item .badge.badge-calm, .badge.badge-calm { + background-color: #11c1f3; + color: #fff; } +.tabs .tab-item .badge.badge-assertive, .badge.badge-assertive { + background-color: #ef473a; + color: #fff; } +.tabs .tab-item .badge.badge-balanced, .badge.badge-balanced { + background-color: #33cd5f; + color: #fff; } +.tabs .tab-item .badge.badge-energized, .badge.badge-energized { + background-color: #ffc900; + color: #fff; } +.tabs .tab-item .badge.badge-royal, .badge.badge-royal { + background-color: #886aea; + color: #fff; } +.tabs .tab-item .badge.badge-dark, .badge.badge-dark { + background-color: #444; + color: #fff; } + +.button .badge { + position: relative; + top: -1px; } + +/** + * Slide Box + * -------------------------------------------------- + */ +.slider { + position: relative; + visibility: hidden; + overflow: hidden; } + +.slider-slides { + position: relative; + height: 100%; } + +.slider-slide { + position: relative; + display: block; + float: left; + width: 100%; + height: 100%; + vertical-align: top; } + +.slider-slide-image > img { + width: 100%; } + +.slider-pager { + position: absolute; + bottom: 20px; + z-index: 1; + width: 100%; + height: 15px; + text-align: center; } + .slider-pager .slider-pager-page { + display: inline-block; + margin: 0px 3px; + width: 15px; + color: #000; + text-decoration: none; + opacity: 0.3; } + .slider-pager .slider-pager-page.active { + -webkit-transition: opacity 0.4s ease-in; + transition: opacity 0.4s ease-in; + opacity: 1; } + +/** + * Forms + * -------------------------------------------------- + */ +form { + margin: 0 0 1.42857; } + +legend { + display: block; + margin-bottom: 1.42857; + padding: 0; + width: 100%; + border: 1px solid #ddd; + color: #444; + font-size: 21px; + line-height: 2.85714; } + legend small { + color: #f8f8f8; + font-size: 1.07143; } + +label, input, button, select, textarea { + font-weight: normal; + font-size: 14px; + line-height: 1.42857; } + +input, button, select, textarea { + font-family: "Helvetica Neue", "Roboto", sans-serif; } + +.item-input { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: relative; + overflow: hidden; + padding: 6px 0 5px 16px; } + .item-input input { + -webkit-border-radius: 0; + border-radius: 0; + -webkit-box-flex: 1; + -webkit-flex: 1 0 220px; + -moz-box-flex: 1; + -moz-flex: 1 0 220px; + -ms-flex: 1 0 220px; + flex: 1 0 220px; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + margin: 0; + padding-right: 24px; + background-color: transparent; } + .item-input .button .icon { + -webkit-box-flex: 0; + -webkit-flex: 0 0 24px; + -moz-box-flex: 0; + -moz-flex: 0 0 24px; + -ms-flex: 0 0 24px; + flex: 0 0 24px; + position: static; + display: inline-block; + height: auto; + text-align: center; + font-size: 16px; } + .item-input .button-bar { + -webkit-border-radius: 0; + border-radius: 0; + -webkit-box-flex: 1; + -webkit-flex: 1 0 220px; + -moz-box-flex: 1; + -moz-flex: 1 0 220px; + -ms-flex: 1 0 220px; + flex: 1 0 220px; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; } + .item-input .icon { + min-width: 14px; } + +.item-input-inset { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + position: relative; + overflow: hidden; + padding: 10.66667px; } + +.item-input-wrapper { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 1; + -webkit-flex: 1 0; + -moz-box-flex: 1; + -moz-flex: 1 0; + -ms-flex: 1 0; + flex: 1 0; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + -webkit-border-radius: 4px; + border-radius: 4px; + padding-right: 8px; + padding-left: 8px; + background: #eee; } + +.item-input-inset .item-input-wrapper input { + padding-left: 4px; + height: 29px; + background: transparent; + line-height: 18px; } + +.item-input-wrapper ~ .button { + margin-left: 10.66667px; } + +.input-label { + -webkit-box-flex: 1; + -webkit-flex: 1 0 100px; + -moz-box-flex: 1; + -moz-flex: 1 0 100px; + -ms-flex: 1 0 100px; + flex: 1 0 100px; + display: table; + padding: 7px 10px 7px 0px; + max-width: 200px; + width: 35%; + color: #444; + font-size: 16px; } + +.placeholder-icon { + color: #aaa; } + .placeholder-icon:first-child { + padding-right: 6px; } + .placeholder-icon:last-child { + padding-left: 6px; } + +.item-stacked-label { + display: block; + background-color: transparent; + box-shadow: none; } + .item-stacked-label .input-label, .item-stacked-label .icon { + display: inline-block; + padding: 4px 0 0 0px; + vertical-align: middle; } + +.item-stacked-label input, .item-stacked-label textarea { + -webkit-border-radius: 2px; + border-radius: 2px; + padding: 4px 8px 3px 0; + border: none; + background-color: #fff; } + +.item-stacked-label input { + overflow: hidden; + height: 46px; } + +.item-floating-label { + display: block; + background-color: transparent; + box-shadow: none; } + .item-floating-label .input-label { + position: relative; + padding: 5px 0 0 0; + opacity: 0; + top: 10px; + -webkit-transition: opacity 0.15s ease-in, top 0.2s linear; + transition: opacity 0.15s ease-in, top 0.2s linear; } + .item-floating-label .input-label.has-input { + opacity: 1; + top: 0; + -webkit-transition: opacity 0.15s ease-in, top 0.2s linear; + transition: opacity 0.15s ease-in, top 0.2s linear; } + +textarea, input[type="text"], input[type="password"], input[type="datetime"], input[type="datetime-local"], input[type="date"], input[type="month"], input[type="time"], input[type="week"], input[type="number"], input[type="email"], input[type="url"], input[type="search"], input[type="tel"], input[type="color"] { + display: block; + padding-top: 2px; + padding-left: 0; + height: 34px; + color: #111; + vertical-align: middle; + font-size: 14px; + line-height: 16px; } + +.platform-ios input[type="datetime-local"], .platform-ios input[type="date"], .platform-ios input[type="month"], .platform-ios input[type="time"], .platform-ios input[type="week"], .platform-android input[type="datetime-local"], .platform-android input[type="date"], .platform-android input[type="month"], .platform-android input[type="time"], .platform-android input[type="week"] { + padding-top: 8px; } + +input, textarea { + width: 100%; } + +textarea { + padding-left: 0; } + textarea::-moz-placeholder { + color: #aaaaaa; } + textarea:-ms-input-placeholder { + color: #aaaaaa; } + textarea::-webkit-input-placeholder { + color: #aaaaaa; + text-indent: -3px; } + +textarea { + height: auto; } + +textarea, input[type="text"], input[type="password"], input[type="datetime"], input[type="datetime-local"], input[type="date"], input[type="month"], input[type="time"], input[type="week"], input[type="number"], input[type="email"], input[type="url"], input[type="search"], input[type="tel"], input[type="color"] { + border: 0; } + +input[type="radio"], input[type="checkbox"] { + margin: 0; + line-height: normal; } + +input[type="file"], input[type="image"], input[type="submit"], input[type="reset"], input[type="button"], input[type="radio"], input[type="checkbox"] { + width: auto; } + +input[type="file"] { + line-height: 34px; } + +.previous-input-focus, .cloned-text-input + input, .cloned-text-input + textarea { + position: absolute !important; + left: -9999px; + width: 200px; } + +input::-moz-placeholder, textarea::-moz-placeholder { + color: #aaaaaa; } +input:-ms-input-placeholder, textarea:-ms-input-placeholder { + color: #aaaaaa; } +input::-webkit-input-placeholder, textarea::-webkit-input-placeholder { + color: #aaaaaa; + text-indent: 0; } + +input[disabled], select[disabled], textarea[disabled], input[readonly]:not(.cloned-text-input), textarea[readonly]:not(.cloned-text-input), select[readonly] { + background-color: #f8f8f8; + cursor: not-allowed; } + +input[type="radio"][disabled], input[type="checkbox"][disabled], input[type="radio"][readonly], input[type="checkbox"][readonly] { + background-color: transparent; } + +/** + * Checkbox + * -------------------------------------------------- + */ +.checkbox { + position: relative; + display: inline-block; + padding: 7px 7px; + cursor: pointer; } + .checkbox input:before, .checkbox .checkbox-icon:before { + border-color: #ddd; } + .checkbox input:checked:before, .checkbox input:checked + .checkbox-icon:before { + background: #387ef5; + border-color: #387ef5; } + +.checkbox-light input:before, .checkbox-light .checkbox-icon:before { + border-color: #ddd; } +.checkbox-light input:checked:before, .checkbox-light input:checked + .checkbox-icon:before { + background: #ddd; + border-color: #ddd; } + +.checkbox-stable input:before, .checkbox-stable .checkbox-icon:before { + border-color: #b2b2b2; } +.checkbox-stable input:checked:before, .checkbox-stable input:checked + .checkbox-icon:before { + background: #b2b2b2; + border-color: #b2b2b2; } + +.checkbox-positive input:before, .checkbox-positive .checkbox-icon:before { + border-color: #387ef5; } +.checkbox-positive input:checked:before, .checkbox-positive input:checked + .checkbox-icon:before { + background: #387ef5; + border-color: #387ef5; } + +.checkbox-calm input:before, .checkbox-calm .checkbox-icon:before { + border-color: #11c1f3; } +.checkbox-calm input:checked:before, .checkbox-calm input:checked + .checkbox-icon:before { + background: #11c1f3; + border-color: #11c1f3; } + +.checkbox-assertive input:before, .checkbox-assertive .checkbox-icon:before { + border-color: #ef473a; } +.checkbox-assertive input:checked:before, .checkbox-assertive input:checked + .checkbox-icon:before { + background: #ef473a; + border-color: #ef473a; } + +.checkbox-balanced input:before, .checkbox-balanced .checkbox-icon:before { + border-color: #33cd5f; } +.checkbox-balanced input:checked:before, .checkbox-balanced input:checked + .checkbox-icon:before { + background: #33cd5f; + border-color: #33cd5f; } + +.checkbox-energized input:before, .checkbox-energized .checkbox-icon:before { + border-color: #ffc900; } +.checkbox-energized input:checked:before, .checkbox-energized input:checked + .checkbox-icon:before { + background: #ffc900; + border-color: #ffc900; } + +.checkbox-royal input:before, .checkbox-royal .checkbox-icon:before { + border-color: #886aea; } +.checkbox-royal input:checked:before, .checkbox-royal input:checked + .checkbox-icon:before { + background: #886aea; + border-color: #886aea; } + +.checkbox-dark input:before, .checkbox-dark .checkbox-icon:before { + border-color: #444; } +.checkbox-dark input:checked:before, .checkbox-dark input:checked + .checkbox-icon:before { + background: #444; + border-color: #444; } + +.checkbox input:disabled:before, .checkbox input:disabled + .checkbox-icon:before { + border-color: #ddd; } + +.checkbox input:disabled:checked:before, .checkbox input:disabled:checked + .checkbox-icon:before { + background: #ddd; } + +.checkbox.checkbox-input-hidden input { + display: none !important; } + +.checkbox input, .checkbox-icon { + position: relative; + width: 28px; + height: 28px; + display: block; + border: 0; + background: transparent; + cursor: pointer; + -webkit-appearance: none; } + .checkbox input:before, .checkbox-icon:before { + display: table; + width: 100%; + height: 100%; + border-width: 1px; + border-style: solid; + border-radius: 28px; + background: #fff; + content: ' '; + -webkit-transition: background-color 20ms ease-in-out; + transition: background-color 20ms ease-in-out; } + +.checkbox input:checked:before, input:checked + .checkbox-icon:before { + border-width: 2px; } + +.checkbox input:after, .checkbox-icon:after { + -webkit-transition: opacity 0.05s ease-in-out; + transition: opacity 0.05s ease-in-out; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + position: absolute; + top: 33%; + left: 25%; + display: table; + width: 14px; + height: 6px; + border: 1px solid #fff; + border-top: 0; + border-right: 0; + content: ' '; + opacity: 0; } + +.platform-android .checkbox-platform input:before, .platform-android .checkbox-platform .checkbox-icon:before, .checkbox-square input:before, .checkbox-square .checkbox-icon:before { + border-radius: 2px; + width: 72%; + height: 72%; + margin-top: 14%; + margin-left: 14%; + border-width: 2px; } + +.platform-android .checkbox-platform input:after, .platform-android .checkbox-platform .checkbox-icon:after, .checkbox-square input:after, .checkbox-square .checkbox-icon:after { + border-width: 2px; + top: 19%; + left: 25%; + width: 13px; + height: 7px; } + +.grade-c .checkbox input:after, .grade-c .checkbox-icon:after { + -webkit-transform: rotate(0); + transform: rotate(0); + top: 3px; + left: 4px; + border: none; + color: #fff; + content: '\2713'; + font-weight: bold; + font-size: 20px; } + +.checkbox input:checked:after, input:checked + .checkbox-icon:after { + opacity: 1; } + +.item-checkbox { + padding-left: 60px; } + .item-checkbox.active { + box-shadow: none; } + +.item-checkbox .checkbox { + position: absolute; + top: 50%; + right: 8px; + left: 8px; + z-index: 3; + margin-top: -21px; } + +.item-checkbox.item-checkbox-right { + padding-right: 60px; + padding-left: 16px; } + +.item-checkbox-right .checkbox input, .item-checkbox-right .checkbox-icon { + float: right; } + +/** + * Toggle + * -------------------------------------------------- + */ +.item-toggle { + pointer-events: none; } + +.toggle { + position: relative; + display: inline-block; + pointer-events: auto; + margin: -5px; + padding: 5px; } + .toggle input:checked + .track { + border-color: #387ef5; + background-color: #387ef5; } + .toggle.dragging .handle { + background-color: #f2f2f2 !important; } + .toggle.toggle-light input:checked + .track { + border-color: #ddd; + background-color: #ddd; } + .toggle.toggle-stable input:checked + .track { + border-color: #b2b2b2; + background-color: #b2b2b2; } + .toggle.toggle-positive input:checked + .track { + border-color: #387ef5; + background-color: #387ef5; } + .toggle.toggle-calm input:checked + .track { + border-color: #11c1f3; + background-color: #11c1f3; } + .toggle.toggle-assertive input:checked + .track { + border-color: #ef473a; + background-color: #ef473a; } + .toggle.toggle-balanced input:checked + .track { + border-color: #33cd5f; + background-color: #33cd5f; } + .toggle.toggle-energized input:checked + .track { + border-color: #ffc900; + background-color: #ffc900; } + .toggle.toggle-royal input:checked + .track { + border-color: #886aea; + background-color: #886aea; } + .toggle.toggle-dark input:checked + .track { + border-color: #444; + background-color: #444; } + +.toggle input { + display: none; } + +/* the track appearance when the toggle is "off" */ +.toggle .track { + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; + -webkit-transition-duration: 0.2s; + transition-duration: 0.2s; + -webkit-transition-property: background-color, border; + transition-property: background-color, border; + display: inline-block; + box-sizing: border-box; + width: 54px; + height: 32px; + border: solid 2px #E5E5E5; + border-radius: 20px; + background-color: #E5E5E5; + content: ' '; + cursor: pointer; + pointer-events: none; } + +/* Fix to avoid background color bleeding */ +/* (occured on (at least) Android 4.2, Asus MeMO Pad HD7 ME173X) */ +.platform-android4_2 .toggle .track { + -webkit-background-clip: padding-box; } + +/* the handle (circle) thats inside the toggle's track area */ +/* also the handle's appearance when it is "off" */ +.toggle .handle { + -webkit-transition: 0.2s ease-in-out; + transition: 0.2s ease-in-out; + position: absolute; + display: block; + width: 28px; + height: 28px; + border-radius: 28px; + background-color: #fff; + top: 7px; + left: 7px; } + .toggle .handle:before { + position: absolute; + top: -4px; + left: -22px; + padding: 19px 35px; + content: " "; } + +.toggle input:checked + .track .handle { + -webkit-transform: translate3d(22px, 0, 0); + transform: translate3d(22px, 0, 0); + background-color: #fff; } + +.item-toggle.active { + box-shadow: none; } + +.item-toggle, .item-toggle.item-complex .item-content { + padding-right: 102px; } + +.item-toggle.item-complex { + padding-right: 0; } + +.item-toggle .toggle { + position: absolute; + top: 8px; + right: 16px; + z-index: 3; } + +.toggle input:disabled + .track { + opacity: 0.6; } + +/** + * Radio Button Inputs + * -------------------------------------------------- + */ +.item-radio { + padding: 0; } + .item-radio:hover { + cursor: pointer; } + +.item-radio .item-content { + /* give some room to the right for the checkmark icon */ + padding-right: 64px; } + +.item-radio .radio-icon { + /* checkmark icon will be hidden by default */ + position: absolute; + top: 0; + right: 0; + z-index: 3; + visibility: hidden; + padding: 14px; + height: 100%; + font-size: 24px; } + +.item-radio input { + /* hide any radio button inputs elements (the ugly circles) */ + position: absolute; + left: -9999px; } + .item-radio input:checked ~ .item-content { + /* style the item content when its checked */ + background: #f7f7f7; } + .item-radio input:checked ~ .radio-icon { + /* show the checkmark icon when its checked */ + visibility: visible; } + +.platform-android.grade-b .item-radio, .platform-android.grade-c .item-radio { + -webkit-animation: androidCheckedbugfix infinite 1s; } + +@-webkit-keyframes androidCheckedbugfix { + from { + padding: 0; } + + to { + padding: 0; } } + +/** + * Range + * -------------------------------------------------- + */ +input[type="range"] { + display: inline-block; + overflow: hidden; + margin-top: 5px; + margin-bottom: 5px; + padding-right: 2px; + padding-left: 1px; + width: auto; + height: 43px; + outline: none; + background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ccc), color-stop(100%, #ccc)); + background: linear-gradient(to right, #ccc 0%, #ccc 100%); + background-position: center; + background-size: 99% 2px; + background-repeat: no-repeat; + -webkit-appearance: none; } + input[type="range"]::-webkit-slider-thumb { + position: relative; + width: 28px; + height: 28px; + border-radius: 50%; + background-color: #fff; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.3), 0 3px 5px rgba(0, 0, 0, 0.2); + cursor: pointer; + -webkit-appearance: none; + border: 0; } + input[type="range"]::-webkit-slider-thumb:before { + /* what creates the colorful line on the left side of the slider */ + position: absolute; + top: 13px; + left: -2001px; + width: 2000px; + height: 2px; + background: #444; + content: ' '; } + input[type="range"]::-webkit-slider-thumb:after { + /* create a larger (but hidden) hit area */ + position: absolute; + top: -15px; + left: -15px; + padding: 30px; + content: ' '; } + +.range { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; + padding: 2px 11px; } + .range.range-light input::-webkit-slider-thumb:before { + background: #ddd; } + .range.range-stable input::-webkit-slider-thumb:before { + background: #b2b2b2; } + .range.range-positive input::-webkit-slider-thumb:before { + background: #387ef5; } + .range.range-calm input::-webkit-slider-thumb:before { + background: #11c1f3; } + .range.range-balanced input::-webkit-slider-thumb:before { + background: #33cd5f; } + .range.range-assertive input::-webkit-slider-thumb:before { + background: #ef473a; } + .range.range-energized input::-webkit-slider-thumb:before { + background: #ffc900; } + .range.range-royal input::-webkit-slider-thumb:before { + background: #886aea; } + .range.range-dark input::-webkit-slider-thumb:before { + background: #444; } + +.range .icon { + -webkit-box-flex: 0; + -webkit-flex: 0; + -moz-box-flex: 0; + -moz-flex: 0; + -ms-flex: 0; + flex: 0; + display: block; + min-width: 24px; + text-align: center; + font-size: 24px; } + +.range input { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + display: block; + margin-right: 10px; + margin-left: 10px; } + +.range-label { + -webkit-box-flex: 0; + -webkit-flex: 0 0 auto; + -moz-box-flex: 0; + -moz-flex: 0 0 auto; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + display: block; + white-space: nowrap; } + +.range-label:first-child { + padding-left: 5px; } + +.range input + .range-label { + padding-right: 5px; + padding-left: 0; } + +/** + * Select + * -------------------------------------------------- + */ +.item-select { + position: relative; } + .item-select select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + position: absolute; + top: 0; + right: 0; + padding: 14px 48px 16px 16px; + max-width: 65%; + border: none; + background: #fff; + color: #333; + text-indent: 0.01px; + text-overflow: ''; + white-space: nowrap; + font-size: 14px; + cursor: pointer; + direction: rtl; } + .item-select select::-ms-expand { + display: none; } + .item-select option { + direction: ltr; } + .item-select:after { + position: absolute; + top: 50%; + right: 16px; + margin-top: -3px; + width: 0; + height: 0; + border-top: 5px solid; + border-right: 5px solid rgba(0, 0, 0, 0); + border-left: 5px solid rgba(0, 0, 0, 0); + color: #999; + content: ""; + pointer-events: none; } + .item-select.item-light select { + background: #fff; + color: #444; } + .item-select.item-stable select { + background: #f8f8f8; + color: #444; } + .item-select.item-stable:after, .item-select.item-stable .input-label { + color: #656565; } + .item-select.item-positive select { + background: #387ef5; + color: #fff; } + .item-select.item-positive:after, .item-select.item-positive .input-label { + color: #fff; } + .item-select.item-calm select { + background: #11c1f3; + color: #fff; } + .item-select.item-calm:after, .item-select.item-calm .input-label { + color: #fff; } + .item-select.item-assertive select { + background: #ef473a; + color: #fff; } + .item-select.item-assertive:after, .item-select.item-assertive .input-label { + color: #fff; } + .item-select.item-balanced select { + background: #33cd5f; + color: #fff; } + .item-select.item-balanced:after, .item-select.item-balanced .input-label { + color: #fff; } + .item-select.item-energized select { + background: #ffc900; + color: #fff; } + .item-select.item-energized:after, .item-select.item-energized .input-label { + color: #fff; } + .item-select.item-royal select { + background: #886aea; + color: #fff; } + .item-select.item-royal:after, .item-select.item-royal .input-label { + color: #fff; } + .item-select.item-dark select { + background: #444; + color: #fff; } + .item-select.item-dark:after, .item-select.item-dark .input-label { + color: #fff; } + +select[multiple], select[size] { + height: auto; } + +/** + * Progress + * -------------------------------------------------- + */ +progress { + display: block; + margin: 15px auto; + width: 100%; } + +/** + * Buttons + * -------------------------------------------------- + */ +.button { + border-color: #b2b2b2; + background-color: #f8f8f8; + color: #444; + position: relative; + display: inline-block; + margin: 0; + padding: 0 12px; + min-width: 52px; + min-height: 47px; + border-width: 1px; + border-style: solid; + border-radius: 2px; + vertical-align: top; + text-align: center; + text-overflow: ellipsis; + font-size: 16px; + line-height: 42px; + cursor: pointer; } + .button:hover { + color: #444; + text-decoration: none; } + .button.active, .button.activated { + border-color: #a2a2a2; + background-color: #e5e5e5; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .button:after { + position: absolute; + top: -6px; + right: -6px; + bottom: -6px; + left: -6px; + content: ' '; } + .button .icon { + vertical-align: top; + pointer-events: none; } + .button .icon:before, .button.icon:before, .button.icon-left:before, .button.icon-right:before { + display: inline-block; + padding: 0 0 1px 0; + vertical-align: inherit; + font-size: 24px; + line-height: 41px; + pointer-events: none; } + .button.icon-left:before { + float: left; + padding-right: 0.2em; + padding-left: 0; } + .button.icon-right:before { + float: right; + padding-right: 0; + padding-left: 0.2em; } + .button.button-block, .button.button-full { + margin-top: 10px; + margin-bottom: 10px; } + .button.button-light { + border-color: #ddd; + background-color: #fff; + color: #444; } + .button.button-light:hover { + color: #444; + text-decoration: none; } + .button.button-light.active, .button.button-light.activated { + border-color: #ccc; + background-color: #fafafa; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .button.button-light.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #ddd; } + .button.button-light.button-icon { + border-color: transparent; + background: none; } + .button.button-light.button-outline { + border-color: #ddd; + background: transparent; + color: #ddd; } + .button.button-light.button-outline.active, .button.button-light.button-outline.activated { + background-color: #ddd; + box-shadow: none; + color: #fff; } + .button.button-stable { + border-color: #b2b2b2; + background-color: #f8f8f8; + color: #444; } + .button.button-stable:hover { + color: #444; + text-decoration: none; } + .button.button-stable.active, .button.button-stable.activated { + border-color: #a2a2a2; + background-color: #e5e5e5; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .button.button-stable.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #b2b2b2; } + .button.button-stable.button-icon { + border-color: transparent; + background: none; } + .button.button-stable.button-outline { + border-color: #b2b2b2; + background: transparent; + color: #b2b2b2; } + .button.button-stable.button-outline.active, .button.button-stable.button-outline.activated { + background-color: #b2b2b2; + box-shadow: none; + color: #fff; } + .button.button-positive { + border-color: #0c63ee; + background-color: #387ef5; + color: #fff; } + .button.button-positive:hover { + color: #fff; + text-decoration: none; } + .button.button-positive.active, .button.button-positive.activated { + border-color: #0c63ee; + background-color: #0c63ee; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .button.button-positive.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #387ef5; } + .button.button-positive.button-icon { + border-color: transparent; + background: none; } + .button.button-positive.button-outline { + border-color: #387ef5; + background: transparent; + color: #387ef5; } + .button.button-positive.button-outline.active, .button.button-positive.button-outline.activated { + background-color: #387ef5; + box-shadow: none; + color: #fff; } + .button.button-calm { + border-color: #0a9ec7; + background-color: #11c1f3; + color: #fff; } + .button.button-calm:hover { + color: #fff; + text-decoration: none; } + .button.button-calm.active, .button.button-calm.activated { + border-color: #0a9ec7; + background-color: #0a9ec7; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .button.button-calm.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #11c1f3; } + .button.button-calm.button-icon { + border-color: transparent; + background: none; } + .button.button-calm.button-outline { + border-color: #11c1f3; + background: transparent; + color: #11c1f3; } + .button.button-calm.button-outline.active, .button.button-calm.button-outline.activated { + background-color: #11c1f3; + box-shadow: none; + color: #fff; } + .button.button-assertive { + border-color: #e42012; + background-color: #ef473a; + color: #fff; } + .button.button-assertive:hover { + color: #fff; + text-decoration: none; } + .button.button-assertive.active, .button.button-assertive.activated { + border-color: #e42012; + background-color: #e42012; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .button.button-assertive.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #ef473a; } + .button.button-assertive.button-icon { + border-color: transparent; + background: none; } + .button.button-assertive.button-outline { + border-color: #ef473a; + background: transparent; + color: #ef473a; } + .button.button-assertive.button-outline.active, .button.button-assertive.button-outline.activated { + background-color: #ef473a; + box-shadow: none; + color: #fff; } + .button.button-balanced { + border-color: #28a54c; + background-color: #33cd5f; + color: #fff; } + .button.button-balanced:hover { + color: #fff; + text-decoration: none; } + .button.button-balanced.active, .button.button-balanced.activated { + border-color: #28a54c; + background-color: #28a54c; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .button.button-balanced.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #33cd5f; } + .button.button-balanced.button-icon { + border-color: transparent; + background: none; } + .button.button-balanced.button-outline { + border-color: #33cd5f; + background: transparent; + color: #33cd5f; } + .button.button-balanced.button-outline.active, .button.button-balanced.button-outline.activated { + background-color: #33cd5f; + box-shadow: none; + color: #fff; } + .button.button-energized { + border-color: #e6b400; + background-color: #ffc900; + color: #fff; } + .button.button-energized:hover { + color: #fff; + text-decoration: none; } + .button.button-energized.active, .button.button-energized.activated { + border-color: #e6b400; + background-color: #e6b400; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .button.button-energized.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #ffc900; } + .button.button-energized.button-icon { + border-color: transparent; + background: none; } + .button.button-energized.button-outline { + border-color: #ffc900; + background: transparent; + color: #ffc900; } + .button.button-energized.button-outline.active, .button.button-energized.button-outline.activated { + background-color: #ffc900; + box-shadow: none; + color: #fff; } + .button.button-royal { + border-color: #6b46e5; + background-color: #886aea; + color: #fff; } + .button.button-royal:hover { + color: #fff; + text-decoration: none; } + .button.button-royal.active, .button.button-royal.activated { + border-color: #6b46e5; + background-color: #6b46e5; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .button.button-royal.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #886aea; } + .button.button-royal.button-icon { + border-color: transparent; + background: none; } + .button.button-royal.button-outline { + border-color: #886aea; + background: transparent; + color: #886aea; } + .button.button-royal.button-outline.active, .button.button-royal.button-outline.activated { + background-color: #886aea; + box-shadow: none; + color: #fff; } + .button.button-dark { + border-color: #111; + background-color: #444; + color: #fff; } + .button.button-dark:hover { + color: #fff; + text-decoration: none; } + .button.button-dark.active, .button.button-dark.activated { + border-color: #000; + background-color: #262626; + box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.1); } + .button.button-dark.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #444; } + .button.button-dark.button-icon { + border-color: transparent; + background: none; } + .button.button-dark.button-outline { + border-color: #444; + background: transparent; + color: #444; } + .button.button-dark.button-outline.active, .button.button-dark.button-outline.activated { + background-color: #444; + box-shadow: none; + color: #fff; } + +.button-small { + padding: 2px 4px 1px; + min-width: 28px; + min-height: 30px; + font-size: 12px; + line-height: 26px; } + .button-small .icon:before, .button-small.icon:before, .button-small.icon-left:before, .button-small.icon-right:before { + font-size: 16px; + line-height: 19px; + margin-top: 3px; } + +.button-large { + padding: 0 16px; + min-width: 68px; + min-height: 59px; + font-size: 20px; + line-height: 53px; } + .button-large .icon:before, .button-large.icon:before, .button-large.icon-left:before, .button-large.icon-right:before { + padding-bottom: 2px; + font-size: 32px; + line-height: 51px; } + +.button-icon { + -webkit-transition: opacity 0.1s; + transition: opacity 0.1s; + padding: 0 6px; + min-width: initial; + border-color: transparent; + background: none; } + .button-icon.button.active, .button-icon.button.activated { + border-color: transparent; + background: none; + box-shadow: none; + opacity: 0.3; } + .button-icon .icon:before, .button-icon.icon:before { + font-size: 32px; } + +.button-clear { + -webkit-transition: opacity 0.1s; + transition: opacity 0.1s; + padding: 0 6px; + max-height: 42px; + border-color: transparent; + background: none; + box-shadow: none; } + .button-clear.button-clear { + border-color: transparent; + background: none; + box-shadow: none; + color: #b2b2b2; } + .button-clear.button-icon { + border-color: transparent; + background: none; } + .button-clear.active, .button-clear.activated { + opacity: 0.3; } + +.button-outline { + -webkit-transition: opacity 0.1s; + transition: opacity 0.1s; + background: none; + box-shadow: none; } + .button-outline.button-outline { + border-color: #b2b2b2; + background: transparent; + color: #b2b2b2; } + .button-outline.button-outline.active, .button-outline.button-outline.activated { + background-color: #b2b2b2; + box-shadow: none; + color: #fff; } + +.padding > .button.button-block:first-child { + margin-top: 0; } + +.button-block { + display: block; + clear: both; } + .button-block:after { + clear: both; } + +.button-full, .button-full > .button { + display: block; + margin-right: 0; + margin-left: 0; + border-right-width: 0; + border-left-width: 0; + border-radius: 0; } + +button.button-block, button.button-full, .button-full > button.button, input.button.button-block { + width: 100%; } + +a.button { + text-decoration: none; } + a.button .icon:before, a.button.icon:before, a.button.icon-left:before, a.button.icon-right:before { + margin-top: 2px; } + +.button.disabled, .button[disabled] { + opacity: 0.4; + cursor: default !important; + pointer-events: none; } + +/** + * Button Bar + * -------------------------------------------------- + */ +.button-bar { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + width: 100%; } + .button-bar.button-bar-inline { + display: block; + width: auto; + *zoom: 1; } + .button-bar.button-bar-inline:before, .button-bar.button-bar-inline:after { + display: table; + content: ""; + line-height: 0; } + .button-bar.button-bar-inline:after { + clear: both; } + .button-bar.button-bar-inline > .button { + width: auto; + display: inline-block; + float: left; } + +.button-bar > .button { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + display: block; + overflow: hidden; + padding: 0 16px; + width: 0; + border-width: 1px 0px 1px 1px; + border-radius: 0; + text-align: center; + text-overflow: ellipsis; + white-space: nowrap; } + .button-bar > .button:before, .button-bar > .button .icon:before { + line-height: 44px; } + .button-bar > .button:first-child { + border-radius: 2px 0px 0px 2px; } + .button-bar > .button:last-child { + border-right-width: 1px; + border-radius: 0px 2px 2px 0px; } + +/** + * Grid + * -------------------------------------------------- + * Using flexbox for the grid, inspired by Philip Walton: + * http://philipwalton.github.io/solved-by-flexbox/demos/grids/ + * By default each .col within a .row will evenly take up + * available width, and the height of each .col with take + * up the height of the tallest .col in the same .row. + */ +.row { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + padding: 5px; + width: 100%; } + +.row-wrap { + -webkit-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; } + +.row + .row { + margin-top: -5px; + padding-top: 0; } + +.col { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + display: block; + padding: 5px; + width: 100%; } + +/* Vertically Align Columns */ +/* .row-* vertically aligns every .col in the .row */ +.row-top { + -webkit-box-align: start; + -ms-flex-align: start; + -webkit-align-items: flex-start; + -moz-align-items: flex-start; + align-items: flex-start; } + +.row-bottom { + -webkit-box-align: end; + -ms-flex-align: end; + -webkit-align-items: flex-end; + -moz-align-items: flex-end; + align-items: flex-end; } + +.row-center { + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + -moz-align-items: center; + align-items: center; } + +.row-stretch { + -webkit-box-align: stretch; + -ms-flex-align: stretch; + -webkit-align-items: stretch; + -moz-align-items: stretch; + align-items: stretch; } + +.row-baseline { + -webkit-box-align: baseline; + -ms-flex-align: baseline; + -webkit-align-items: baseline; + -moz-align-items: baseline; + align-items: baseline; } + +/* .col-* vertically aligns an individual .col */ +.col-top { + -webkit-align-self: flex-start; + -moz-align-self: flex-start; + -ms-flex-item-align: start; + align-self: flex-start; } + +.col-bottom { + -webkit-align-self: flex-end; + -moz-align-self: flex-end; + -ms-flex-item-align: end; + align-self: flex-end; } + +.col-center { + -webkit-align-self: center; + -moz-align-self: center; + -ms-flex-item-align: center; + align-self: center; } + +/* Column Offsets */ +.col-offset-10 { + margin-left: 10%; } + +.col-offset-20 { + margin-left: 20%; } + +.col-offset-25 { + margin-left: 25%; } + +.col-offset-33, .col-offset-34 { + margin-left: 33.3333%; } + +.col-offset-50 { + margin-left: 50%; } + +.col-offset-66, .col-offset-67 { + margin-left: 66.6666%; } + +.col-offset-75 { + margin-left: 75%; } + +.col-offset-80 { + margin-left: 80%; } + +.col-offset-90 { + margin-left: 90%; } + +/* Explicit Column Percent Sizes */ +/* By default each grid column will evenly distribute */ +/* across the grid. However, you can specify individual */ +/* columns to take up a certain size of the available area */ +.col-10 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 10%; + -moz-box-flex: 0; + -moz-flex: 0 0 10%; + -ms-flex: 0 0 10%; + flex: 0 0 10%; + max-width: 10%; } + +.col-20 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 20%; + -moz-box-flex: 0; + -moz-flex: 0 0 20%; + -ms-flex: 0 0 20%; + flex: 0 0 20%; + max-width: 20%; } + +.col-25 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 25%; + -moz-box-flex: 0; + -moz-flex: 0 0 25%; + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; } + +.col-33, .col-34 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 33.3333%; + -moz-box-flex: 0; + -moz-flex: 0 0 33.3333%; + -ms-flex: 0 0 33.3333%; + flex: 0 0 33.3333%; + max-width: 33.3333%; } + +.col-50 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 50%; + -moz-box-flex: 0; + -moz-flex: 0 0 50%; + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; } + +.col-66, .col-67 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 66.6666%; + -moz-box-flex: 0; + -moz-flex: 0 0 66.6666%; + -ms-flex: 0 0 66.6666%; + flex: 0 0 66.6666%; + max-width: 66.6666%; } + +.col-75 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 75%; + -moz-box-flex: 0; + -moz-flex: 0 0 75%; + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; } + +.col-80 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 80%; + -moz-box-flex: 0; + -moz-flex: 0 0 80%; + -ms-flex: 0 0 80%; + flex: 0 0 80%; + max-width: 80%; } + +.col-90 { + -webkit-box-flex: 0; + -webkit-flex: 0 0 90%; + -moz-box-flex: 0; + -moz-flex: 0 0 90%; + -ms-flex: 0 0 90%; + flex: 0 0 90%; + max-width: 90%; } + +/* Responsive Grid Classes */ +/* Adding a class of responsive-X to a row */ +/* will trigger the flex-direction to */ +/* change to column and add some margin */ +/* to any columns in the row for clearity */ +@media (max-width: 567px) { + .responsive-sm { + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } + .responsive-sm .col, .responsive-sm .col-10, .responsive-sm .col-20, .responsive-sm .col-25, .responsive-sm .col-33, .responsive-sm .col-34, .responsive-sm .col-50, .responsive-sm .col-66, .responsive-sm .col-67, .responsive-sm .col-75, .responsive-sm .col-80, .responsive-sm .col-90 { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + margin-bottom: 15px; + margin-left: 0; + max-width: 100%; + width: 100%; } } + +@media (max-width: 767px) { + .responsive-md { + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } + .responsive-md .col, .responsive-md .col-10, .responsive-md .col-20, .responsive-md .col-25, .responsive-md .col-33, .responsive-md .col-34, .responsive-md .col-50, .responsive-md .col-66, .responsive-md .col-67, .responsive-md .col-75, .responsive-md .col-80, .responsive-md .col-90 { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + margin-bottom: 15px; + margin-left: 0; + max-width: 100%; + width: 100%; } } + +@media (max-width: 1023px) { + .responsive-lg { + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } + .responsive-lg .col, .responsive-lg .col-10, .responsive-lg .col-20, .responsive-lg .col-25, .responsive-lg .col-33, .responsive-lg .col-34, .responsive-lg .col-50, .responsive-lg .col-66, .responsive-lg .col-67, .responsive-lg .col-75, .responsive-lg .col-80, .responsive-lg .col-90 { + -webkit-box-flex: 1; + -webkit-flex: 1; + -moz-box-flex: 1; + -moz-flex: 1; + -ms-flex: 1; + flex: 1; + margin-bottom: 15px; + margin-left: 0; + max-width: 100%; + width: 100%; } } + +/** + * Utility Classes + * -------------------------------------------------- + */ +.hide { + display: none; } + +.opacity-hide { + opacity: 0; } + +.grade-b .opacity-hide, .grade-c .opacity-hide { + opacity: 1; + display: none; } + +.show { + display: block; } + +.opacity-show { + opacity: 1; } + +.invisible { + visibility: hidden; } + +.keyboard-open .hide-on-keyboard-open { + display: none; } + +.keyboard-open .tabs.hide-on-keyboard-open + .pane .has-tabs, .keyboard-open .bar-footer.hide-on-keyboard-open + .pane .has-footer { + bottom: 0; } + +.inline { + display: inline-block; } + +.disable-pointer-events { + pointer-events: none; } + +.enable-pointer-events { + pointer-events: auto; } + +.disable-user-behavior { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-touch-callout: none; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-tap-highlight-color: transparent; + -webkit-user-drag: none; + -ms-touch-action: none; + -ms-content-zooming: none; } + +.click-block { + position: absolute; + top: 0; + left: 0; + z-index: 99999; + width: 100%; + height: 100%; + opacity: 0; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + +.click-block-hide { + -webkit-transform: translate3d(-9999px, 0, 0); + transform: translate3d(-9999px, 0, 0); } + +.no-resize { + resize: none; } + +.block { + display: block; + clear: both; } + .block:after { + display: block; + visibility: hidden; + clear: both; + height: 0; + content: "."; } + +.full-image { + width: 100%; } + +.clearfix { + *zoom: 1; } + .clearfix:before, .clearfix:after { + display: table; + content: ""; + line-height: 0; } + .clearfix:after { + clear: both; } + +/** + * Content Padding + * -------------------------------------------------- + */ +.padding { + padding: 10px; } + +.padding-top, .padding-vertical { + padding-top: 10px; } + +.padding-right, .padding-horizontal { + padding-right: 10px; } + +.padding-bottom, .padding-vertical { + padding-bottom: 10px; } + +.padding-left, .padding-horizontal { + padding-left: 10px; } + +/** + * Rounded + * -------------------------------------------------- + */ +.rounded { + border-radius: 4px; } + +/** + * Utility Colors + * -------------------------------------------------- + * Utility colors are added to help set a naming convention. You'll + * notice we purposely do not use words like "red" or "blue", but + * instead have colors which represent an emotion or generic theme. + */ +.light, a.light { + color: #fff; } + +.light-bg { + background-color: #fff; } + +.light-border { + border-color: #ddd; } + +.stable, a.stable { + color: #f8f8f8; } + +.stable-bg { + background-color: #f8f8f8; } + +.stable-border { + border-color: #b2b2b2; } + +.positive, a.positive { + color: #387ef5; } + +.positive-bg { + background-color: #387ef5; } + +.positive-border { + border-color: #0c63ee; } + +.calm, a.calm { + color: #11c1f3; } + +.calm-bg { + background-color: #11c1f3; } + +.calm-border { + border-color: #0a9ec7; } + +.assertive, a.assertive { + color: #ef473a; } + +.assertive-bg { + background-color: #ef473a; } + +.assertive-border { + border-color: #e42012; } + +.balanced, a.balanced { + color: #33cd5f; } + +.balanced-bg { + background-color: #33cd5f; } + +.balanced-border { + border-color: #28a54c; } + +.energized, a.energized { + color: #ffc900; } + +.energized-bg { + background-color: #ffc900; } + +.energized-border { + border-color: #e6b400; } + +.royal, a.royal { + color: #886aea; } + +.royal-bg { + background-color: #886aea; } + +.royal-border { + border-color: #6b46e5; } + +.dark, a.dark { + color: #444; } + +.dark-bg { + background-color: #444; } + +.dark-border { + border-color: #111; } + +/** + * Platform + * -------------------------------------------------- + * Platform specific tweaks + */ +.platform-ios.platform-cordova:not(.fullscreen) .bar-header:not(.bar-subheader) { + height: 64px; } + .platform-ios.platform-cordova:not(.fullscreen) .bar-header:not(.bar-subheader).item-input-inset .item-input-wrapper { + margin-top: 19px !important; } + .platform-ios.platform-cordova:not(.fullscreen) .bar-header:not(.bar-subheader) > * { + margin-top: 20px; } +.platform-ios.platform-cordova:not(.fullscreen) .tabs-top > .tabs, .platform-ios.platform-cordova:not(.fullscreen) .tabs.tabs-top { + top: 64px; } +.platform-ios.platform-cordova:not(.fullscreen) .has-header, .platform-ios.platform-cordova:not(.fullscreen) .bar-subheader { + top: 64px; } +.platform-ios.platform-cordova:not(.fullscreen) .has-subheader { + top: 108px; } +.platform-ios.platform-cordova:not(.fullscreen) .has-tabs-top { + top: 113px; } +.platform-ios.platform-cordova:not(.fullscreen) .has-header.has-subheader.has-tabs-top { + top: 157px; } +.platform-ios.platform-cordova.status-bar-hide { + margin-bottom: 20px; } + +@media (orientation: landscape) { + .platform-ios.platform-browser.platform-ipad { + position: fixed; } } + +.platform-c:not(.enable-transitions) * { + -webkit-transition: none !important; + transition: none !important; } + +.slide-in-up { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); } + +.slide-in-up.ng-enter, .slide-in-up > .ng-enter { + -webkit-transition: all cubic-bezier(0.1, 0.7, 0.1, 1) 400ms; + transition: all cubic-bezier(0.1, 0.7, 0.1, 1) 400ms; } + +.slide-in-up.ng-enter-active, .slide-in-up > .ng-enter-active { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + +.slide-in-up.ng-leave, .slide-in-up > .ng-leave { + -webkit-transition: all ease-in-out 250ms; + transition: all ease-in-out 250ms; } + +@-webkit-keyframes scaleOut { + from { + -webkit-transform: scale(1); + opacity: 1; } + + to { + -webkit-transform: scale(0.8); + opacity: 0; } } + +@keyframes scaleOut { + from { + transform: scale(1); + opacity: 1; } + + to { + transform: scale(0.8); + opacity: 0; } } + +@-webkit-keyframes superScaleIn { + from { + -webkit-transform: scale(1.2); + opacity: 0; } + + to { + -webkit-transform: scale(1); + opacity: 1; } } + +@keyframes superScaleIn { + from { + transform: scale(1.2); + opacity: 0; } + + to { + transform: scale(1); + opacity: 1; } } + +[nav-view-transition="ios"] [nav-view="entering"], [nav-view-transition="ios"] [nav-view="leaving"] { + -webkit-transition-duration: 450ms; + transition-duration: 450ms; + -webkit-transition-timing-function: cubic-bezier(0.3, 0.9, 0.4, 1); + transition-timing-function: cubic-bezier(0.3, 0.9, 0.4, 1); + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, transform; } +[nav-view-transition="ios"][nav-view-direction="forward"], [nav-view-transition="ios"][nav-view-direction="back"] { + background-color: #000; } +[nav-view-transition="ios"] [nav-view="active"], [nav-view-transition="ios"][nav-view-direction="forward"] [nav-view="entering"], [nav-view-transition="ios"][nav-view-direction="back"] [nav-view="leaving"] { + z-index: 3; } +[nav-view-transition="ios"][nav-view-direction="back"] [nav-view="entering"], [nav-view-transition="ios"][nav-view-direction="forward"] [nav-view="leaving"] { + z-index: 2; } + +[nav-bar-transition="ios"] .title, [nav-bar-transition="ios"] .buttons, [nav-bar-transition="ios"] .back-text { + -webkit-transition-duration: 450ms; + transition-duration: 450ms; + -webkit-transition-timing-function: cubic-bezier(0.3, 0.9, 0.4, 1); + transition-timing-function: cubic-bezier(0.3, 0.9, 0.4, 1); + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, transform; } +[nav-bar-transition="ios"] [nav-bar="active"], [nav-bar-transition="ios"] [nav-bar="entering"] { + z-index: 10; } + [nav-bar-transition="ios"] [nav-bar="active"] .bar, [nav-bar-transition="ios"] [nav-bar="entering"] .bar { + background: transparent; } +[nav-bar-transition="ios"] [nav-bar="cached"] { + display: block; } + [nav-bar-transition="ios"] [nav-bar="cached"] .header-item { + display: none; } + +[nav-view-transition="android"] [nav-view="entering"], [nav-view-transition="android"] [nav-view="leaving"] { + -webkit-transition-duration: 200ms; + transition-duration: 200ms; + -webkit-transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1); + transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1); + -webkit-transition-property: -webkit-transform; + transition-property: transform; } +[nav-view-transition="android"] [nav-view="active"], [nav-view-transition="android"][nav-view-direction="forward"] [nav-view="entering"], [nav-view-transition="android"][nav-view-direction="back"] [nav-view="leaving"] { + z-index: 3; } +[nav-view-transition="android"][nav-view-direction="back"] [nav-view="entering"], [nav-view-transition="android"][nav-view-direction="forward"] [nav-view="leaving"] { + z-index: 2; } + +[nav-bar-transition="android"] .title, [nav-bar-transition="android"] .buttons { + -webkit-transition-duration: 200ms; + transition-duration: 200ms; + -webkit-transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1); + transition-timing-function: cubic-bezier(0.4, 0.6, 0.2, 1); + -webkit-transition-property: opacity; + transition-property: opacity; } +[nav-bar-transition="android"] [nav-bar="active"], [nav-bar-transition="android"] [nav-bar="entering"] { + z-index: 10; } + [nav-bar-transition="android"] [nav-bar="active"] .bar, [nav-bar-transition="android"] [nav-bar="entering"] .bar { + background: transparent; } +[nav-bar-transition="android"] [nav-bar="cached"] { + display: block; } + [nav-bar-transition="android"] [nav-bar="cached"] .header-item { + display: none; } + +[nav-view="cached"], [nav-bar="cached"] { + display: none; } + +[nav-view="stage"] { + opacity: 0; + -webkit-transition-duration: 0; + transition-duration: 0; } + +[nav-bar="stage"] .title, [nav-bar="stage"] .buttons, [nav-bar="stage"] .back-text { + position: absolute; + opacity: 0; + -webkit-transition-duration: 0s; + transition-duration: 0s; } diff --git a/lib/fonts/ionicons.eot b/lib/fonts/ionicons.eot new file mode 100755 index 0000000000000000000000000000000000000000..52b1e577b8e2c154c6b5bf791ae3d7ef35aa212b GIT binary patch literal 101984 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æJF`Vywto8OcQLcM3Ekh?qO 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 + + + + +Created by FontForge 20120731 at Mon Jun 16 14:44:31 2014 + By Adam Bradley +Created by Adam Bradley with FontForge 2.0 (http://fontforge.sf.net) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/fonts/ionicons.ttf b/lib/fonts/ionicons.ttf new file mode 100755 index 0000000000000000000000000000000000000000..cc67b2f57bb0b00578a93d611c68cb977c48e8fe GIT binary patch literal 164548 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 -}))cfi$W{u1Q7~*hD@|>60THcKH%$#S5|pWY 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 + * License MIT + */ +//Interval object +var deprecated = { + method: function(msg, log, fn) { + var called = false; + return function deprecatedMethod() { + if (!called) { + called = true; + log(msg); + } + return fn.apply(this, arguments); + }; + }, + + field: function(msg, log, parent, field, val) { + var called = false; + var getter = function() { + if (!called) { + called = true; + log(msg); + } + return val; + }; + var setter = function(v) { + if (!called) { + called = true; + log(msg); + } + val = v; + return v; + }; + Object.defineProperty(parent, field, { + get: getter, + set: setter, + enumerable: true + }); + return; + } +}; + +var IonicModule = angular.module('ionic', ['ngAnimate', 'ngSanitize', 'ui.router']), + extend = angular.extend, + forEach = angular.forEach, + isDefined = angular.isDefined, + isNumber = angular.isNumber, + isString = angular.isString, + jqLite = angular.element; + + +/** + * @ngdoc service + * @name $ionicActionSheet + * @module ionic + * @description + * The Action Sheet is a slide-up pane that lets the user choose from a set of options. + * Dangerous options are highlighted in red and 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. + * + * ![Action Sheet](http://ionicframework.com.s3.amazonaws.com/docs/controllers/actionSheet.gif) + * + * @usage + * To trigger an Action Sheet in your code, use the $ionicActionSheet service in your angular controllers: + * + * ```js + * angular.module('mySuperApp', ['ionic']) + * .controller(function($scope, $ionicActionSheet, $timeout) { + * + * // Triggered on a button click, or some other target + * $scope.show = function() { + * + * // Show the action sheet + * var hideSheet = $ionicActionSheet.show({ + * buttons: [ + * { text: 'Share This' }, + * { text: 'Move' } + * ], + * destructiveText: 'Delete', + * titleText: 'Modify your album', + * cancelText: 'Cancel', + * cancel: function() { + // add cancel code.. + }, + * buttonClicked: function(index) { + * return true; + * } + * }); + * + * // For example's sake, hide the sheet after two seconds + * $timeout(function() { + * hideSheet(); + * }, 2000); + * + * }; + * }); + * ``` + * + */ +IonicModule +.factory('$ionicActionSheet', [ + '$rootScope', + '$compile', + '$animate', + '$timeout', + '$ionicTemplateLoader', + '$ionicPlatform', + '$ionicBody', +function($rootScope, $compile, $animate, $timeout, $ionicTemplateLoader, $ionicPlatform, $ionicBody) { + + return { + show: actionSheet + }; + + /** + * @ngdoc method + * @name $ionicActionSheet#show + * @description + * Load and return a new action sheet. + * + * A new isolated scope will be created for the + * action sheet and the new element will be appended into the body. + * + * @param {object} options The options for this ActionSheet. Properties: + * + * - `[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. + * - `{boolean=}` `cancelOnStateChange` Whether to cancel the actionSheet when navigating + * to a new state. Default true. + * - `{string}` `cssClass` The custom CSS class name. + * + * @returns {function} `hideSheet` A function which, when called, hides & cancels the action sheet. + */ + function actionSheet(opts) { + var scope = $rootScope.$new(true); + + angular.extend(scope, { + cancel: angular.noop, + destructiveButtonClicked: angular.noop, + buttonClicked: angular.noop, + $deregisterBackButton: angular.noop, + buttons: [], + cancelOnStateChange: true + }, opts || {}); + + + // Compile the template + var element = scope.element = $compile('')(scope); + + // Grab the sheet element for animation + var sheetEl = jqLite(element[0].querySelector('.action-sheet-wrapper')); + + var stateChangeListenDone = scope.cancelOnStateChange ? + $rootScope.$on('$stateChangeSuccess', function() { scope.cancel(); }) : + angular.noop; + + // removes the actionSheet from the screen + scope.removeSheet = function(done) { + if (scope.removed) return; + + scope.removed = true; + sheetEl.removeClass('action-sheet-up'); + $timeout(function() { + // wait to remove this due to a 300ms delay native + // click which would trigging whatever was underneath this + $ionicBody.removeClass('action-sheet-open'); + }, 400); + scope.$deregisterBackButton(); + stateChangeListenDone(); + + $animate.removeClass(element, 'active').then(function() { + scope.$destroy(); + element.remove(); + // scope.cancel.$scope is defined near the bottom + scope.cancel.$scope = sheetEl = null; + (done || angular.noop)(); + }); + }; + + scope.showSheet = function(done) { + if (scope.removed) return; + + $ionicBody.append(element) + .addClass('action-sheet-open'); + + $animate.addClass(element, 'active').then(function() { + if (scope.removed) return; + (done || angular.noop)(); + }); + $timeout(function() { + if (scope.removed) return; + sheetEl.addClass('action-sheet-up'); + }, 20, false); + }; + + // registerBackButtonAction returns a callback to deregister the action + scope.$deregisterBackButton = $ionicPlatform.registerBackButtonAction( + function() { + $timeout(scope.cancel); + }, + PLATFORM_BACK_BUTTON_PRIORITY_ACTION_SHEET + ); + + // called when the user presses the cancel button + scope.cancel = function() { + // after the animation is out, call the cancel callback + scope.removeSheet(opts.cancel); + }; + + scope.buttonClicked = function(index) { + // Check if the button click event returned true, which means + // we can close the action sheet + if (opts.buttonClicked(index, opts.buttons[index]) === true) { + scope.removeSheet(); + } + }; + + scope.destructiveButtonClicked = function() { + // Check if the destructive button click event returned true, which means + // we can close the action sheet + if (opts.destructiveButtonClicked() === true) { + scope.removeSheet(); + } + }; + + scope.showSheet(); + + // Expose the scope on $ionicActionSheet's return value for the sake + // of testing it. + scope.cancel.$scope = scope; + + return scope.cancel; + } +}]); + + +jqLite.prototype.addClass = function(cssClasses) { + var x, y, cssClass, el, splitClasses, existingClasses; + if (cssClasses && cssClasses != 'ng-scope' && cssClasses != 'ng-isolate-scope') { + for (x = 0; x < this.length; x++) { + el = this[x]; + if (el.setAttribute) { + + if (cssClasses.indexOf(' ') < 0 && el.classList.add) { + el.classList.add(cssClasses); + } else { + existingClasses = (' ' + (el.getAttribute('class') || '') + ' ') + .replace(/[\n\t]/g, " "); + splitClasses = cssClasses.split(' '); + + for (y = 0; y < splitClasses.length; y++) { + cssClass = splitClasses[y].trim(); + if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) { + existingClasses += cssClass + ' '; + } + } + el.setAttribute('class', existingClasses.trim()); + } + } + } + } + return this; +}; + +jqLite.prototype.removeClass = function(cssClasses) { + var x, y, splitClasses, cssClass, el; + if (cssClasses) { + for (x = 0; x < this.length; x++) { + el = this[x]; + if (el.getAttribute) { + if (cssClasses.indexOf(' ') < 0 && el.classList.remove) { + el.classList.remove(cssClasses); + } else { + splitClasses = cssClasses.split(' '); + + for (y = 0; y < splitClasses.length; y++) { + cssClass = splitClasses[y]; + el.setAttribute('class', ( + (" " + (el.getAttribute('class') || '') + " ") + .replace(/[\n\t]/g, " ") + .replace(" " + cssClass.trim() + " ", " ")).trim() + ); + } + } + } + } + } + return this; +}; + + +/** + * @private + */ +IonicModule +.factory('$$ionicAttachDrag', [function() { + + return attachDrag; + + function attachDrag(scope, element, options) { + var opts = extend({}, { + getDistance: function() { return opts.element.prop('offsetWidth'); }, + onDragStart: angular.noop, + onDrag: angular.noop, + onDragEnd: angular.noop + }, options); + + var dragStartGesture = ionic.onGesture('dragstart', handleDragStart, element[0]); + var dragGesture = ionic.onGesture('drag', handleDrag, element[0]); + var dragEndGesture = ionic.onGesture('dragend', handleDragEnd, element[0]); + + scope.$on('$destroy', function() { + ionic.offGesture(dragStartGesture, 'dragstart', handleDragStart); + ionic.offGesture(dragGesture, 'drag', handleDrag); + ionic.offGesture(dragEndGesture, 'dragend', handleDragEnd); + }); + + var isDragging = false; + element.on('touchmove pointermove mousemove', function(ev) { + if (isDragging) ev.preventDefault(); + }); + element.on('touchend mouseup mouseleave', function(ev) { + isDragging = false; + }); + + var dragState; + function handleDragStart(ev) { + if (dragState) return; + if (opts.onDragStart() !== false) { + dragState = { + startX: ev.gesture.center.pageX, + startY: ev.gesture.center.pageY, + distance: opts.getDistance() + }; + } + } + function handleDrag(ev) { + if (!dragState) return; + var deltaX = dragState.startX - ev.gesture.center.pageX; + var deltaY = dragState.startY - ev.gesture.center.pageY; + var isVertical = ev.gesture.direction === 'up' || ev.gesture.direction === 'down'; + + if (isVertical && Math.abs(deltaY) > Math.abs(deltaX) * 2) { + handleDragEnd(ev); + return; + } + if (Math.abs(deltaX) > Math.abs(deltaY) * 2) { + isDragging = true; + } + + var percent = getDragPercent(ev.gesture.center.pageX); + opts.onDrag(percent); + } + function handleDragEnd(ev) { + if (!dragState) return; + var percent = getDragPercent(ev.gesture.center.pageX); + options.onDragEnd(percent, ev.gesture.velocityX); + + dragState = null; + } + + function getDragPercent(x) { + var delta = dragState.startX - x; + var percent = delta / dragState.distance; + return percent; + } + } + +}]); + +/** + * @ngdoc service + * @name $ionicBackdrop + * @module ionic + * @description + * Shows and hides a backdrop over the UI. Appears behind popups, loading, + * and other overlays. + * + * Often, multiple UI components require a backdrop, but only one backdrop is + * ever needed in the DOM at a time. + * + * Therefore, each component that requires the backdrop to be shown calls + * `$ionicBackdrop.retain()` when it wants the backdrop, then `$ionicBackdrop.release()` + * when it is done with the backdrop. + * + * For each time `retain` is called, the backdrop will be shown until `release` is called. + * + * For example, if `retain` is called three times, the backdrop will be shown until `release` + * is called three times. + * + * @usage + * + * ```js + * function MyController($scope, $ionicBackdrop, $timeout) { + * //Show a backdrop for one second + * $scope.action = function() { + * $ionicBackdrop.retain(); + * $timeout(function() { + * $ionicBackdrop.release(); + * }, 1000); + * }; + * } + * ``` + */ +IonicModule +.factory('$ionicBackdrop', [ + '$document', '$timeout', +function($document, $timeout) { + + var el = jqLite('
'); + var backdropHolds = 0; + + $document[0].body.appendChild(el[0]); + + return { + /** + * @ngdoc method + * @name $ionicBackdrop#retain + * @description Retains the backdrop. + */ + retain: retain, + /** + * @ngdoc method + * @name $ionicBackdrop#release + * @description + * Releases the backdrop. + */ + release: release, + + getElement: getElement, + + // exposed for testing + _element: el + }; + + function retain() { + if ((++backdropHolds) === 1) { + el.addClass('visible'); + ionic.requestAnimationFrame(function() { + backdropHolds && el.addClass('active'); + }); + } + } + function release() { + if ((--backdropHolds) === 0) { + el.removeClass('active'); + $timeout(function() { + !backdropHolds && el.removeClass('visible'); + }, 400, false); + } + } + + function getElement() { + return el; + } + +}]); + +/** + * @private + */ +IonicModule +.factory('$ionicBind', ['$parse', '$interpolate', function($parse, $interpolate) { + var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/; + return function(scope, attrs, bindDefinition) { + forEach(bindDefinition || {}, function (definition, scopeName) { + //Adapted from angular.js $compile + var match = definition.match(LOCAL_REGEXP) || [], + attrName = match[3] || scopeName, + mode = match[1], // @, =, or & + parentGet, + unwatch; + + switch(mode) { + case '@': + if (!attrs[attrName]) { + return; + } + attrs.$observe(attrName, function(value) { + scope[scopeName] = value; + }); + // we trigger an interpolation to ensure + // the value is there for use immediately + if (attrs[attrName]) { + scope[scopeName] = $interpolate(attrs[attrName])(scope); + } + break; + + case '=': + if (!attrs[attrName]) { + return; + } + unwatch = scope.$watch(attrs[attrName], function(value) { + scope[scopeName] = value; + }); + //Destroy parent scope watcher when this scope is destroyed + scope.$on('$destroy', unwatch); + break; + + case '&': + /* jshint -W044 */ + if (attrs[attrName] && attrs[attrName].match(RegExp(scopeName + '\(.*?\)'))) { + throw new Error('& expression binding "' + scopeName + '" looks like it will recursively call "' + + attrs[attrName] + '" and cause a stack overflow! Please choose a different scopeName.'); + } + parentGet = $parse(attrs[attrName]); + scope[scopeName] = function(locals) { + return parentGet(scope, locals); + }; + break; + } + }); + }; +}]); + +/** + * @ngdoc service + * @name $ionicBody + * @module ionic + * @description An angular utility service to easily and efficiently + * add and remove CSS classes from the document's body element. + */ +IonicModule +.factory('$ionicBody', ['$document', function($document) { + return { + /** + * @ngdoc method + * @name $ionicBody#add + * @description Add a class to the document's body element. + * @param {string} class Each argument will be added to the body element. + * @returns {$ionicBody} The $ionicBody service so methods can be chained. + */ + addClass: function() { + for (var x = 0; x < arguments.length; x++) { + $document[0].body.classList.add(arguments[x]); + } + return this; + }, + /** + * @ngdoc method + * @name $ionicBody#removeClass + * @description Remove a class from the document's body element. + * @param {string} class Each argument will be removed from the body element. + * @returns {$ionicBody} The $ionicBody service so methods can be chained. + */ + removeClass: function() { + for (var x = 0; x < arguments.length; x++) { + $document[0].body.classList.remove(arguments[x]); + } + return this; + }, + /** + * @ngdoc method + * @name $ionicBody#enableClass + * @description Similar to the `add` method, except the first parameter accepts a boolean + * value determining if the class should be added or removed. Rather than writing user code, + * such as "if true then add the class, else then remove the class", this method can be + * given a true or false value which reduces redundant code. + * @param {boolean} shouldEnableClass A true/false value if the class should be added or removed. + * @param {string} class Each remaining argument would be added or removed depending on + * the first argument. + * @returns {$ionicBody} The $ionicBody service so methods can be chained. + */ + enableClass: function(shouldEnableClass) { + var args = Array.prototype.slice.call(arguments).slice(1); + if (shouldEnableClass) { + this.addClass.apply(this, args); + } else { + this.removeClass.apply(this, args); + } + return this; + }, + /** + * @ngdoc method + * @name $ionicBody#append + * @description Append a child to the document's body. + * @param {element} element The element to be appended to the body. The passed in element + * can be either a jqLite element, or a DOM element. + * @returns {$ionicBody} The $ionicBody service so methods can be chained. + */ + append: function(ele) { + $document[0].body.appendChild(ele.length ? ele[0] : ele); + return this; + }, + /** + * @ngdoc method + * @name $ionicBody#get + * @description Get the document's body element. + * @returns {element} Returns the document's body element. + */ + get: function() { + return $document[0].body; + } + }; +}]); + +IonicModule +.factory('$ionicClickBlock', [ + '$document', + '$ionicBody', + '$timeout', +function($document, $ionicBody, $timeout) { + var CSS_HIDE = 'click-block-hide'; + var cbEle, fallbackTimer, pendingShow; + + function addClickBlock() { + if (pendingShow) { + if (cbEle) { + cbEle.classList.remove(CSS_HIDE); + } else { + cbEle = $document[0].createElement('div'); + cbEle.className = 'click-block'; + $ionicBody.append(cbEle); + } + pendingShow = false; + } + } + + function removeClickBlock() { + cbEle && cbEle.classList.add(CSS_HIDE); + } + + return { + show: function(autoExpire) { + pendingShow = true; + $timeout.cancel(fallbackTimer); + fallbackTimer = $timeout(this.hide, autoExpire || 310); + ionic.requestAnimationFrame(addClickBlock); + }, + hide: function() { + pendingShow = false; + $timeout.cancel(fallbackTimer); + ionic.requestAnimationFrame(removeClickBlock); + } + }; +}]); + +IonicModule +.factory('$collectionDataSource', [ + '$cacheFactory', + '$parse', + '$rootScope', +function($cacheFactory, $parse, $rootScope) { + function hideWithTransform(element) { + element.css(ionic.CSS.TRANSFORM, 'translate3d(-2000px,-2000px,0)'); + } + + function CollectionRepeatDataSource(options) { + var self = this; + this.scope = options.scope; + this.transcludeFn = options.transcludeFn; + this.transcludeParent = options.transcludeParent; + this.element = options.element; + + this.keyExpr = options.keyExpr; + this.listExpr = options.listExpr; + this.trackByExpr = options.trackByExpr; + + this.heightGetter = options.heightGetter; + this.widthGetter = options.widthGetter; + + this.dimensions = []; + this.data = []; + + this.attachedItems = {}; + this.BACKUP_ITEMS_LENGTH = 20; + this.backupItemsArray = []; + } + CollectionRepeatDataSource.prototype = { + setup: function() { + if (this.isSetup) return; + this.isSetup = true; + for (var i = 0; i < this.BACKUP_ITEMS_LENGTH; i++) { + this.detachItem(this.createItem()); + } + }, + destroy: function() { + this.dimensions.length = 0; + this.data = null; + this.backupItemsArray.length = 0; + this.attachedItems = {}; + }, + calculateDataDimensions: function() { + var locals = {}; + this.dimensions = this.data.map(function(value, index) { + locals[this.keyExpr] = value; + locals.$index = index; + return { + width: this.widthGetter(this.scope, locals), + height: this.heightGetter(this.scope, locals) + }; + }, this); + this.dimensions = this.beforeSiblings.concat(this.dimensions).concat(this.afterSiblings); + this.dataStartIndex = this.beforeSiblings.length; + }, + createItem: function() { + var item = {}; + + item.scope = this.scope.$new(); + this.transcludeFn(item.scope, function(clone) { + clone.css('position', 'absolute'); + item.element = clone; + }); + this.transcludeParent.append(item.element); + + return item; + }, + getItem: function(index) { + var item; + if ( (item = this.attachedItems[index]) ) { + //do nothing, the item is good + } else if ( (item = this.backupItemsArray.pop()) ) { + ionic.Utils.reconnectScope(item.scope); + } else { + item = this.createItem(); + } + return item; + }, + attachItemAtIndex: function(index) { + if (index < this.dataStartIndex) { + return this.beforeSiblings[index]; + } + // Subtract so we start at the beginning of this.data, after + // this.beforeSiblings. + index -= this.dataStartIndex; + + if (index > this.data.length - 1) { + return this.afterSiblings[index - this.dataStartIndex]; + } + + var item = this.getItem(index); + var value = this.data[index]; + + if (item.index !== index || item.scope[this.keyExpr] !== value) { + item.index = item.scope.$index = index; + item.scope[this.keyExpr] = value; + item.scope.$first = (index === 0); + item.scope.$last = (index === (this.getLength() - 1)); + item.scope.$middle = !(item.scope.$first || item.scope.$last); + item.scope.$odd = !(item.scope.$even = (index&1) === 0); + + //We changed the scope, so digest if needed + if (!$rootScope.$$phase) { + item.scope.$digest(); + } + } + this.attachedItems[index] = item; + + return item; + }, + destroyItem: function(item) { + item.element.remove(); + item.scope.$destroy(); + item.scope = null; + item.element = null; + }, + detachItem: function(item) { + delete this.attachedItems[item.index]; + + //If it's an outside item, only hide it. These items aren't part of collection + //repeat's list, only sit outside + if (item.isOutside) { + hideWithTransform(item.element); + // If we are at the limit of backup items, just get rid of the this element + } else if (this.backupItemsArray.length >= this.BACKUP_ITEMS_LENGTH) { + this.destroyItem(item); + // Otherwise, add it to our backup items + } else { + this.backupItemsArray.push(item); + hideWithTransform(item.element); + //Don't .$destroy(), just stop watchers and events firing + ionic.Utils.disconnectScope(item.scope); + } + + }, + getLength: function() { + return this.dimensions && this.dimensions.length || 0; + }, + setData: function(value, beforeSiblings, afterSiblings) { + this.data = value || []; + this.beforeSiblings = beforeSiblings || []; + this.afterSiblings = afterSiblings || []; + this.calculateDataDimensions(); + + this.afterSiblings.forEach(function(item) { + item.element.css({position: 'absolute', top: '0', left: '0' }); + hideWithTransform(item.element); + }); + }, + }; + + return CollectionRepeatDataSource; +}]); + + +IonicModule +.factory('$collectionRepeatManager', [ + '$rootScope', + '$timeout', +function($rootScope, $timeout) { + /** + * Vocabulary: "primary" and "secondary" size/direction/position mean + * "y" and "x" for vertical scrolling, or "x" and "y" for horizontal scrolling. + */ + function CollectionRepeatManager(options) { + var self = this; + this.dataSource = options.dataSource; + this.element = options.element; + this.scrollView = options.scrollView; + + this.isVertical = !!this.scrollView.options.scrollingY; + this.renderedItems = {}; + this.dimensions = []; + this.setCurrentIndex(0); + + //Override scrollview's render callback + this.scrollView.__$callback = this.scrollView.__callback; + this.scrollView.__callback = angular.bind(this, this.renderScroll); + + function getViewportSize() { return self.viewportSize; } + //Set getters and setters to match whether this scrollview is vertical or not + if (this.isVertical) { + this.scrollView.options.getContentHeight = getViewportSize; + + this.scrollValue = function() { + return this.scrollView.__scrollTop; + }; + this.scrollMaxValue = function() { + return this.scrollView.__maxScrollTop; + }; + this.scrollSize = function() { + return this.scrollView.__clientHeight; + }; + this.secondaryScrollSize = function() { + return this.scrollView.__clientWidth; + }; + this.transformString = function(y, x) { + return 'translate3d('+x+'px,'+y+'px,0)'; + }; + this.primaryDimension = function(dim) { + return dim.height; + }; + this.secondaryDimension = function(dim) { + return dim.width; + }; + } else { + this.scrollView.options.getContentWidth = getViewportSize; + + this.scrollValue = function() { + return this.scrollView.__scrollLeft; + }; + this.scrollMaxValue = function() { + return this.scrollView.__maxScrollLeft; + }; + this.scrollSize = function() { + return this.scrollView.__clientWidth; + }; + this.secondaryScrollSize = function() { + return this.scrollView.__clientHeight; + }; + this.transformString = function(x, y) { + return 'translate3d('+x+'px,'+y+'px,0)'; + }; + this.primaryDimension = function(dim) { + return dim.width; + }; + this.secondaryDimension = function(dim) { + return dim.height; + }; + } + } + + CollectionRepeatManager.prototype = { + destroy: function() { + this.renderedItems = {}; + this.render = angular.noop; + this.calculateDimensions = angular.noop; + this.dimensions = []; + }, + + /* + * Pre-calculate the position of all items in the data list. + * Do this using the provided width and height (primarySize and secondarySize) + * provided by the dataSource. + */ + calculateDimensions: function() { + /* + * For the sake of explanations below, we're going to pretend we are scrolling + * vertically: Items are laid out with primarySize being height, + * secondarySize being width. + */ + var primaryPos = 0; + var secondaryPos = 0; + var secondaryScrollSize = this.secondaryScrollSize(); + var previousItem; + + this.dataSource.beforeSiblings && this.dataSource.beforeSiblings.forEach(calculateSize, this); + var beforeSize = primaryPos + (previousItem ? previousItem.primarySize : 0); + + primaryPos = secondaryPos = 0; + previousItem = null; + + var dimensions = this.dataSource.dimensions.map(calculateSize, this); + var totalSize = primaryPos + (previousItem ? previousItem.primarySize : 0); + + return { + beforeSize: beforeSize, + totalSize: totalSize, + dimensions: dimensions + }; + + function calculateSize(dim) { + + //Each dimension is an object {width: Number, height: Number} provided by + //the dataSource + var rect = { + //Get the height out of the dimension object + primarySize: this.primaryDimension(dim), + //Max out the item's width to the width of the scrollview + secondarySize: Math.min(this.secondaryDimension(dim), secondaryScrollSize) + }; + + //If this isn't the first item + if (previousItem) { + //Move the item's x position over by the width of the previous item + secondaryPos += previousItem.secondarySize; + //If the y position is the same as the previous item and + //the x position is bigger than the scroller's width + if (previousItem.primaryPos === primaryPos && + secondaryPos + rect.secondarySize > secondaryScrollSize) { + //Then go to the next row, with x position 0 + secondaryPos = 0; + primaryPos += previousItem.primarySize; + } + } + + rect.primaryPos = primaryPos; + rect.secondaryPos = secondaryPos; + + previousItem = rect; + return rect; + } + }, + resize: function() { + var result = this.calculateDimensions(); + this.dimensions = result.dimensions; + this.viewportSize = result.totalSize; + this.beforeSize = result.beforeSize; + this.setCurrentIndex(0); + this.render(true); + this.dataSource.setup(); + }, + /* + * setCurrentIndex sets the index in the list that matches the scroller's position. + * Also save the position in the scroller for next and previous items (if they exist) + */ + setCurrentIndex: function(index, height) { + var currentPos = (this.dimensions[index] || {}).primaryPos || 0; + this.currentIndex = index; + + this.hasPrevIndex = index > 0; + if (this.hasPrevIndex) { + this.previousPos = Math.max( + currentPos - this.dimensions[index - 1].primarySize, + this.dimensions[index - 1].primaryPos + ); + } + this.hasNextIndex = index + 1 < this.dataSource.getLength(); + if (this.hasNextIndex) { + this.nextPos = Math.min( + currentPos + this.dimensions[index + 1].primarySize, + this.dimensions[index + 1].primaryPos + ); + } + }, + /** + * override the scroller's render callback to check if we need to + * re-render our collection + */ + renderScroll: ionic.animationFrameThrottle(function(transformLeft, transformTop, zoom, wasResize) { + if (this.isVertical) { + this.renderIfNeeded(transformTop); + } else { + this.renderIfNeeded(transformLeft); + } + return this.scrollView.__$callback(transformLeft, transformTop, zoom, wasResize); + }), + + renderIfNeeded: function(scrollPos) { + if ((this.hasNextIndex && scrollPos >= this.nextPos) || + (this.hasPrevIndex && scrollPos < this.previousPos)) { + // Math.abs(transformPos - this.lastRenderScrollValue) > 100) { + this.render(); + } + }, + /* + * getIndexForScrollValue: Given the most recent data index and a new scrollValue, + * find the data index that matches that scrollValue. + * + * Strategy (if we are scrolling down): keep going forward in the dimensions list, + * starting at the given index, until an item with height matching the new scrollValue + * is found. + * + * This is a while loop. In the worst case it will have to go through the whole list + * (eg to scroll from top to bottom). The most common case is to scroll + * down 1-3 items at a time. + * + * While this is not as efficient as it could be, optimizing it gives no noticeable + * benefit. We would have to use a new memory-intensive data structure for dimensions + * to fully optimize it. + */ + getIndexForScrollValue: function(i, scrollValue) { + var rect; + //Scrolling up + if (scrollValue <= this.dimensions[i].primaryPos) { + while ( (rect = this.dimensions[i - 1]) && rect.primaryPos > scrollValue) { + i--; + } + //Scrolling down + } else { + while ( (rect = this.dimensions[i + 1]) && rect.primaryPos < scrollValue) { + i++; + } + } + return i; + }, + /* + * render: Figure out the scroll position, the index matching it, and then tell + * the data source to render the correct items into the DOM. + */ + render: function(shouldRedrawAll) { + var self = this; + var i; + var isOutOfBounds = ( this.currentIndex >= this.dataSource.getLength() ); + // We want to remove all the items and redraw everything if we're out of bounds + // or a flag is passed in. + if (isOutOfBounds || shouldRedrawAll) { + for (i in this.renderedItems) { + this.removeItem(i); + } + // Just don't render anything if we're out of bounds + if (isOutOfBounds) return; + } + + var rect; + var scrollValue = this.scrollValue(); + // Scroll size = how many pixels are visible in the scroller at one time + var scrollSize = this.scrollSize(); + // We take the current scroll value and add it to the scrollSize to get + // what scrollValue the current visible scroll area ends at. + var scrollSizeEnd = scrollSize + scrollValue; + // Get the new start index for scrolling, based on the current scrollValue and + // the most recent known index + var startIndex = this.getIndexForScrollValue(this.currentIndex, scrollValue); + + // If we aren't on the first item, add one row of items before so that when the user is + // scrolling up he sees the previous item + var renderStartIndex = Math.max(startIndex - 1, 0); + // Keep adding items to the 'extra row above' until we get to a new row. + // This is for the case where there are multiple items on one row above + // the current item; we want to keep adding items above until + // a new row is reached. + while (renderStartIndex > 0 && + (rect = this.dimensions[renderStartIndex]) && + rect.primaryPos === this.dimensions[startIndex - 1].primaryPos) { + renderStartIndex--; + } + + // Keep rendering items, adding them until we are past the end of the visible scroll area + i = renderStartIndex; + while ((rect = this.dimensions[i]) && (rect.primaryPos - rect.primarySize < scrollSizeEnd)) { + doRender(i, rect); + i++; + } + + // Render two extra items at the end as a buffer + if (self.dimensions[i]) { + doRender(i, self.dimensions[i]); + i++; + } + if (self.dimensions[i]) { + doRender(i, self.dimensions[i]); + } + var renderEndIndex = i; + + // Remove any items that were rendered and aren't visible anymore + for (var renderIndex in this.renderedItems) { + if (renderIndex < renderStartIndex || renderIndex > renderEndIndex) { + this.removeItem(renderIndex); + } + } + + this.setCurrentIndex(startIndex); + + function doRender(dataIndex, rect) { + if (dataIndex < self.dataSource.dataStartIndex) { + // do nothing + } else { + self.renderItem(dataIndex, rect.primaryPos - self.beforeSize, rect.secondaryPos); + } + } + }, + renderItem: function(dataIndex, primaryPos, secondaryPos) { + // Attach an item, and set its transform position to the required value + var item = this.dataSource.attachItemAtIndex(dataIndex); + //console.log(dataIndex, item); + if (item && item.element) { + if (item.primaryPos !== primaryPos || item.secondaryPos !== secondaryPos) { + item.element.css(ionic.CSS.TRANSFORM, this.transformString( + primaryPos, secondaryPos + )); + item.primaryPos = primaryPos; + item.secondaryPos = secondaryPos; + } + // Save the item in rendered items + this.renderedItems[dataIndex] = item; + } else { + // If an item at this index doesn't exist anymore, be sure to delete + // it from rendered items + delete this.renderedItems[dataIndex]; + } + }, + removeItem: function(dataIndex) { + // Detach a given item + var item = this.renderedItems[dataIndex]; + if (item) { + item.primaryPos = item.secondaryPos = null; + this.dataSource.detachItem(item); + delete this.renderedItems[dataIndex]; + } + } + }; + + return CollectionRepeatManager; +}]); + + +/** + * @ngdoc service + * @name $ionicGesture + * @module ionic + * @description An angular service exposing ionic + * {@link ionic.utility:ionic.EventController}'s gestures. + */ +IonicModule +.factory('$ionicGesture', [function() { + return { + /** + * @ngdoc method + * @name $ionicGesture#on + * @description Add an event listener for a gesture on an element. See {@link ionic.utility:ionic.EventController#onGesture}. + * @param {string} eventType The gesture event to listen for. + * @param {function(e)} callback The function to call when the gesture + * happens. + * @param {element} $element The angular element to listen for the event on. + * @param {object} options object. + * @returns {ionic.Gesture} The gesture object (use this to remove the gesture later on). + */ + on: function(eventType, cb, $element, options) { + return window.ionic.onGesture(eventType, cb, $element[0], options); + }, + /** + * @ngdoc method + * @name $ionicGesture#off + * @description Remove an event listener for a gesture on an element. See {@link ionic.utility:ionic.EventController#offGesture}. + * @param {ionic.Gesture} gesture The gesture that should be removed. + * @param {string} eventType The gesture event to remove the listener for. + * @param {function(e)} callback The listener to remove. + */ + off: function(gesture, eventType, cb) { + return window.ionic.offGesture(gesture, eventType, cb); + } + }; +}]); + +/** + * @ngdoc service + * @name $ionicHistory + * @module ionic + * @description + * $ionicHistory keeps track of views as the user navigates through an app. Similar to the way a + * browser behaves, an Ionic app is able to keep track of the previous view, the current view, and + * the forward view (if there is one). However, a typical web browser only keeps track of one + * history stack in a linear fashion. + * + * Unlike a traditional browser environment, apps and webapps have parallel independent histories, + * such as with tabs. Should a user navigate few pages deep on one tab, and then switch to a new + * tab and back, the back button relates not to the previous tab, but to the previous pages + * visited within _that_ tab. + * + * `$ionicHistory` facilitates this parallel history architecture. + */ + +IonicModule +.factory('$ionicHistory', [ + '$rootScope', + '$state', + '$location', + '$window', + '$timeout', + '$ionicViewSwitcher', + '$ionicNavViewDelegate', +function($rootScope, $state, $location, $window, $timeout, $ionicViewSwitcher, $ionicNavViewDelegate) { + + // history actions while navigating views + var ACTION_INITIAL_VIEW = 'initialView'; + var ACTION_NEW_VIEW = 'newView'; + var ACTION_MOVE_BACK = 'moveBack'; + var ACTION_MOVE_FORWARD = 'moveForward'; + + // direction of navigation + var DIRECTION_BACK = 'back'; + var DIRECTION_FORWARD = 'forward'; + var DIRECTION_ENTER = 'enter'; + var DIRECTION_EXIT = 'exit'; + var DIRECTION_SWAP = 'swap'; + var DIRECTION_NONE = 'none'; + + var stateChangeCounter = 0; + var lastStateId, nextViewOptions, nextViewExpireTimer, forcedNav; + + var viewHistory = { + histories: { root: { historyId: 'root', parentHistoryId: null, stack: [], cursor: -1 } }, + views: {}, + backView: null, + forwardView: null, + currentView: null + }; + + var View = function() {}; + View.prototype.initialize = function(data) { + if (data) { + for (var name in data) this[name] = data[name]; + return this; + } + return null; + }; + View.prototype.go = function() { + + if (this.stateName) { + return $state.go(this.stateName, this.stateParams); + } + + if (this.url && this.url !== $location.url()) { + + if (viewHistory.backView === this) { + return $window.history.go(-1); + } else if (viewHistory.forwardView === this) { + return $window.history.go(1); + } + + $location.url(this.url); + return; + } + + return null; + }; + View.prototype.destroy = function() { + if (this.scope) { + this.scope.$destroy && this.scope.$destroy(); + this.scope = null; + } + }; + + + function getViewById(viewId) { + return (viewId ? viewHistory.views[ viewId ] : null); + } + + function getBackView(view) { + return (view ? getViewById(view.backViewId) : null); + } + + function getForwardView(view) { + return (view ? getViewById(view.forwardViewId) : null); + } + + function getHistoryById(historyId) { + return (historyId ? viewHistory.histories[ historyId ] : null); + } + + function getHistory(scope) { + var histObj = getParentHistoryObj(scope); + + if (!viewHistory.histories[ histObj.historyId ]) { + // this history object exists in parent scope, but doesn't + // exist in the history data yet + viewHistory.histories[ histObj.historyId ] = { + historyId: histObj.historyId, + parentHistoryId: getParentHistoryObj(histObj.scope.$parent).historyId, + stack: [], + cursor: -1 + }; + } + return getHistoryById(histObj.historyId); + } + + function getParentHistoryObj(scope) { + var parentScope = scope; + while (parentScope) { + if (parentScope.hasOwnProperty('$historyId')) { + // this parent scope has a historyId + return { historyId: parentScope.$historyId, scope: parentScope }; + } + // nothing found keep climbing up + parentScope = parentScope.$parent; + } + // no history for the parent, use the root + return { historyId: 'root', scope: $rootScope }; + } + + function setNavViews(viewId) { + viewHistory.currentView = getViewById(viewId); + viewHistory.backView = getBackView(viewHistory.currentView); + viewHistory.forwardView = getForwardView(viewHistory.currentView); + } + + function getCurrentStateId() { + var id; + if ($state && $state.current && $state.current.name) { + id = $state.current.name; + if ($state.params) { + for (var key in $state.params) { + if ($state.params.hasOwnProperty(key) && $state.params[key]) { + id += "_" + key + "=" + $state.params[key]; + } + } + } + return id; + } + // if something goes wrong make sure its got a unique stateId + return ionic.Utils.nextUid(); + } + + function getCurrentStateParams() { + var rtn; + if ($state && $state.params) { + for (var key in $state.params) { + if ($state.params.hasOwnProperty(key)) { + rtn = rtn || {}; + rtn[key] = $state.params[key]; + } + } + } + return rtn; + } + + + return { + + register: function(parentScope, viewLocals) { + + var currentStateId = getCurrentStateId(), + hist = getHistory(parentScope), + currentView = viewHistory.currentView, + backView = viewHistory.backView, + forwardView = viewHistory.forwardView, + viewId = null, + action = null, + direction = DIRECTION_NONE, + historyId = hist.historyId, + url = $location.url(), + tmp, x, ele; + + if (lastStateId !== currentStateId) { + lastStateId = currentStateId; + stateChangeCounter++; + } + + if (forcedNav) { + // we've previously set exactly what to do + viewId = forcedNav.viewId; + action = forcedNav.action; + direction = forcedNav.direction; + forcedNav = null; + + } else if (backView && backView.stateId === currentStateId) { + // they went back one, set the old current view as a forward view + viewId = backView.viewId; + historyId = backView.historyId; + action = ACTION_MOVE_BACK; + if (backView.historyId === currentView.historyId) { + // went back in the same history + direction = DIRECTION_BACK; + + } else if (currentView) { + direction = DIRECTION_EXIT; + + tmp = getHistoryById(backView.historyId); + if (tmp && tmp.parentHistoryId === currentView.historyId) { + direction = DIRECTION_ENTER; + + } else { + tmp = getHistoryById(currentView.historyId); + if (tmp && tmp.parentHistoryId === hist.parentHistoryId) { + direction = DIRECTION_SWAP; + } + } + } + + } else if (forwardView && forwardView.stateId === currentStateId) { + // they went to the forward one, set the forward view to no longer a forward view + viewId = forwardView.viewId; + historyId = forwardView.historyId; + action = ACTION_MOVE_FORWARD; + if (forwardView.historyId === currentView.historyId) { + direction = DIRECTION_FORWARD; + + } else if (currentView) { + direction = DIRECTION_EXIT; + + if (currentView.historyId === hist.parentHistoryId) { + direction = DIRECTION_ENTER; + + } else { + tmp = getHistoryById(currentView.historyId); + if (tmp && tmp.parentHistoryId === hist.parentHistoryId) { + direction = DIRECTION_SWAP; + } + } + } + + tmp = getParentHistoryObj(parentScope); + if (forwardView.historyId && tmp.scope) { + // if a history has already been created by the forward view then make sure it stays the same + tmp.scope.$historyId = forwardView.historyId; + historyId = forwardView.historyId; + } + + } else if (currentView && currentView.historyId !== historyId && + hist.cursor > -1 && hist.stack.length > 0 && hist.cursor < hist.stack.length && + hist.stack[hist.cursor].stateId === currentStateId) { + // they just changed to a different history and the history already has views in it + var switchToView = hist.stack[hist.cursor]; + viewId = switchToView.viewId; + historyId = switchToView.historyId; + action = ACTION_MOVE_BACK; + direction = DIRECTION_SWAP; + + tmp = getHistoryById(currentView.historyId); + if (tmp && tmp.parentHistoryId === historyId) { + direction = DIRECTION_EXIT; + + } else { + tmp = getHistoryById(historyId); + if (tmp && tmp.parentHistoryId === currentView.historyId) { + direction = DIRECTION_ENTER; + } + } + + // if switching to a different history, and the history of the view we're switching + // to has an existing back view from a different history than itself, then + // it's back view would be better represented using the current view as its back view + tmp = getViewById(switchToView.backViewId); + if (tmp && switchToView.historyId !== tmp.historyId) { + hist.stack[hist.cursor].backViewId = currentView.viewId; + } + + } else { + + // create an element from the viewLocals template + ele = $ionicViewSwitcher.createViewEle(viewLocals); + if (this.isAbstractEle(ele, viewLocals)) { + void 0; + return { + action: 'abstractView', + direction: DIRECTION_NONE, + ele: ele + }; + } + + // set a new unique viewId + viewId = ionic.Utils.nextUid(); + + if (currentView) { + // set the forward view if there is a current view (ie: if its not the first view) + currentView.forwardViewId = viewId; + + action = ACTION_NEW_VIEW; + + // check if there is a new forward view within the same history + if (forwardView && currentView.stateId !== forwardView.stateId && + currentView.historyId === forwardView.historyId) { + // they navigated to a new view but the stack already has a forward view + // since its a new view remove any forwards that existed + tmp = getHistoryById(forwardView.historyId); + if (tmp) { + // the forward has a history + for (x = tmp.stack.length - 1; x >= forwardView.index; x--) { + // starting from the end destroy all forwards in this history from this point + tmp.stack[x].destroy(); + tmp.stack.splice(x); + } + historyId = forwardView.historyId; + } + } + + // its only moving forward if its in the same history + if (hist.historyId === currentView.historyId) { + direction = DIRECTION_FORWARD; + + } else if (currentView.historyId !== hist.historyId) { + direction = DIRECTION_ENTER; + + tmp = getHistoryById(currentView.historyId); + if (tmp && tmp.parentHistoryId === hist.parentHistoryId) { + direction = DIRECTION_SWAP; + + } else { + tmp = getHistoryById(tmp.parentHistoryId); + if (tmp && tmp.historyId === hist.historyId) { + direction = DIRECTION_EXIT; + } + } + } + + } else { + // there's no current view, so this must be the initial view + action = ACTION_INITIAL_VIEW; + } + + if (stateChangeCounter < 2) { + // views that were spun up on the first load should not animate + direction = DIRECTION_NONE; + } + + // add the new view + viewHistory.views[viewId] = this.createView({ + viewId: viewId, + index: hist.stack.length, + historyId: hist.historyId, + backViewId: (currentView && currentView.viewId ? currentView.viewId : null), + forwardViewId: null, + stateId: currentStateId, + stateName: this.currentStateName(), + stateParams: getCurrentStateParams(), + url: url + }); + + // add the new view to this history's stack + hist.stack.push(viewHistory.views[viewId]); + } + + $timeout.cancel(nextViewExpireTimer); + if (nextViewOptions) { + if (nextViewOptions.disableAnimate) direction = DIRECTION_NONE; + if (nextViewOptions.disableBack) viewHistory.views[viewId].backViewId = null; + if (nextViewOptions.historyRoot) { + for (x = 0; x < hist.stack.length; x++) { + if (hist.stack[x].viewId === viewId) { + hist.stack[x].index = 0; + hist.stack[x].backViewId = hist.stack[x].forwardViewId = null; + } else { + delete viewHistory.views[hist.stack[x].viewId]; + } + } + hist.stack = [viewHistory.views[viewId]]; + } + nextViewOptions = null; + } + + setNavViews(viewId); + + if (viewHistory.backView && historyId == viewHistory.backView.historyId && currentStateId == viewHistory.backView.stateId && url == viewHistory.backView.url) { + for (x = 0; x < hist.stack.length; x++) { + if (hist.stack[x].viewId == viewId) { + action = 'dupNav'; + direction = DIRECTION_NONE; + hist.stack[x - 1].forwardViewId = viewHistory.forwardView = null; + viewHistory.currentView.index = viewHistory.backView.index; + viewHistory.currentView.backViewId = viewHistory.backView.backViewId; + viewHistory.backView = getBackView(viewHistory.backView); + hist.stack.splice(x, 1); + break; + } + } + } + + void 0; + + hist.cursor = viewHistory.currentView.index; + + return { + viewId: viewId, + action: action, + direction: direction, + historyId: historyId, + enableBack: !!(viewHistory.backView && viewHistory.backView.historyId === viewHistory.currentView.historyId), + isHistoryRoot: (viewHistory.currentView.index === 0), + ele: ele + }; + }, + + registerHistory: function(scope) { + scope.$historyId = ionic.Utils.nextUid(); + }, + + createView: function(data) { + var newView = new View(); + return newView.initialize(data); + }, + + getViewById: getViewById, + + /** + * @ngdoc method + * @name $ionicHistory#viewHistory + * @description The app's view history data, such as all the views and histories, along + * with how they are ordered and linked together within the navigation stack. + * @returns {object} Returns an object containing the apps view history data. + */ + viewHistory: function() { + return viewHistory; + }, + + /** + * @ngdoc method + * @name $ionicHistory#currentView + * @description The app's current view. + * @returns {object} Returns the current view. + */ + currentView: function(view) { + if (arguments.length) { + viewHistory.currentView = view; + } + return viewHistory.currentView; + }, + + /** + * @ngdoc method + * @name $ionicHistory#currentHistoryId + * @description The ID of the history stack which is the parent container of the current view. + * @returns {string} Returns the current history ID. + */ + currentHistoryId: function() { + return viewHistory.currentView ? viewHistory.currentView.historyId : null; + }, + + /** + * @ngdoc method + * @name $ionicHistory#currentTitle + * @description Gets and sets the current view's title. + * @param {string=} val The title to update the current view with. + * @returns {string} Returns the current view's title. + */ + currentTitle: function(val) { + if (viewHistory.currentView) { + if (arguments.length) { + viewHistory.currentView.title = val; + } + return viewHistory.currentView.title; + } + }, + + /** + * @ngdoc method + * @name $ionicHistory#backView + * @description Returns the view that was before the current view in the history stack. + * If the user navigated from View A to View B, then View A would be the back view, and + * View B would be the current view. + * @returns {object} Returns the back view. + */ + backView: function(view) { + if (arguments.length) { + viewHistory.backView = view; + } + return viewHistory.backView; + }, + + /** + * @ngdoc method + * @name $ionicHistory#backTitle + * @description Gets the back view's title. + * @returns {string} Returns the back view's title. + */ + backTitle: function() { + if (viewHistory.backView) { + return viewHistory.backView.title; + } + }, + + /** + * @ngdoc method + * @name $ionicHistory#forwardView + * @description Returns the view that was in front of the current view in the history stack. + * A forward view would exist if the user navigated from View A to View B, then + * navigated back to View A. At this point then View B would be the forward view, and View + * A would be the current view. + * @returns {object} Returns the forward view. + */ + forwardView: function(view) { + if (arguments.length) { + viewHistory.forwardView = view; + } + return viewHistory.forwardView; + }, + + /** + * @ngdoc method + * @name $ionicHistory#currentStateName + * @description Returns the current state name. + * @returns {string} + */ + currentStateName: function() { + return ($state && $state.current ? $state.current.name : null); + }, + + isCurrentStateNavView: function(navView) { + return !!($state && $state.current && $state.current.views && $state.current.views[navView]); + }, + + goToHistoryRoot: function(historyId) { + if (historyId) { + var hist = getHistoryById(historyId); + if (hist && hist.stack.length) { + if (viewHistory.currentView && viewHistory.currentView.viewId === hist.stack[0].viewId) { + return; + } + forcedNav = { + viewId: hist.stack[0].viewId, + action: ACTION_MOVE_BACK, + direction: DIRECTION_BACK + }; + hist.stack[0].go(); + } + } + }, + + /** + * @ngdoc method + * @name $ionicHistory#goBack + * @description Navigates the app to the back view, if a back view exists. + */ + goBack: function() { + viewHistory.backView && viewHistory.backView.go(); + }, + + /** + * @ngdoc method + * @name $ionicHistory#clearHistory + * @description Clears out the app's entire history, except for the current view. + */ + clearHistory: function() { + var + histories = viewHistory.histories, + currentView = viewHistory.currentView; + + if (histories) { + for (var historyId in histories) { + + if (histories[historyId].stack) { + histories[historyId].stack = []; + histories[historyId].cursor = -1; + } + + if (currentView && currentView.historyId === historyId) { + currentView.backViewId = currentView.forwardViewId = null; + histories[historyId].stack.push(currentView); + } else if (histories[historyId].destroy) { + histories[historyId].destroy(); + } + + } + } + + for (var viewId in viewHistory.views) { + if (viewId !== currentView.viewId) { + delete viewHistory.views[viewId]; + } + } + + if (currentView) { + setNavViews(currentView.viewId); + } + }, + + /** + * @ngdoc method + * @name $ionicHistory#clearCache + * @description Removes all cached views within every {@link ionic.directive:ionNavView}. + * This both removes the view element from the DOM, and destroy it's scope. + */ + clearCache: function() { + $ionicNavViewDelegate._instances.forEach(function(instance) { + instance.clearCache(); + }); + }, + + /** + * @ngdoc method + * @name $ionicHistory#nextViewOptions + * @description Sets options for the next view. This method can be useful to override + * certain view/transition defaults right before a view transition happens. For example, + * the {@link ionic.directive:menuClose} directive uses this method internally to ensure + * an animated view transition does not happen when a side menu is open, and also sets + * the next view as the root of its history stack. After the transition these options + * are set back to null. + * + * Available options: + * + * * `disableAnimate`: Do not animate the next transition. + * * `disableBack`: The next view should forget its back view, and set it to null. + * * `historyRoot`: The next view should become the root view in its history stack. + * + * ```js + * $ionicHistory.nextViewOptions({ + * disableAnimate: true, + * disableBack: true + * }); + * ``` + */ + nextViewOptions: function(opts) { + if (arguments.length) { + $timeout.cancel(nextViewExpireTimer); + if (opts === null) { + nextViewOptions = opts; + } else { + nextViewOptions = nextViewOptions || {}; + extend(nextViewOptions, opts); + if (nextViewOptions.expire) { + nextViewExpireTimer = $timeout(function(){ + nextViewOptions = null; + }, nextViewOptions.expire); + } + } + } + return nextViewOptions; + }, + + isAbstractEle: function(ele, viewLocals) { + if (viewLocals && viewLocals.$$state && viewLocals.$$state.self.abstract) { + return true; + } + return !!(ele && (isAbstractTag(ele) || isAbstractTag(ele.children()))); + }, + + isActiveScope: function(scope) { + if (!scope) return false; + + var climbScope = scope; + var currentHistoryId = this.currentHistoryId(); + var foundHistoryId; + + while (climbScope) { + if (climbScope.$$disconnected) { + return false; + } + + if (!foundHistoryId && climbScope.hasOwnProperty('$historyId')) { + foundHistoryId = true; + } + + if (currentHistoryId) { + if (climbScope.hasOwnProperty('$historyId') && currentHistoryId == climbScope.$historyId) { + return true; + } + if (climbScope.hasOwnProperty('$activeHistoryId')) { + if (currentHistoryId == climbScope.$activeHistoryId) { + if (climbScope.hasOwnProperty('$historyId')) { + return true; + } + if (!foundHistoryId) { + return true; + } + } + } + } + + if (foundHistoryId && climbScope.hasOwnProperty('$activeHistoryId')) { + foundHistoryId = false; + } + + climbScope = climbScope.$parent; + } + + return currentHistoryId ? currentHistoryId == 'root' : true; + } + + }; + + function isAbstractTag(ele) { + return ele && ele.length && /ion-side-menus|ion-tabs/i.test(ele[0].tagName); + } + +}]) + +.run([ + '$rootScope', + '$state', + '$location', + '$document', + '$ionicPlatform', + '$ionicHistory', +function($rootScope, $state, $location, $document, $ionicPlatform, $ionicHistory) { + + // always reset the keyboard state when change stage + $rootScope.$on('$ionicView.beforeEnter', function() { + ionic.keyboard && ionic.keyboard.hide && ionic.keyboard.hide(); + }); + + $rootScope.$on('$ionicHistory.change', function(e, data) { + if (!data) return; + + var viewHistory = $ionicHistory.viewHistory(); + + var hist = (data.historyId ? viewHistory.histories[ data.historyId ] : null); + if (hist && hist.cursor > -1 && hist.cursor < hist.stack.length) { + // the history they're going to already exists + // go to it's last view in its stack + var view = hist.stack[ hist.cursor ]; + return view.go(data); + } + + // this history does not have a URL, but it does have a uiSref + // figure out its URL from the uiSref + if (!data.url && data.uiSref) { + data.url = $state.href(data.uiSref); + } + + if (data.url) { + // don't let it start with a #, messes with $location.url() + if (data.url.indexOf('#') === 0) { + data.url = data.url.replace('#', ''); + } + if (data.url !== $location.url()) { + // we've got a good URL, ready GO! + $location.url(data.url); + } + } + }); + + $rootScope.$ionicGoBack = function() { + $ionicHistory.goBack(); + }; + + // Set the document title when a new view is shown + $rootScope.$on('$ionicView.afterEnter', function(ev, data) { + if (data && data.title) { + $document[0].title = data.title; + } + }); + + // Triggered when devices with a hardware back button (Android) is clicked by the user + // This is a Cordova/Phonegap platform specifc method + function onHardwareBackButton(e) { + var backView = $ionicHistory.backView(); + if (backView) { + // there is a back view, go to it + backView.go(); + } else { + // there is no back view, so close the app instead + ionic.Platform.exitApp(); + } + e.preventDefault(); + return false; + } + $ionicPlatform.registerBackButtonAction( + onHardwareBackButton, + PLATFORM_BACK_BUTTON_PRIORITY_VIEW + ); + +}]); + +/** + * @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 preform 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#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#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 + }, + navBar: { + alignTitle: PLATFORM, + positionPrimaryButtons: PLATFORM, + positionSecondaryButtons: PLATFORM, + transition: PLATFORM + }, + backButton: { + icon: PLATFORM, + text: PLATFORM, + previousTitleText: PLATFORM + }, + form: { + checkbox: PLATFORM + }, + tabs: { + style: PLATFORM, + position: PLATFORM + }, + templates: { + maxPrefetch: PLATFORM + }, + platform: {} + }; + createConfig(configProperties, provider, ''); + + + + // Default + // ------------------------- + setPlatformConfig('default', { + + views: { + maxCache: 10, + forwardCache: false, + transition: 'ios' + }, + + navBar: { + alignTitle: 'center', + positionPrimaryButtons: 'left', + positionSecondaryButtons: 'right', + transition: 'view' + }, + + backButton: { + icon: 'ion-ios7-arrow-back', + text: 'Back', + previousTitleText: true + }, + + form: { + checkbox: 'circle' + }, + + tabs: { + style: 'standard', + position: 'bottom' + }, + + templates: { + maxPrefetch: 30 + } + + }); + + + + // iOS (it is the default already) + // ------------------------- + setPlatformConfig('ios', {}); + + + + // Android + // ------------------------- + setPlatformConfig('android', { + + views: { + transition: 'android' + }, + + navBar: { + alignTitle: 'left', + positionPrimaryButtons: 'right', + positionSecondaryButtons: 'right' + }, + + backButton: { + icon: 'ion-arrow-left-c', + text: false, + previousTitleText: false + }, + + form: { + checkbox: 'square' + }, + + tabs: { + style: 'striped', + position: 'top' + } + + }); + + + provider.transitions = { + views: {}, + navBar: {} + }; + + + // iOS Transitions + // ----------------------- + provider.transitions.views.ios = function(enteringEle, leavingEle, direction, shouldAnimate) { + shouldAnimate = shouldAnimate && (direction == 'forward' || direction == 'back'); + + function setStyles(ele, opacity, x) { + var css = {}; + css[ionic.CSS.TRANSITION_DURATION] = shouldAnimate ? '' : 0; + css.opacity = opacity; + css[ionic.CSS.TRANSFORM] = 'translate3d(' + x + '%,0,0)'; + ionic.DomUtil.cachedStyles(ele, css); + } + + return { + run: function(step) { + if (direction == 'forward') { + setStyles(enteringEle, 1, (1 - step) * 99); // starting at 98% prevents a flicker + setStyles(leavingEle, (1 - 0.1 * step), step * -33); + + } else if (direction == 'back') { + setStyles(enteringEle, (1 - 0.1 * (1 - step)), (1 - step) * -33); + setStyles(leavingEle, 1, step * 100); + + } else { + // swap, enter, exit + setStyles(enteringEle, 1, 0); + setStyles(leavingEle, 0, 0); + } + }, + shouldAnimate: shouldAnimate + }; + }; + + provider.transitions.navBar.ios = function(enteringHeaderBar, leavingHeaderBar, direction, shouldAnimate) { + shouldAnimate = shouldAnimate && (direction == 'forward' || direction == 'back'); + + function setStyles(ctrl, opacity, titleX, backTextX) { + var css = {}; + css[ionic.CSS.TRANSITION_DURATION] = shouldAnimate ? '' : 0; + 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) 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) return; + var titleX = (-(ctrlA.titleTextX() - ctrlB.backButtonTextLeft()) - (ctrlA.titleLeftRight())) * step; + setStyles(ctrlA, 1 - step, titleX, 0); + } + + return { + run: function(step) { + var enteringHeaderCtrl = enteringHeaderBar.controller(); + var leavingHeaderCtrl = leavingHeaderBar && leavingHeaderBar.controller(); + if (direction == 'back') { + leave(enteringHeaderCtrl, leavingHeaderCtrl, 1 - step); + enter(leavingHeaderCtrl, enteringHeaderCtrl, 1 - step); + } else { + enter(enteringHeaderCtrl, leavingHeaderCtrl, step); + leave(leavingHeaderCtrl, enteringHeaderCtrl, step); + } + }, + shouldAnimate: shouldAnimate + }; + }; + + + // Android Transitions + // ----------------------- + + provider.transitions.views.android = function(enteringEle, leavingEle, direction, shouldAnimate) { + shouldAnimate = shouldAnimate && (direction == 'forward' || direction == 'back'); + + function setStyles(ele, x) { + var css = {}; + css[ionic.CSS.TRANSITION_DURATION] = shouldAnimate ? '' : 0; + css[ionic.CSS.TRANSFORM] = 'translate3d(' + x + '%,0,0)'; + ionic.DomUtil.cachedStyles(ele, css); + } + + return { + run: function(step) { + if (direction == 'forward') { + setStyles(enteringEle, (1 - step) * 99); // starting at 98% prevents a flicker + setStyles(leavingEle, step * -100); + + } else if (direction == 'back') { + setStyles(enteringEle, (1 - step) * -100); + setStyles(leavingEle, step * 100); + + } else { + // swap, enter, exit + setStyles(enteringEle, 0); + setStyles(leavingEle, 0); + } + }, + shouldAnimate: shouldAnimate + }; + }; + + provider.transitions.navBar.android = function(enteringHeaderBar, leavingHeaderBar, direction, shouldAnimate) { + shouldAnimate = shouldAnimate && (direction == 'forward' || direction == 'back'); + + 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: true + }; + }; + + + // No Transition + // ----------------------- + + provider.transitions.views.none = function(enteringEle, leavingEle) { + return { + run: function(step) { + provider.transitions.views.android(enteringEle, leavingEle, false, false).run(step); + } + }; + }; + + 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); + } + }; + }; + + + // 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; + }; +}); + + +var LOADING_TPL = + '
' + + '
' + + '
' + + '
'; + +var LOADING_HIDE_DEPRECATED = '$ionicLoading instance.hide() has been deprecated. Use $ionicLoading.hide().'; +var LOADING_SHOW_DEPRECATED = '$ionicLoading instance.show() has been deprecated. Use $ionicLoading.show().'; +var LOADING_SET_DEPRECATED = '$ionicLoading instance.setContent() has been deprecated. Use $ionicLoading.show({ template: \'my content\' }).'; + +/** + * @ngdoc service + * @name $ionicLoading + * @module ionic + * @description + * An overlay that can be used to indicate activity while blocking user + * interaction. + * + * @usage + * ```js + * angular.module('LoadingApp', ['ionic']) + * .controller('LoadingCtrl', function($scope, $ionicLoading) { + * $scope.show = function() { + * $ionicLoading.show({ + * template: 'Loading...' + * }); + * }; + * $scope.hide = function(){ + * $ionicLoading.hide(); + * }; + * }); + * ``` + */ +/** + * @ngdoc object + * @name $ionicLoadingConfig + * @module ionic + * @description + * Set the default options to be passed to the {@link ionic.service:$ionicLoading} service. + * + * @usage + * ```js + * var app = angular.module('myApp', ['ionic']) + * app.constant('$ionicLoadingConfig', { + * template: 'Default Loading Template...' + * }); + * app.controller('AppCtrl', function($scope, $ionicLoading) { + * $scope.showLoading = function() { + * $ionicLoading.show(); //options default to values in $ionicLoadingConfig + * }; + * }); + * ``` + */ +IonicModule +.constant('$ionicLoadingConfig', { + template: '' +}) +.factory('$ionicLoading', [ + '$ionicLoadingConfig', + '$ionicBody', + '$ionicTemplateLoader', + '$ionicBackdrop', + '$timeout', + '$q', + '$log', + '$compile', + '$ionicPlatform', + '$rootScope', +function($ionicLoadingConfig, $ionicBody, $ionicTemplateLoader, $ionicBackdrop, $timeout, $q, $log, $compile, $ionicPlatform, $rootScope) { + + var loaderInstance; + //default values + var deregisterBackAction = angular.noop; + var deregisterStateListener = angular.noop; + var loadingShowDelay = $q.when(); + + return { + /** + * @ngdoc method + * @name $ionicLoading#show + * @description Shows a loading indicator. If the indicator is already shown, + * it will set the options given and keep the indicator shown. + * @param {object} opts The options for the loading indicator. Available properties: + * - `{string=}` `template` The html content of the indicator. + * - `{string=}` `templateUrl` The url of an html template to load as the content of the indicator. + * - `{object=}` `scope` The scope to be a child of. Default: creates a child of $rootScope. + * - `{boolean=}` `noBackdrop` Whether to hide the backdrop. By default it will be shown. + * - `{boolean=}` `hideOnStateChange` Whether to hide the loading spinner when navigating + * to a new state. Default false. + * - `{number=}` `delay` How many milliseconds to delay showing the indicator. By default there is no delay. + * - `{number=}` `duration` How many milliseconds to wait until automatically + * hiding the indicator. By default, the indicator will be shown until `.hide()` is called. + */ + show: showLoader, + /** + * @ngdoc method + * @name $ionicLoading#hide + * @description Hides the loading indicator, if shown. + */ + hide: hideLoader, + /** + * @private for testing + */ + _getLoader: getLoader + }; + + function getLoader() { + if (!loaderInstance) { + loaderInstance = $ionicTemplateLoader.compile({ + template: LOADING_TPL, + appendTo: $ionicBody.get() + }) + .then(function(loader) { + var self = loader; + + loader.show = function(options) { + var templatePromise = options.templateUrl ? + $ionicTemplateLoader.load(options.templateUrl) : + //options.content: deprecated + $q.when(options.template || options.content || ''); + + self.scope = options.scope || self.scope; + + if (!this.isShown) { + //options.showBackdrop: deprecated + this.hasBackdrop = !options.noBackdrop && options.showBackdrop !== false; + if (this.hasBackdrop) { + $ionicBackdrop.retain(); + $ionicBackdrop.getElement().addClass('backdrop-loading'); + } + } + + if (options.duration) { + $timeout.cancel(this.durationTimeout); + this.durationTimeout = $timeout( + angular.bind(this, this.hide), + +options.duration + ); + } + + deregisterBackAction(); + //Disable hardware back button while loading + deregisterBackAction = $ionicPlatform.registerBackButtonAction( + angular.noop, + PLATFORM_BACK_BUTTON_PRIORITY_LOADING + ); + + templatePromise.then(function(html) { + if (html) { + var loading = self.element.children(); + loading.html(html); + $compile(loading.contents())(self.scope); + } + + //Don't show until template changes + if (self.isShown) { + self.element.addClass('visible'); + ionic.requestAnimationFrame(function() { + if(self.isShown) { + self.element.addClass('active'); + $ionicBody.addClass('loading-active'); + } + }); + } + }); + + this.isShown = true; + }; + loader.hide = function() { + + deregisterBackAction(); + if (this.isShown) { + if (this.hasBackdrop) { + $ionicBackdrop.release(); + $ionicBackdrop.getElement().removeClass('backdrop-loading'); + } + self.element.removeClass('active'); + $ionicBody.removeClass('loading-active'); + setTimeout(function() { + !self.isShown && self.element.removeClass('visible'); + }, 200); + } + $timeout.cancel(this.durationTimeout); + this.isShown = false; + }; + + return loader; + }); + } + return loaderInstance; + } + + function showLoader(options) { + options = extend({}, $ionicLoadingConfig || {}, options || {}); + var delay = options.delay || options.showDelay || 0; + + //If loading.show() was called previously, cancel it and show with our new options + loadingShowDelay && $timeout.cancel(loadingShowDelay); + loadingShowDelay = $timeout(angular.noop, delay); + + loadingShowDelay.then(getLoader).then(function(loader) { + if (options.hideOnStateChange) { + deregisterStateListener = $rootScope.$on('$stateChangeSuccess', hideLoader); + } + return loader.show(options); + }); + + return { + hide: deprecated.method(LOADING_HIDE_DEPRECATED, $log.error, hideLoader), + show: deprecated.method(LOADING_SHOW_DEPRECATED, $log.error, function() { + showLoader(options); + }), + setContent: deprecated.method(LOADING_SET_DEPRECATED, $log.error, function(content) { + getLoader().then(function(loader) { + loader.show({ template: content }); + }); + }) + }; + } + + function hideLoader() { + deregisterStateListener(); + $timeout.cancel(loadingShowDelay); + getLoader().then(function(loader) { + loader.hide(); + }); + } +}]); + +/** + * @ngdoc service + * @name $ionicModal + * @module ionic + * @description + * + * Related: {@link ionic.controller:ionicModal ionicModal controller}. + * + * The Modal is a content pane that can go over the user's main view + * temporarily. Usually used for making a choice or editing an item. + * + * Put the content of the modal inside of an `` element. + * + * **Notes:** + * - A modal will broadcast 'modal.shown', 'modal.hidden', and 'modal.removed' events from its originating + * scope, passing in itself as an event argument. Both the modal.removed and modal.hidden events are + * called when the modal is removed. + * + * - This example assumes your modal is in your main index file or another template file. If it is in its own + * template file, remove the script tags and call it by file name. + * + * @usage + * ```html + * + * ``` + * ```js + * angular.module('testApp', ['ionic']) + * .controller('MyController', function($scope, $ionicModal) { + * $ionicModal.fromTemplateUrl('my-modal.html', { + * scope: $scope, + * animation: 'slide-in-up' + * }).then(function(modal) { + * $scope.modal = modal; + * }); + * $scope.openModal = function() { + * $scope.modal.show(); + * }; + * $scope.closeModal = function() { + * $scope.modal.hide(); + * }; + * //Cleanup the modal when we're done with it! + * $scope.$on('$destroy', function() { + * $scope.modal.remove(); + * }); + * // Execute action on hide modal + * $scope.$on('modal.hidden', function() { + * // Execute action + * }); + * // Execute action on remove modal + * $scope.$on('modal.removed', function() { + * // Execute action + * }); + * }); + * ``` + */ +IonicModule +.factory('$ionicModal', [ + '$rootScope', + '$ionicBody', + '$compile', + '$timeout', + '$ionicPlatform', + '$ionicTemplateLoader', + '$q', + '$log', +function($rootScope, $ionicBody, $compile, $timeout, $ionicPlatform, $ionicTemplateLoader, $q, $log) { + + /** + * @ngdoc controller + * @name ionicModal + * @module ionic + * @description + * Instantiated by the {@link ionic.service:$ionicModal} service. + * + * Be sure to call [remove()](#remove) when you are done with each modal + * to clean it up and avoid memory leaks. + * + * Note: a modal will broadcast 'modal.shown', 'modal.hidden', and 'modal.removed' events from its originating + * scope, passing in itself as an event argument. Note: both modal.removed and modal.hidden are + * called when the modal is removed. + */ + var ModalView = ionic.views.Modal.inherit({ + /** + * @ngdoc method + * @name ionicModal#initialize + * @description Creates a new modal controller instance. + * @param {object} options An options object with the following properties: + * - `{object=}` `scope` The scope to be a child of. + * Default: creates a child of $rootScope. + * - `{string=}` `animation` The animation to show & hide with. + * Default: 'slide-in-up' + * - `{boolean=}` `focusFirstInput` Whether to autofocus the first input of + * the modal when shown. Default: false. + * - `{boolean=}` `backdropClickToClose` Whether to close the modal on clicking the backdrop. + * Default: true. + * - `{boolean=}` `hardwareBackButtonClose` Whether the modal can be closed using the hardware + * back button on Android and similar devices. Default: true. + */ + initialize: function(opts) { + ionic.views.Modal.prototype.initialize.call(this, opts); + this.animation = opts.animation || 'slide-in-up'; + }, + + /** + * @ngdoc method + * @name ionicModal#show + * @description Show this modal instance. + * @returns {promise} A promise which is resolved when the modal is finished animating in. + */ + show: function(target) { + var self = this; + + if (self.scope.$$destroyed) { + $log.error('Cannot call ' + self.viewType + '.show() after remove(). Please create a new ' + self.viewType + ' instance.'); + return; + } + + var modalEl = jqLite(self.modalEl); + + self.el.classList.remove('hide'); + $timeout(function() { + $ionicBody.addClass(self.viewType + '-open'); + }, 400); + + if (!self.el.parentElement) { + modalEl.addClass(self.animation); + $ionicBody.append(self.el); + } + + if (target && self.positionView) { + self.positionView(target, modalEl); + // set up a listener for in case the window size changes + ionic.on('resize',function() { + ionic.off('resize',null,window); + self.positionView(target,modalEl); + },window); + } + + modalEl.addClass('ng-enter active') + .removeClass('ng-leave ng-leave-active'); + + self._isShown = true; + self._deregisterBackButton = $ionicPlatform.registerBackButtonAction( + self.hardwareBackButtonClose ? angular.bind(self, self.hide) : angular.noop, + PLATFORM_BACK_BUTTON_PRIORITY_MODAL + ); + + self._isOpenPromise = $q.defer(); + + ionic.views.Modal.prototype.show.call(self); + + $timeout(function() { + modalEl.addClass('ng-enter-active'); + ionic.trigger('resize'); + self.scope.$parent && self.scope.$parent.$broadcast(self.viewType + '.shown', self); + self.el.classList.add('active'); + self.scope.$broadcast('$ionicHeader.align'); + }, 20); + + return $timeout(function() { + //After animating in, allow hide on backdrop click + self.$el.on('click', function(e) { + if (self.backdropClickToClose && e.target === self.el) { + self.hide(); + } + }); + }, 400); + }, + + /** + * @ngdoc method + * @name ionicModal#hide + * @description Hide this modal instance. + * @returns {promise} A promise which is resolved when the modal is finished animating out. + */ + hide: function() { + var self = this; + var modalEl = jqLite(self.modalEl); + + self.el.classList.remove('active'); + modalEl.addClass('ng-leave'); + + $timeout(function() { + modalEl.addClass('ng-leave-active') + .removeClass('ng-enter ng-enter-active active'); + }, 20); + + self.$el.off('click'); + self._isShown = false; + self.scope.$parent && self.scope.$parent.$broadcast(self.viewType + '.hidden', self); + self._deregisterBackButton && self._deregisterBackButton(); + + ionic.views.Modal.prototype.hide.call(self); + + // clean up event listeners + if (self.positionView) { + ionic.off('resize',null,window); + } + + return $timeout(function() { + $ionicBody.removeClass(self.viewType + '-open'); + self.el.classList.add('hide'); + }, self.hideDelay || 320); + }, + + /** + * @ngdoc method + * @name ionicModal#remove + * @description Remove this modal instance from the DOM and clean up. + * @returns {promise} A promise which is resolved when the modal is finished animating out. + */ + remove: function() { + var self = this; + self.scope.$parent && self.scope.$parent.$broadcast(self.viewType + '.removed', self); + + return self.hide().then(function() { + self.scope.$destroy(); + self.$el.remove(); + }); + }, + + /** + * @ngdoc method + * @name ionicModal#isShown + * @returns boolean Whether this modal is currently shown. + */ + isShown: function() { + return !!this._isShown; + } + }); + + var createModal = function(templateString, options) { + // Create a new scope for the modal + var scope = options.scope && options.scope.$new() || $rootScope.$new(true); + + options.viewType = options.viewType || 'modal'; + + extend(scope, { + $hasHeader: false, + $hasSubheader: false, + $hasFooter: false, + $hasSubfooter: false, + $hasTabs: false, + $hasTabsTop: false + }); + + // Compile the template + var element = $compile('' + templateString + '')(scope); + + options.$el = element; + options.el = element[0]; + options.modalEl = options.el.querySelector('.' + options.viewType); + var modal = new ModalView(options); + + modal.scope = scope; + + // If this wasn't a defined scope, we can assign the viewType to the isolated scope + // we created + if (!options.scope) { + scope[ options.viewType ] = modal; + } + + return modal; + }; + + return { + /** + * @ngdoc method + * @name $ionicModal#fromTemplate + * @param {string} templateString The template string to use as the modal's + * content. + * @param {object} options Options to be passed {@link ionic.controller:ionicModal#initialize ionicModal#initialize} method. + * @returns {object} An instance of an {@link ionic.controller:ionicModal} + * controller. + */ + fromTemplate: function(templateString, options) { + var modal = createModal(templateString, options || {}); + return modal; + }, + /** + * @ngdoc method + * @name $ionicModal#fromTemplateUrl + * @param {string} templateUrl The url to load the template from. + * @param {object} options Options to be passed {@link ionic.controller:ionicModal#initialize ionicModal#initialize} method. + * options object. + * @returns {promise} A promise that will be resolved with an instance of + * an {@link ionic.controller:ionicModal} controller. + */ + fromTemplateUrl: function(url, options, _) { + var cb; + //Deprecated: allow a callback as second parameter. Now we return a promise. + if (angular.isFunction(options)) { + cb = options; + options = _; + } + return $ionicTemplateLoader.load(url).then(function(templateString) { + var modal = createModal(templateString, options || {}); + cb && cb(modal); + return modal; + }); + } + }; +}]); + + +/** + * @ngdoc service + * @name $ionicNavBarDelegate + * @module ionic + * @description + * Delegate for controlling the {@link ionic.directive:ionNavBar} directive. + * + * @usage + * + * ```html + * + * + * + * + * + * ``` + * ```js + * function MyCtrl($scope, $ionicNavBarDelegate) { + * $scope.setNavTitle = function(title) { + * $ionicNavBarDelegate.title(title); + * } + * } + * ``` + */ +IonicModule +.service('$ionicNavBarDelegate', ionic.DelegateService([ + /** + * @ngdoc method + * @name $ionicNavBarDelegate#align + * @description Aligns the title with the buttons in a given direction. + * @param {string=} direction The direction to the align the title text towards. + * Available: 'left', 'right', 'center'. Default: 'center'. + */ + 'align', + /** + * @ngdoc method + * @name $ionicNavBarDelegate#showBackButton + * @description + * Set/get whether the {@link ionic.directive:ionNavBackButton} is shown + * (if it exists and there is a previous view that can be navigated to). + * @param {boolean=} show Whether to show the back button. + * @returns {boolean} Whether the back button is shown. + */ + 'showBackButton', + /** + * @ngdoc method + * @name $ionicNavBarDelegate#showBar + * @description + * Set/get whether the {@link ionic.directive:ionNavBar} is shown. + * @param {boolean} show Whether to show the bar. + * @returns {boolean} Whether the bar is shown. + */ + 'showBar', + /** + * @ngdoc method + * @name $ionicNavBarDelegate#title + * @description + * Set the title for the {@link ionic.directive:ionNavBar}. + * @param {string} title The new title to show. + */ + 'title', + + // DEPRECATED, as of v1.0.0-beta14 ------- + 'changeTitle', + 'setTitle', + 'getTitle', + 'back', + 'getPreviousTitle' + // END DEPRECATED ------- +])); + + +IonicModule +.service('$ionicNavViewDelegate', ionic.DelegateService([ + 'clearCache' +])); + + +var PLATFORM_BACK_BUTTON_PRIORITY_VIEW = 100; +var PLATFORM_BACK_BUTTON_PRIORITY_SIDE_MENU = 150; +var PLATFORM_BACK_BUTTON_PRIORITY_MODAL = 200; +var PLATFORM_BACK_BUTTON_PRIORITY_ACTION_SHEET = 300; +var PLATFORM_BACK_BUTTON_PRIORITY_POPUP = 400; +var PLATFORM_BACK_BUTTON_PRIORITY_LOADING = 500; + +/** + * @ngdoc service + * @name $ionicPlatform + * @module ionic + * @description + * An angular abstraction of {@link ionic.utility:ionic.Platform}. + * + * Used to detect the current platform, as well as do things like override the + * Android back button in PhoneGap/Cordova. + */ +IonicModule +.provider('$ionicPlatform', function() { + return { + $get: ['$q', '$rootScope', function($q, $rootScope) { + var self = { + + /** + * @ngdoc method + * @name $ionicPlatform#onHardwareBackButton + * @description + * Some platforms have a hardware back button, so this is one way to + * bind to it. + * @param {function} callback the callback to trigger when this event occurs + */ + onHardwareBackButton: function(cb) { + ionic.Platform.ready(function() { + document.addEventListener('backbutton', cb, false); + }); + }, + + /** + * @ngdoc method + * @name $ionicPlatform#offHardwareBackButton + * @description + * Remove an event listener for the backbutton. + * @param {function} callback The listener function that was + * originally bound. + */ + offHardwareBackButton: function(fn) { + ionic.Platform.ready(function() { + document.removeEventListener('backbutton', fn); + }); + }, + + /** + * @ngdoc method + * @name $ionicPlatform#registerBackButtonAction + * @description + * Register a hardware back button action. Only one action will execute + * when the back button is clicked, so this method decides which of + * the registered back button actions has the highest priority. + * + * For example, if an actionsheet is showing, the back button should + * close the actionsheet, but it should not also go back a page view + * or close a modal which may be open. + * + * @param {function} callback Called when the back button is pressed, + * if this listener is the highest priority. + * @param {number} priority Only the highest priority will execute. + * @param {*=} actionId The id to assign this action. Default: a + * random unique id. + * @returns {function} A function that, when called, will deregister + * this backButtonAction. + */ + $backButtonActions: {}, + registerBackButtonAction: function(fn, priority, actionId) { + + if (!self._hasBackButtonHandler) { + // add a back button listener if one hasn't been setup yet + self.$backButtonActions = {}; + self.onHardwareBackButton(self.hardwareBackButtonClick); + self._hasBackButtonHandler = true; + } + + var action = { + id: (actionId ? actionId : ionic.Utils.nextUid()), + priority: (priority ? priority : 0), + fn: fn + }; + self.$backButtonActions[action.id] = action; + + // return a function to de-register this back button action + return function() { + delete self.$backButtonActions[action.id]; + }; + }, + + /** + * @private + */ + hardwareBackButtonClick: function(e) { + // loop through all the registered back button actions + // and only run the last one of the highest priority + var priorityAction, actionId; + for (actionId in self.$backButtonActions) { + if (!priorityAction || self.$backButtonActions[actionId].priority >= priorityAction.priority) { + priorityAction = self.$backButtonActions[actionId]; + } + } + if (priorityAction) { + priorityAction.fn(e); + return priorityAction; + } + }, + + is: function(type) { + return ionic.Platform.is(type); + }, + + /** + * @ngdoc method + * @name $ionicPlatform#on + * @description + * Add Cordova event listeners, such as `pause`, `resume`, `volumedownbutton`, `batterylow`, + * `offline`, etc. More information about available event types can be found in + * [Cordova's event documentation](https://cordova.apache.org/docs/en/edge/cordova_events_events.md.html#Events). + * @param {string} type Cordova [event type](https://cordova.apache.org/docs/en/edge/cordova_events_events.md.html#Events). + * @param {function} callback Called when the Cordova event is fired. + * @returns {function} Returns a deregistration function to remove the event listener. + */ + on: function(type, cb) { + ionic.Platform.ready(function() { + document.addEventListener(type, cb, false); + }); + return function() { + ionic.Platform.ready(function() { + document.removeEventListener(type, cb); + }); + }; + }, + + /** + * @ngdoc method + * @name $ionicPlatform#ready + * @description + * Trigger a callback once the device is ready, + * or immediately if the device is already ready. + * @param {function=} callback The function to call. + * @returns {promise} A promise which is resolved when the device is ready. + */ + ready: function(cb) { + var q = $q.defer(); + + ionic.Platform.ready(function() { + q.resolve(); + cb && cb(); + }); + + return q.promise; + } + }; + return self; + }] + }; + +}); + +/** + * @ngdoc service + * @name $ionicPopover + * @module ionic + * @description + * + * Related: {@link ionic.controller:ionicPopover ionicPopover controller}. + * + * The Popover is a view that floats above an app’s content. Popovers provide an + * easy way to present or gather information from the user and are + * commonly used in the following situations: + * + * - Show more info about the current view + * - Select a commonly used tool or configuration + * - Present a list of actions to perform inside one of your views + * + * Put the content of the popover inside of an `` element. + * + * @usage + * ```html + *

+ * + *

+ * + * + * ``` + * ```js + * angular.module('testApp', ['ionic']) + * .controller('MyController', function($scope, $ionicPopover) { + * + * // .fromTemplate() method + * var template = '

My Popover Title

Hello!
'; + * + * $scope.popover = $ionicPopover.fromTemplate(template, { + * scope: $scope, + * }); + * + * // .fromTemplateUrl() method + * $ionicPopover.fromTemplateUrl('my-popover.html', { + * scope: $scope, + * }).then(function(popover) { + * $scope.popover = popover; + * }); + * + * + * $scope.openPopover = function($event) { + * $scope.popover.show($event); + * }; + * $scope.closePopover = function() { + * $scope.popover.hide(); + * }; + * //Cleanup the popover when we're done with it! + * $scope.$on('$destroy', function() { + * $scope.popover.remove(); + * }); + * // Execute action on hide popover + * $scope.$on('popover.hidden', function() { + * // Execute action + * }); + * // Execute action on remove popover + * $scope.$on('popover.removed', function() { + * // Execute action + * }); + * }); + * ``` + */ + + +IonicModule +.factory('$ionicPopover', ['$ionicModal', '$ionicPosition', '$document', '$window', +function($ionicModal, $ionicPosition, $document, $window) { + + var POPOVER_BODY_PADDING = 6; + + var POPOVER_OPTIONS = { + viewType: 'popover', + hideDelay: 1, + animation: 'none', + positionView: positionView + }; + + function positionView(target, popoverEle) { + var targetEle = angular.element(target.target || target); + var buttonOffset = $ionicPosition.offset(targetEle); + var popoverWidth = popoverEle.prop('offsetWidth'); + var popoverHeight = popoverEle.prop('offsetHeight'); + var bodyWidth = $document[0].body.clientWidth; + // clientHeight doesn't work on all platforms for body + var bodyHeight = $window.innerHeight; + + var popoverCSS = { + left: buttonOffset.left + buttonOffset.width / 2 - popoverWidth / 2 + }; + var arrowEle = jqLite(popoverEle[0].querySelector('.popover-arrow')); + + if (popoverCSS.left < POPOVER_BODY_PADDING) { + popoverCSS.left = POPOVER_BODY_PADDING; + } else if (popoverCSS.left + popoverWidth + POPOVER_BODY_PADDING > bodyWidth) { + popoverCSS.left = bodyWidth - popoverWidth - POPOVER_BODY_PADDING; + } + + // If the popover when popped down stretches past bottom of screen, + // make it pop up + if (buttonOffset.top + buttonOffset.height + popoverHeight > bodyHeight) { + popoverCSS.top = buttonOffset.top - popoverHeight; + popoverEle.addClass('popover-bottom'); + } else { + popoverCSS.top = buttonOffset.top + buttonOffset.height; + popoverEle.removeClass('popover-bottom'); + } + + arrowEle.css({ + left: buttonOffset.left + buttonOffset.width / 2 - + arrowEle.prop('offsetWidth') / 2 - popoverCSS.left + 'px' + }); + + popoverEle.css({ + top: popoverCSS.top + 'px', + left: popoverCSS.left + 'px', + marginLeft: '0', + opacity: '1' + }); + + } + + /** + * @ngdoc controller + * @name ionicPopover + * @module ionic + * @description + * Instantiated by the {@link ionic.service:$ionicPopover} service. + * + * Be sure to call [remove()](#remove) when you are done with each popover + * to clean it up and avoid memory leaks. + * + * Note: a popover will broadcast 'popover.shown', 'popover.hidden', and 'popover.removed' events from its originating + * scope, passing in itself as an event argument. Both the popover.removed and popover.hidden events are + * called when the popover is removed. + */ + + /** + * @ngdoc method + * @name ionicPopover#initialize + * @description Creates a new popover controller instance. + * @param {object} options An options object with the following properties: + * - `{object=}` `scope` The scope to be a child of. + * Default: creates a child of $rootScope. + * - `{boolean=}` `focusFirstInput` Whether to autofocus the first input of + * the popover when shown. Default: false. + * - `{boolean=}` `backdropClickToClose` Whether to close the popover on clicking the backdrop. + * Default: true. + * - `{boolean=}` `hardwareBackButtonClose` Whether the popover can be closed using the hardware + * back button on Android and similar devices. Default: true. + */ + + /** + * @ngdoc method + * @name ionicPopover#show + * @description Show this popover instance. + * @param {$event} $event The $event or target element which the popover should align + * itself next to. + * @returns {promise} A promise which is resolved when the popover is finished animating in. + */ + + /** + * @ngdoc method + * @name ionicPopover#hide + * @description Hide this popover instance. + * @returns {promise} A promise which is resolved when the popover is finished animating out. + */ + + /** + * @ngdoc method + * @name ionicPopover#remove + * @description Remove this popover instance from the DOM and clean up. + * @returns {promise} A promise which is resolved when the popover is finished animating out. + */ + + /** + * @ngdoc method + * @name ionicPopover#isShown + * @returns boolean Whether this popover is currently shown. + */ + + return { + /** + * @ngdoc method + * @name $ionicPopover#fromTemplate + * @param {string} templateString The template string to use as the popovers's + * content. + * @param {object} options Options to be passed to the initialize method. + * @returns {object} An instance of an {@link ionic.controller:ionicPopover} + * controller (ionicPopover is built on top of $ionicPopover). + */ + fromTemplate: function(templateString, options) { + return $ionicModal.fromTemplate(templateString, ionic.Utils.extend(POPOVER_OPTIONS, options || {})); + }, + /** + * @ngdoc method + * @name $ionicPopover#fromTemplateUrl + * @param {string} templateUrl The url to load the template from. + * @param {object} options Options to be passed to the initialize method. + * @returns {promise} A promise that will be resolved with an instance of + * an {@link ionic.controller:ionicPopover} controller (ionicPopover is built on top of $ionicPopover). + */ + fromTemplateUrl: function(url, options) { + return $ionicModal.fromTemplateUrl(url, ionic.Utils.extend(POPOVER_OPTIONS, options || {})); + } + }; + +}]); + + +var POPUP_TPL = + ''; + +/** + * @ngdoc service + * @name $ionicPopup + * @module ionic + * @restrict E + * @codepen zkmhJ + * @description + * + * The Ionic Popup service allows programmatically creating and showing popup + * windows that require the user to respond in order to continue. + * + * The popup system 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. + * + * An input can be given an `autofocus` attribute so it automatically receives focus when + * the popup first shows. However, depending on certain use-cases this can cause issues with + * the tap/click system, which is why Ionic prefers using the `autofocus` attribute as + * an opt-in feature and not the default. + * + * @usage + * A few basic examples, see below for details about all of the options available. + * + * ```js + *angular.module('mySuperApp', ['ionic']) + *.controller('PopupCtrl',function($scope, $ionicPopup, $timeout) { + * + * // Triggered on a button click, or some other target + * $scope.showPopup = function() { + * $scope.data = {} + * + * // An elaborate, custom popup + * var myPopup = $ionicPopup.show({ + * template: '', + * title: 'Enter Wi-Fi Password', + * subTitle: 'Please use normal things', + * scope: $scope, + * buttons: [ + * { text: 'Cancel' }, + * { + * text: 'Save', + * type: 'button-positive', + * onTap: function(e) { + * if (!$scope.data.wifi) { + * //don't allow the user to close unless he enters wifi password + * e.preventDefault(); + * } else { + * return $scope.data.wifi; + * } + * } + * } + * ] + * }); + * myPopup.then(function(res) { + * console.log('Tapped!', res); + * }); + * $timeout(function() { + * myPopup.close(); //close the popup after 3 seconds for some reason + * }, 3000); + * }; + * // A confirm dialog + * $scope.showConfirm = function() { + * var confirmPopup = $ionicPopup.confirm({ + * title: 'Consume Ice Cream', + * template: 'Are you sure you want to eat this ice cream?' + * }); + * confirmPopup.then(function(res) { + * if(res) { + * console.log('You are sure'); + * } else { + * console.log('You are not sure'); + * } + * }); + * }; + * + * // An alert dialog + * $scope.showAlert = function() { + * var alertPopup = $ionicPopup.alert({ + * title: 'Don\'t eat that!', + * template: 'It might taste good' + * }); + * alertPopup.then(function(res) { + * console.log('Thank you for not eating my delicious ice cream cone'); + * }); + * }; + *}); + *``` + */ + +IonicModule +.factory('$ionicPopup', [ + '$ionicTemplateLoader', + '$ionicBackdrop', + '$q', + '$timeout', + '$rootScope', + '$ionicBody', + '$compile', + '$ionicPlatform', +function($ionicTemplateLoader, $ionicBackdrop, $q, $timeout, $rootScope, $ionicBody, $compile, $ionicPlatform) { + //TODO allow this to be configured + var config = { + stackPushDelay: 75 + }; + var popupStack = []; + var $ionicPopup = { + /** + * @ngdoc method + * @description + * Show a complex popup. This is the master show function for all popups. + * + * A complex popup has a `buttons` array, with each button having a `text` and `type` + * field, in addition to an `onTap` function. The `onTap` function, called when + * the corresponding button on the popup is tapped, will by default close the popup + * and resolve the popup promise with its return value. If you wish to prevent the + * default and keep the popup open on button tap, call `event.preventDefault()` on the + * passed in tap event. Details below. + * + * @name $ionicPopup#show + * @param {object} options The options for the new popup, of the form: + * + * ``` + * { + * title: '', // String. The title of the popup. + * cssClass: '', // String, The custom CSS class name + * subTitle: '', // String (optional). The sub-title of the popup. + * template: '', // String (optional). The html template to place in the popup body. + * templateUrl: '', // String (optional). The URL of an html template to place in the popup body. + * scope: null, // Scope (optional). A scope to link to the popup content. + * buttons: [{ // Array[Object] (optional). Buttons to place in the popup footer. + * text: 'Cancel', + * type: 'button-default', + * onTap: function(e) { + * // e.preventDefault() will stop the popup from closing when tapped. + * e.preventDefault(); + * } + * }, { + * text: 'OK', + * type: 'button-positive', + * onTap: function(e) { + * // Returning a value will cause the promise to resolve with the given value. + * return scope.data.response; + * } + * }] + * } + * ``` + * + * @returns {object} A promise which is resolved when the popup is closed. Has an additional + * `close` function, which can be used to programmatically close the popup. + */ + show: showPopup, + + /** + * @ngdoc method + * @name $ionicPopup#alert + * @description Show a simple alert popup with a message and one button that the user can + * tap to close the popup. + * + * @param {object} options The options for showing the alert, of the form: + * + * ``` + * { + * title: '', // String. The title of the popup. + * cssClass: '', // String, The custom CSS class name + * subTitle: '', // String (optional). The sub-title of the popup. + * template: '', // String (optional). The html template to place in the popup body. + * templateUrl: '', // String (optional). The URL of an html template to place in the popup body. + * okText: '', // String (default: 'OK'). The text of the OK button. + * okType: '', // String (default: 'button-positive'). The type of the OK button. + * } + * ``` + * + * @returns {object} A promise which is resolved when the popup is closed. Has one additional + * function `close`, which can be called with any value to programmatically close the popup + * with the given value. + */ + alert: showAlert, + + /** + * @ngdoc method + * @name $ionicPopup#confirm + * @description + * Show a simple confirm popup with a 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} options The options for showing the confirm popup, of the form: + * + * ``` + * { + * title: '', // String. The title of the popup. + * cssClass: '', // String, The custom CSS class name + * subTitle: '', // String (optional). The sub-title of the popup. + * template: '', // String (optional). The html template to place in the popup body. + * templateUrl: '', // String (optional). The URL of an html template to place in the popup body. + * cancelText: '', // String (default: 'Cancel'). The text of the Cancel button. + * cancelType: '', // String (default: 'button-default'). The type of the Cancel button. + * okText: '', // String (default: 'OK'). The text of the OK button. + * okType: '', // String (default: 'button-positive'). The type of the OK button. + * } + * ``` + * + * @returns {object} A promise which is resolved when the popup is closed. Has one additional + * function `close`, which can be called with any value to programmatically close the popup + * with the given value. + */ + confirm: showConfirm, + + /** + * @ngdoc method + * @name $ionicPopup#prompt + * @description Show a simple prompt popup, which has an input, OK button, and Cancel button. + * Resolves the promise with the value of the input if the user presses OK, and with undefined + * if the user presses Cancel. + * + * ```javascript + * $ionicPopup.prompt({ + * title: 'Password Check', + * template: 'Enter your secret password', + * inputType: 'password', + * inputPlaceholder: 'Your password' + * }).then(function(res) { + * console.log('Your password is', res); + * }); + * ``` + * @param {object} options The options for showing the prompt popup, of the form: + * + * ``` + * { + * title: '', // String. The title of the popup. + * cssClass: '', // String, The custom CSS class name + * subTitle: '', // String (optional). The sub-title of the popup. + * template: '', // String (optional). The html template to place in the popup body. + * templateUrl: '', // String (optional). The URL of an html template to place in the popup body. + * inputType: // String (default: 'text'). The type of input to use + * inputPlaceholder: // String (default: ''). A placeholder to use for the input. + * cancelText: // String (default: 'Cancel'. The text of the Cancel button. + * cancelType: // String (default: 'button-default'). The type of the Cancel button. + * okText: // String (default: 'OK'). The text of the OK button. + * okType: // String (default: 'button-positive'). The type of the OK button. + * } + * ``` + * + * @returns {object} A promise which is resolved when the popup is closed. Has one additional + * function `close`, which can be called with any value to programmatically close the popup + * with the given value. + */ + prompt: showPrompt, + /** + * @private for testing + */ + _createPopup: createPopup, + _popupStack: popupStack + }; + + return $ionicPopup; + + function createPopup(options) { + options = extend({ + scope: null, + title: '', + buttons: [] + }, options || {}); + + var popupPromise = $ionicTemplateLoader.compile({ + template: POPUP_TPL, + scope: options.scope && options.scope.$new(), + appendTo: $ionicBody.get() + }); + var contentPromise = options.templateUrl ? + $ionicTemplateLoader.load(options.templateUrl) : + $q.when(options.template || options.content || ''); + + return $q.all([popupPromise, contentPromise]) + .then(function(results) { + var self = results[0]; + var content = results[1]; + var responseDeferred = $q.defer(); + + self.responseDeferred = responseDeferred; + + //Can't ng-bind-html for popup-body because it can be insecure html + //(eg an input in case of prompt) + var body = jqLite(self.element[0].querySelector('.popup-body')); + if (content) { + body.html(content); + $compile(body.contents())(self.scope); + } else { + body.remove(); + } + + extend(self.scope, { + title: options.title, + buttons: options.buttons, + subTitle: options.subTitle, + cssClass: options.cssClass, + $buttonTapped: function(button, event) { + var result = (button.onTap || angular.noop)(event); + event = event.originalEvent || event; //jquery events + + if (!event.defaultPrevented) { + responseDeferred.resolve(result); + } + } + }); + + self.show = function() { + if (self.isShown) return; + + self.isShown = true; + ionic.requestAnimationFrame(function() { + //if hidden while waiting for raf, don't show + if (!self.isShown) return; + + self.element.removeClass('popup-hidden'); + self.element.addClass('popup-showing active'); + focusInput(self.element); + }); + }; + self.hide = function(callback) { + callback = callback || angular.noop; + if (!self.isShown) return callback(); + + self.isShown = false; + self.element.removeClass('active'); + self.element.addClass('popup-hidden'); + $timeout(callback, 250); + }; + self.remove = function() { + if (self.removed) return; + + self.hide(function() { + self.element.remove(); + self.scope.$destroy(); + }); + + self.removed = true; + }; + + return self; + }); + } + + function onHardwareBackButton(e) { + popupStack[0] && popupStack[0].responseDeferred.resolve(); + } + + function showPopup(options) { + var popupPromise = $ionicPopup._createPopup(options); + var previousPopup = popupStack[0]; + + if (previousPopup) { + previousPopup.hide(); + } + + var resultPromise = $timeout(angular.noop, previousPopup ? config.stackPushDelay : 0) + .then(function() { return popupPromise; }) + .then(function(popup) { + if (!previousPopup) { + //Add popup-open & backdrop if this is first popup + $ionicBody.addClass('popup-open'); + $ionicBackdrop.retain(); + //only show the backdrop on the first popup + $ionicPopup._backButtonActionDone = $ionicPlatform.registerBackButtonAction( + onHardwareBackButton, + PLATFORM_BACK_BUTTON_PRIORITY_POPUP + ); + } + popupStack.unshift(popup); + popup.show(); + + //DEPRECATED: notify the promise with an object with a close method + popup.responseDeferred.notify({ + close: resultPromise.close + }); + + return popup.responseDeferred.promise.then(function(result) { + var index = popupStack.indexOf(popup); + if (index !== -1) { + popupStack.splice(index, 1); + } + popup.remove(); + + var previousPopup = popupStack[0]; + if (previousPopup) { + previousPopup.show(); + } else { + //Remove popup-open & backdrop if this is last popup + $timeout(function() { + // wait to remove this due to a 300ms delay native + // click which would trigging whatever was underneath this + $ionicBody.removeClass('popup-open'); + }, 400); + $timeout(function() { + $ionicBackdrop.release(); + }, config.stackPushDelay || 0); + ($ionicPopup._backButtonActionDone || angular.noop)(); + } + return result; + }); + }); + + function close(result) { + popupPromise.then(function(popup) { + if (!popup.removed) { + popup.responseDeferred.resolve(result); + } + }); + } + resultPromise.close = close; + + return resultPromise; + } + + function focusInput(element) { + var focusOn = element[0].querySelector('[autofocus]'); + if (focusOn) { + focusOn.focus(); + } + } + + function showAlert(opts) { + return showPopup(extend({ + buttons: [{ + text: opts.okText || 'OK', + type: opts.okType || 'button-positive', + onTap: function(e) { + return true; + } + }] + }, opts || {})); + } + + function showConfirm(opts) { + return showPopup(extend({ + buttons: [{ + text: opts.cancelText || 'Cancel', + type: opts.cancelType || 'button-default', + onTap: function(e) { return false; } + }, { + text: opts.okText || 'OK', + type: opts.okType || 'button-positive', + onTap: function(e) { return true; } + }] + }, opts || {})); + } + + function showPrompt(opts) { + var scope = $rootScope.$new(true); + scope.data = {}; + var text = ''; + if (opts.template && /<[a-z][\s\S]*>/i.test(opts.template) === false) { + text = '' + opts.template + ''; + delete opts.template; + } + return showPopup(extend({ + template: text + '', + scope: scope, + buttons: [{ + text: opts.cancelText || 'Cancel', + type: opts.cancelType || 'button-default', + onTap: function(e) {} + }, { + text: opts.okText || 'OK', + type: opts.okType || 'button-positive', + onTap: function(e) { + return scope.data.response || ''; + } + }] + }, opts || {})); + } +}]); + +/** + * @ngdoc service + * @name $ionicPosition + * @module ionic + * @description + * A set of utility methods that can be use to retrieve position of DOM elements. + * It is meant to be used where we need to absolute-position DOM elements in + * relation to other, existing elements (this is the case for tooltips, popovers, etc.). + * + * Adapted from [AngularUI Bootstrap](https://github.com/angular-ui/bootstrap/blob/master/src/position/position.js), + * ([license](https://github.com/angular-ui/bootstrap/blob/master/LICENSE)) + */ +IonicModule +.factory('$ionicPosition', ['$document', '$window', function($document, $window) { + + function getStyle(el, cssprop) { + if (el.currentStyle) { //IE + return el.currentStyle[cssprop]; + } else if ($window.getComputedStyle) { + return $window.getComputedStyle(el)[cssprop]; + } + // finally try and get inline style + return el.style[cssprop]; + } + + /** + * Checks if a given element is statically positioned + * @param element - raw DOM element + */ + function isStaticPositioned(element) { + return (getStyle(element, 'position') || 'static') === 'static'; + } + + /** + * returns the closest, non-statically positioned parentOffset of a given element + * @param element + */ + var parentOffsetEl = function(element) { + var docDomEl = $document[0]; + var offsetParent = element.offsetParent || docDomEl; + while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent)) { + offsetParent = offsetParent.offsetParent; + } + return offsetParent || docDomEl; + }; + + return { + /** + * @ngdoc method + * @name $ionicPosition#position + * @description 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. + */ + position: function(element) { + var elBCR = this.offset(element); + var offsetParentBCR = { top: 0, left: 0 }; + var offsetParentEl = parentOffsetEl(element[0]); + if (offsetParentEl != $document[0]) { + offsetParentBCR = this.offset(angular.element(offsetParentEl)); + offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop; + offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft; + } + + var boundingClientRect = element[0].getBoundingClientRect(); + return { + width: boundingClientRect.width || element.prop('offsetWidth'), + height: boundingClientRect.height || element.prop('offsetHeight'), + top: elBCR.top - offsetParentBCR.top, + left: elBCR.left - offsetParentBCR.left + }; + }, + + /** + * @ngdoc method + * @name $ionicPosition#offset + * @description 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. + */ + offset: function(element) { + var boundingClientRect = element[0].getBoundingClientRect(); + return { + width: boundingClientRect.width || element.prop('offsetWidth'), + height: boundingClientRect.height || element.prop('offsetHeight'), + top: boundingClientRect.top + ($window.pageYOffset || $document[0].documentElement.scrollTop), + left: boundingClientRect.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft) + }; + } + + }; +}]); + + +/** + * @ngdoc service + * @name $ionicScrollDelegate + * @module ionic + * @description + * Delegate for controlling scrollViews (created by + * {@link ionic.directive:ionContent} and + * {@link ionic.directive:ionScroll} directives). + * + * Methods called directly on the $ionicScrollDelegate service will control all scroll + * views. Use the {@link ionic.service:$ionicScrollDelegate#$getByHandle $getByHandle} + * method to control specific scrollViews. + * + * @usage + * + * ```html + * + * + * + * + * + * ``` + * ```js + * function MainCtrl($scope, $ionicScrollDelegate) { + * $scope.scrollTop = function() { + * $ionicScrollDelegate.scrollTop(); + * }; + * } + * ``` + * + * Example of advanced usage, with two scroll areas using `delegate-handle` + * for fine control. + * + * ```html + * + * + * + * + * + * + * + * + * ``` + * ```js + * function MainCtrl($scope, $ionicScrollDelegate) { + * $scope.scrollMainToTop = function() { + * $ionicScrollDelegate.$getByHandle('mainScroll').scrollTop(); + * }; + * $scope.scrollSmallToTop = function() { + * $ionicScrollDelegate.$getByHandle('small').scrollTop(); + * }; + * } + * ``` + */ +IonicModule +.service('$ionicScrollDelegate', ionic.DelegateService([ + /** + * @ngdoc method + * @name $ionicScrollDelegate#resize + * @description Tell the scrollView to recalculate the size of its container. + */ + 'resize', + /** + * @ngdoc method + * @name $ionicScrollDelegate#scrollTop + * @param {boolean=} shouldAnimate Whether the scroll should animate. + */ + 'scrollTop', + /** + * @ngdoc method + * @name $ionicScrollDelegate#scrollBottom + * @param {boolean=} shouldAnimate Whether the scroll should animate. + */ + 'scrollBottom', + /** + * @ngdoc method + * @name $ionicScrollDelegate#scrollTo + * @param {number} left The x-value to scroll to. + * @param {number} top The y-value to scroll to. + * @param {boolean=} shouldAnimate Whether the scroll should animate. + */ + 'scrollTo', + /** + * @ngdoc method + * @name $ionicScrollDelegate#scrollBy + * @param {number} left The x-offset to scroll by. + * @param {number} top The y-offset to scroll by. + * @param {boolean=} shouldAnimate Whether the scroll should animate. + */ + 'scrollBy', + /** + * @ngdoc method + * @name $ionicScrollDelegate#zoomTo + * @param {number} level Level to zoom to. + * @param {boolean=} animate Whether to animate the zoom. + * @param {number=} originLeft Zoom in at given left coordinate. + * @param {number=} originTop Zoom in at given top coordinate. + */ + 'zoomTo', + /** + * @ngdoc method + * @name $ionicScrollDelegate#zoomBy + * @param {number} factor The factor to zoom by. + * @param {boolean=} animate Whether to animate the zoom. + * @param {number=} originLeft Zoom in at given left coordinate. + * @param {number=} originTop Zoom in at given top coordinate. + */ + 'zoomBy', + /** + * @ngdoc method + * @name $ionicScrollDelegate#getScrollPosition + * @returns {object} The scroll position of this view, with the following properties: + * - `{number}` `left` The distance the user has scrolled from the left (starts at 0). + * - `{number}` `top` The distance the user has scrolled from the top (starts at 0). + */ + 'getScrollPosition', + /** + * @ngdoc method + * @name $ionicScrollDelegate#anchorScroll + * @description Tell the scrollView to scroll to the element with an id + * matching window.location.hash. + * + * If no matching element is found, it will scroll to top. + * + * @param {boolean=} shouldAnimate Whether the scroll should animate. + */ + 'anchorScroll', + /** + * @ngdoc method + * @name $ionicScrollDelegate#getScrollView + * @returns {object} The scrollView associated with this delegate. + */ + 'getScrollView', + /** + * @ngdoc method + * @name $ionicScrollDelegate#$getByHandle + * @param {string} handle + * @returns `delegateInstance` A delegate instance that controls only the + * scrollViews with `delegate-handle` matching the given handle. + * + * Example: `$ionicScrollDelegate.$getByHandle('my-handle').scrollTop();` + */ +])); + + +/** + * @ngdoc service + * @name $ionicSideMenuDelegate + * @module ionic + * + * @description + * Delegate for controlling the {@link ionic.directive:ionSideMenus} directive. + * + * Methods called directly on the $ionicSideMenuDelegate service will control all side + * menus. Use the {@link ionic.service:$ionicSideMenuDelegate#$getByHandle $getByHandle} + * method to control specific ionSideMenus instances. + * + * @usage + * + * ```html + * + * + * + * Content! + * + * + * + * Left Menu! + * + * + * + * ``` + * ```js + * function MainCtrl($scope, $ionicSideMenuDelegate) { + * $scope.toggleLeftSideMenu = function() { + * $ionicSideMenuDelegate.toggleLeft(); + * }; + * } + * ``` + */ +IonicModule +.service('$ionicSideMenuDelegate', ionic.DelegateService([ + /** + * @ngdoc method + * @name $ionicSideMenuDelegate#toggleLeft + * @description Toggle the left side menu (if it exists). + * @param {boolean=} isOpen Whether to open or close the menu. + * Default: Toggles the menu. + */ + 'toggleLeft', + /** + * @ngdoc method + * @name $ionicSideMenuDelegate#toggleRight + * @description Toggle the right side menu (if it exists). + * @param {boolean=} isOpen Whether to open or close the menu. + * Default: Toggles the menu. + */ + 'toggleRight', + /** + * @ngdoc method + * @name $ionicSideMenuDelegate#getOpenRatio + * @description Gets the ratio of open amount over menu width. For example, a + * menu of width 100 that is opened by 50 pixels is 50% opened, and would return + * a ratio of 0.5. + * + * @returns {float} 0 if nothing is open, between 0 and 1 if left menu is + * opened/opening, and between 0 and -1 if right menu is opened/opening. + */ + 'getOpenRatio', + /** + * @ngdoc method + * @name $ionicSideMenuDelegate#isOpen + * @returns {boolean} Whether either the left or right menu is currently opened. + */ + 'isOpen', + /** + * @ngdoc method + * @name $ionicSideMenuDelegate#isOpenLeft + * @returns {boolean} Whether the left menu is currently opened. + */ + 'isOpenLeft', + /** + * @ngdoc method + * @name $ionicSideMenuDelegate#isOpenRight + * @returns {boolean} Whether the right menu is currently opened. + */ + 'isOpenRight', + /** + * @ngdoc method + * @name $ionicSideMenuDelegate#canDragContent + * @param {boolean=} canDrag Set whether the content can or cannot be dragged to open + * side menus. + * @returns {boolean} Whether the content can be dragged to open side menus. + */ + 'canDragContent', + /** + * @ngdoc method + * @name $ionicSideMenuDelegate#edgeDragThreshold + * @param {boolean|number=} value Set whether the content drag can only start if it is below a certain threshold distance from the edge of the screen. Accepts three different values: + * - If a non-zero number is given, that many pixels is used as the maximum allowed distance from the edge that starts dragging the side menu. + * - If true is given, the default number of pixels (25) is used as the maximum allowed distance. + * - If false or 0 is given, the edge drag threshold is disabled, and dragging from anywhere on the content is allowed. + * @returns {boolean} Whether the drag can start only from within the edge of screen threshold. + */ + 'edgeDragThreshold', + /** + * @ngdoc method + * @name $ionicSideMenuDelegate#$getByHandle + * @param {string} handle + * @returns `delegateInstance` A delegate instance that controls only the + * {@link ionic.directive:ionSideMenus} directives with `delegate-handle` matching + * the given handle. + * + * Example: `$ionicSideMenuDelegate.$getByHandle('my-handle').toggleLeft();` + */ +])); + + +/** + * @ngdoc service + * @name $ionicSlideBoxDelegate + * @module ionic + * @description + * Delegate that controls the {@link ionic.directive:ionSlideBox} directive. + * + * Methods called directly on the $ionicSlideBoxDelegate service will control all slide boxes. Use the {@link ionic.service:$ionicSlideBoxDelegate#$getByHandle $getByHandle} + * method to control specific slide box instances. + * + * @usage + * + * ```html + * + * + * + *
+ * + *
+ *
+ * + *
+ * Slide 2! + *
+ *
+ *
+ * + * ``` + * ```js + * function MyCtrl($scope, $ionicSlideBoxDelegate) { + * $scope.nextSlide = function() { + * $ionicSlideBoxDelegate.next(); + * } + * } + * ``` + */ +IonicModule +.service('$ionicSlideBoxDelegate', ionic.DelegateService([ + /** + * @ngdoc method + * @name $ionicSlideBoxDelegate#update + * @description + * Update the slidebox (for example if using Angular with ng-repeat, + * resize it for the elements inside). + */ + 'update', + /** + * @ngdoc method + * @name $ionicSlideBoxDelegate#slide + * @param {number} to The index to slide to. + * @param {number=} speed The number of milliseconds for the change to take. + */ + 'slide', + 'select', + /** + * @ngdoc method + * @name $ionicSlideBoxDelegate#enableSlide + * @param {boolean=} shouldEnable Whether to enable sliding the slidebox. + * @returns {boolean} Whether sliding is enabled. + */ + 'enableSlide', + /** + * @ngdoc method + * @name $ionicSlideBoxDelegate#previous + * @description Go to the previous slide. Wraps around if at the beginning. + */ + 'previous', + /** + * @ngdoc method + * @name $ionicSlideBoxDelegate#next + * @description Go to the next slide. Wraps around if at the end. + */ + 'next', + /** + * @ngdoc method + * @name $ionicSlideBoxDelegate#stop + * @description Stop sliding. The slideBox will not move again until + * explicitly told to do so. + */ + 'stop', + 'autoPlay', + /** + * @ngdoc method + * @name $ionicSlideBoxDelegate#start + * @description Start sliding again if the slideBox was stopped. + */ + 'start', + /** + * @ngdoc method + * @name $ionicSlideBoxDelegate#currentIndex + * @returns number The index of the current slide. + */ + 'currentIndex', + 'selected', + /** + * @ngdoc method + * @name $ionicSlideBoxDelegate#slidesCount + * @returns number The number of slides there are currently. + */ + 'slidesCount', + 'count', + 'loop', + /** + * @ngdoc method + * @name $ionicSlideBoxDelegate#$getByHandle + * @param {string} handle + * @returns `delegateInstance` A delegate instance that controls only the + * {@link ionic.directive:ionSlideBox} directives with `delegate-handle` matching + * the given handle. + * + * Example: `$ionicSlideBoxDelegate.$getByHandle('my-handle').stop();` + */ +])); + + +/** + * @ngdoc service + * @name $ionicTabsDelegate + * @module ionic + * + * @description + * Delegate for controlling the {@link ionic.directive:ionTabs} directive. + * + * Methods called directly on the $ionicTabsDelegate service will control all ionTabs + * directives. Use the {@link ionic.service:$ionicTabsDelegate#$getByHandle $getByHandle} + * method to control specific ionTabs instances. + * + * @usage + * + * ```html + * + * + * + * + * Hello tab 1! + * + * + * Hello tab 2! + * + * + * + * ``` + * ```js + * function MyCtrl($scope, $ionicTabsDelegate) { + * $scope.selectTabWithIndex = function(index) { + * $ionicTabsDelegate.select(index); + * } + * } + * ``` + */ +IonicModule +.service('$ionicTabsDelegate', ionic.DelegateService([ + /** + * @ngdoc method + * @name $ionicTabsDelegate#select + * @description Select the tab matching the given index. + * + * @param {number} index Index of the tab to select. + */ + 'select', + /** + * @ngdoc method + * @name $ionicTabsDelegate#selectedIndex + * @returns `number` The index of the selected tab, or -1. + */ + 'selectedIndex' + /** + * @ngdoc method + * @name $ionicTabsDelegate#$getByHandle + * @param {string} handle + * @returns `delegateInstance` A delegate instance that controls only the + * {@link ionic.directive:ionTabs} directives with `delegate-handle` matching + * the given handle. + * + * Example: `$ionicTabsDelegate.$getByHandle('my-handle').select(0);` + */ +])); + + +// closure to keep things neat +(function() { + var templatesToCache = []; + +/** + * @ngdoc service + * @name $ionicTemplateCache + * @module ionic + * @description A service that preemptively caches template files to eliminate transition flicker and boost performance. + * @usage + * State templates are cached automatically, but you can optionally cache other templates. + * + * ```js + * $ionicTemplateCache('myNgIncludeTemplate.html'); + * ``` + * + * Optionally disable all preemptive caching with the `$ionicConfigProvider` or individual states by setting `prefetchTemplate` + * in the `$state` definition + * + * ```js + * angular.module('myApp', ['ionic']) + * .config(function($stateProvider, $ionicConfigProvider) { + * + * // disable preemptive template caching globally + * $ionicConfigProvider.templates.prefetch(false); + * + * // disable individual states + * $stateProvider + * .state('tabs', { + * url: "/tab", + * abstract: true, + * prefetchTemplate: false, + * templateUrl: "tabs-templates/tabs.html" + * }) + * .state('tabs.home', { + * url: "/home", + * views: { + * 'home-tab': { + * prefetchTemplate: false, + * templateUrl: "tabs-templates/home.html", + * controller: 'HomeTabCtrl' + * } + * } + * }); + * }); + * ``` + */ +IonicModule +.factory('$ionicTemplateCache', [ +'$http', +'$templateCache', +'$timeout', +function($http, $templateCache, $timeout) { + var toCache = templatesToCache, + hasRun; + + function $ionicTemplateCache(templates) { + if (typeof templates === 'undefined') { + return run(); + } + if (isString(templates)) { + templates = [templates]; + } + forEach(templates, function(template) { + toCache.push(template); + }); + if (hasRun) { + run(); + } + } + + // run through methods - internal method + function run() { + $ionicTemplateCache._runCount++; + + hasRun = true; + // ignore if race condition already zeroed out array + if (toCache.length === 0) return; + + var i = 0; + while (i < 4 && (template = toCache.pop())) { + // note that inline templates are ignored by this request + if (isString(template)) $http.get(template, { cache: $templateCache }); + i++; + } + // only preload 3 templates a second + if (toCache.length) { + $timeout(run, 1000); + } + } + + // exposing for testing + $ionicTemplateCache._runCount = 0; + // default method + return $ionicTemplateCache; +}]) + +// Intercepts the $stateprovider.state() command to look for templateUrls that can be cached +.config([ +'$stateProvider', +'$ionicConfigProvider', +function($stateProvider, $ionicConfigProvider) { + var stateProviderState = $stateProvider.state; + $stateProvider.state = function(stateName, definition) { + // don't even bother if it's disabled. note, another config may run after this, so it's not a catch-all + if (typeof definition === 'object') { + var enabled = definition.prefetchTemplate !== false && templatesToCache.length < $ionicConfigProvider.templates.maxPrefetch(); + if (enabled && isString(definition.templateUrl)) templatesToCache.push(definition.templateUrl); + if (angular.isObject(definition.views)) { + for (var key in definition.views) { + enabled = definition.views[key].prefetchTemplate !== false && templatesToCache.length < $ionicConfigProvider.templates.maxPrefetch(); + if (enabled && isString(definition.views[key].templateUrl)) templatesToCache.push(definition.views[key].templateUrl); + } + } + } + return stateProviderState.call($stateProvider, stateName, definition); + }; +}]) + +// process the templateUrls collected by the $stateProvider, adding them to the cache +.run(['$ionicTemplateCache', function($ionicTemplateCache) { + $ionicTemplateCache(); +}]); + +})(); + +IonicModule +.factory('$ionicTemplateLoader', [ + '$compile', + '$controller', + '$http', + '$q', + '$rootScope', + '$templateCache', +function($compile, $controller, $http, $q, $rootScope, $templateCache) { + + return { + load: fetchTemplate, + compile: loadAndCompile + }; + + function fetchTemplate(url) { + return $http.get(url, {cache: $templateCache}) + .then(function(response) { + return response.data && response.data.trim(); + }); + } + + function loadAndCompile(options) { + options = extend({ + template: '', + templateUrl: '', + scope: null, + controller: null, + locals: {}, + appendTo: null + }, options || {}); + + var templatePromise = options.templateUrl ? + this.load(options.templateUrl) : + $q.when(options.template); + + return templatePromise.then(function(template) { + var controller; + var scope = options.scope || $rootScope.$new(); + + //Incase template doesn't have just one root element, do this + var element = jqLite('
').html(template).contents(); + + if (options.controller) { + controller = $controller( + options.controller, + extend(options.locals, { + $scope: scope + }) + ); + element.children().data('$ngControllerController', controller); + } + if (options.appendTo) { + jqLite(options.appendTo).append(element); + } + + $compile(element)(scope); + + return { + element: element, + scope: scope + }; + }); + } + +}]); + +/** + * @private + * DEPRECATED, as of v1.0.0-beta14 ------- + */ +IonicModule +.factory('$ionicViewService', ['$ionicHistory', '$log', function($ionicHistory, $log) { + + function warn(oldMethod, newMethod) { + $log.warn('$ionicViewService' + oldMethod + ' is deprecated, please use $ionicHistory' + newMethod + ' instead: http://ionicframework.com/docs/nightly/api/service/$ionicHistory/'); + } + + warn('', ''); + + var methodsMap = { + getCurrentView: 'currentView', + getBackView: 'backView', + getForwardView: 'forwardView', + getCurrentStateName: 'currentStateName', + nextViewOptions: 'nextViewOptions', + clearHistory: 'clearHistory' + }; + + forEach(methodsMap, function(newMethod, oldMethod) { + methodsMap[oldMethod] = function() { + warn('.' + oldMethod, '.' + newMethod); + return $ionicHistory[newMethod].apply(this, arguments); + }; + }); + + return methodsMap; + +}]); + +/** + * @private + * TODO document + */ + +IonicModule +.factory('$ionicViewSwitcher',[ + '$timeout', + '$document', + '$q', + '$ionicClickBlock', + '$ionicConfig', + '$ionicNavBarDelegate', +function($timeout, $document, $q, $ionicClickBlock, $ionicConfig, $ionicNavBarDelegate) { + + var TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend'; + var DATA_NO_CACHE = '$noCache'; + var DATA_DESTROY_ELE = '$destroyEle'; + var DATA_ELE_IDENTIFIER = '$eleId'; + var DATA_VIEW_ACCESSED = '$accessed'; + var DATA_FALLBACK_TIMER = '$fallbackTimer'; + var DATA_VIEW = '$viewData'; + var NAV_VIEW_ATTR = 'nav-view'; + var HISTORY_CURSOR_ATTR = 'history-cursor'; + var VIEW_STATUS_ACTIVE = 'active'; + var VIEW_STATUS_CACHED = 'cached'; + var VIEW_STATUS_STAGED = 'stage'; + + var transitionCounter = 0; + var nextTransition, nextDirection; + ionic.transition = ionic.transition || {}; + ionic.transition.isActive = false; + var isActiveTimer; + var cachedAttr = ionic.DomUtil.cachedAttr; + var transitionPromises = []; + + var ionicViewSwitcher = { + + create: function(navViewCtrl, viewLocals, enteringView, leavingView) { + // get a reference to an entering/leaving element if they exist + // loop through to see if the view is already in the navViewElement + var enteringEle, leavingEle; + var transitionId = ++transitionCounter; + var alreadyInDom; + + var switcher = { + + init: function(registerData, callback) { + ionicViewSwitcher.isTransitioning(true); + + switcher.loadViewElements(registerData); + + switcher.render(registerData, function() { + callback && callback(); + }); + }, + + loadViewElements: function(registerData) { + var viewEle, viewElements = navViewCtrl.getViewElements(); + var enteringEleIdentifier = getViewElementIdentifier(viewLocals, enteringView); + var navViewActiveEleId = navViewCtrl.activeEleId(); + + for (var x = 0, l = viewElements.length; x < l; x++) { + viewEle = viewElements.eq(x); + + if (viewEle.data(DATA_ELE_IDENTIFIER) === enteringEleIdentifier) { + // we found an existing element in the DOM that should be entering the view + if (viewEle.data(DATA_NO_CACHE)) { + // the existing element should not be cached, don't use it + viewEle.data(DATA_ELE_IDENTIFIER, enteringEleIdentifier + ionic.Utils.nextUid()); + viewEle.data(DATA_DESTROY_ELE, true); + + } else { + enteringEle = viewEle; + } + + } else if (viewEle.data(DATA_ELE_IDENTIFIER) === navViewActiveEleId) { + leavingEle = viewEle; + } + + if (enteringEle && leavingEle) break; + } + + alreadyInDom = !!enteringEle; + + if (!alreadyInDom) { + // still no existing element to use + // create it using existing template/scope/locals + enteringEle = registerData.ele || ionicViewSwitcher.createViewEle(viewLocals); + + // existing elements in the DOM are looked up by their state name and state id + enteringEle.data(DATA_ELE_IDENTIFIER, enteringEleIdentifier); + } + + navViewCtrl.activeEleId(enteringEleIdentifier); + + registerData.ele = null; + }, + + render: function(registerData, callback) { + // disconnect the leaving scope before reconnecting or creating a scope for the entering view + leavingEle && ionic.Utils.disconnectScope(leavingEle.scope()); + + if (alreadyInDom) { + // it was already found in the DOM, just reconnect the scope + ionic.Utils.reconnectScope(enteringEle.scope()); + + } else { + // the entering element is not already in the DOM + // set that the entering element should be "staged" and its + // styles of where this element will go before it hits the DOM + navViewAttr(enteringEle, VIEW_STATUS_STAGED); + + var enteringData = getTransitionData(viewLocals, enteringEle, registerData.direction, enteringView); + var transitionFn = $ionicConfig.transitions.views[enteringData.transition] || $ionicConfig.transitions.views.none; + transitionFn(enteringEle, null, enteringData.direction, true).run(0); + + enteringEle.data(DATA_VIEW, { + viewId: enteringData.viewId, + historyId: enteringData.historyId, + stateName: enteringData.stateName, + stateParams: enteringData.stateParams + }); + + // if the current state has cache:false + // or the element has cache-view="false" attribute + if (viewState(viewLocals).cache === false || viewState(viewLocals).cache === 'false' || + enteringEle.attr('cache-view') == 'false' || $ionicConfig.views.maxCache() === 0) { + enteringEle.data(DATA_NO_CACHE, true); + } + + // append the entering element to the DOM, create a new scope and run link + var viewScope = navViewCtrl.appendViewElement(enteringEle, viewLocals); + + delete enteringData.direction; + delete enteringData.transition; + viewScope.$emit('$ionicView.loaded', enteringData); + } + + // update that this view was just accessed + enteringEle.data(DATA_VIEW_ACCESSED, Date.now()); + + callback && callback(); + }, + + transition: function(direction, enableBack) { + var deferred = $q.defer(); + transitionPromises.push(deferred.promise); + + var enteringData = getTransitionData(viewLocals, enteringEle, direction, enteringView); + var leavingData = extend(extend({}, enteringData), getViewData(leavingView)); + enteringData.transitionId = leavingData.transitionId = transitionId; + enteringData.fromCache = !!alreadyInDom; + enteringData.enableBack = !!enableBack; + + cachedAttr(enteringEle.parent(), 'nav-view-transition', enteringData.transition); + cachedAttr(enteringEle.parent(), 'nav-view-direction', enteringData.direction); + + // cancel any previous transition complete fallbacks + $timeout.cancel(enteringEle.data(DATA_FALLBACK_TIMER)); + + switcher.emit('before', enteringData, leavingData); + + // 1) get the transition ready and see if it'll animate + var transitionFn = $ionicConfig.transitions.views[enteringData.transition] || $ionicConfig.transitions.views.none; + var viewTransition = transitionFn(enteringEle, leavingEle, enteringData.direction, enteringData.shouldAnimate); + + if (viewTransition.shouldAnimate) { + // 2) attach transitionend events (and fallback timer) + enteringEle.on(TRANSITIONEND_EVENT, transitionComplete); + enteringEle.data(DATA_FALLBACK_TIMER, $timeout(transitionComplete, 1000)); + $ionicClickBlock.show(); + } + + // 3) stage entering element, opacity 0, no transition duration + navViewAttr(enteringEle, VIEW_STATUS_STAGED); + + // 4) place the elements in the correct step to begin + viewTransition.run(0); + + // 5) wait a frame so the styles apply + $timeout(onReflow, 16); + + function onReflow() { + // 6) remove that we're staging the entering element so it can transition + navViewAttr(enteringEle, viewTransition.shouldAnimate ? 'entering' : VIEW_STATUS_ACTIVE); + navViewAttr(leavingEle, viewTransition.shouldAnimate ? 'leaving' : VIEW_STATUS_CACHED); + + // 7) start the transition + viewTransition.run(1); + + $ionicNavBarDelegate._instances.forEach(function(instance) { + instance.triggerTransitionStart(transitionId); + }); + + if (!viewTransition.shouldAnimate) { + // no animated transition + transitionComplete(); + } + } + + function transitionComplete() { + if (transitionComplete.x) return; + transitionComplete.x = true; + + enteringEle.off(TRANSITIONEND_EVENT, transitionComplete); + $timeout.cancel(enteringEle.data(DATA_FALLBACK_TIMER)); + leavingEle && $timeout.cancel(leavingEle.data(DATA_FALLBACK_TIMER)); + + // 8) emit that the views have finished transitioning + // each parent nav-view will update which views are active and cached + switcher.emit('after', enteringData, leavingData); + + // 9) resolve that this one transition (there could be many w/ nested views) + deferred.resolve(navViewCtrl); + + // 10) the most recent transition added has completed and all the active + // transition promises should be added to the services array of promises + if (transitionId === transitionCounter) { + $q.all(transitionPromises).then(ionicViewSwitcher.transitionEnd); + switcher.cleanup(enteringData); + } + + $ionicNavBarDelegate._instances.forEach(function(instance) { + instance.triggerTransitionEnd(); + }); + + // remove any references that could cause memory issues + nextTransition = nextDirection = enteringView = leavingView = enteringEle = leavingEle = null; + } + + }, + + emit: function(step, enteringData, leavingData) { + var scope = enteringEle.scope(); + if (scope) { + scope.$emit('$ionicView.' + step + 'Enter', enteringData); + if (step == 'after') { + scope.$emit('$ionicView.enter', enteringData); + } + } + + if (leavingEle) { + scope = leavingEle.scope(); + if (scope) { + scope.$emit('$ionicView.' + step + 'Leave', leavingData); + if (step == 'after') { + scope.$emit('$ionicView.leave', leavingData); + } + } + } + }, + + cleanup: function(transData) { + // check if any views should be removed + if (leavingEle && transData.direction == 'back' && !$ionicConfig.views.forwardCache()) { + // if they just navigated back we can destroy the forward view + // do not remove forward views if cacheForwardViews config is true + destroyViewEle(leavingEle); + } + + var viewElements = navViewCtrl.getViewElements(); + var viewElementsLength = viewElements.length; + var x, viewElement; + var removeOldestAccess = (viewElementsLength - 1) > $ionicConfig.views.maxCache(); + var removableEle; + var oldestAccess = Date.now(); + + for (x = 0; x < viewElementsLength; x++) { + viewElement = viewElements.eq(x); + + if (removeOldestAccess && viewElement.data(DATA_VIEW_ACCESSED) < oldestAccess) { + // remember what was the oldest element to be accessed so it can be destroyed + oldestAccess = viewElement.data(DATA_VIEW_ACCESSED); + removableEle = viewElements.eq(x); + + } else if (viewElement.data(DATA_DESTROY_ELE) && navViewAttr(viewElement) != VIEW_STATUS_ACTIVE) { + destroyViewEle(viewElement); + } + } + + destroyViewEle(removableEle); + + if (enteringEle.data(DATA_NO_CACHE)) { + enteringEle.data(DATA_DESTROY_ELE, true); + } + }, + + enteringEle: function() { return enteringEle; }, + leavingEle: function() { return leavingEle; } + + }; + + return switcher; + }, + + transitionEnd: function(navViewCtrls) { + forEach(navViewCtrls, function(navViewCtrl){ + navViewCtrl.transitionEnd(); + }); + + ionicViewSwitcher.isTransitioning(false); + $ionicClickBlock.hide(); + transitionPromises = []; + }, + + nextTransition: function(val) { + nextTransition = val; + }, + + nextDirection: function(val) { + nextDirection = val; + }, + + isTransitioning: function(val) { + if (arguments.length) { + ionic.transition.isActive = !!val; + $timeout.cancel(isActiveTimer); + if (val) { + isActiveTimer = $timeout(function() { + ionicViewSwitcher.isTransitioning(false); + }, 999); + } + } + return ionic.transition.isActive; + }, + + createViewEle: function(viewLocals) { + var containerEle = $document[0].createElement('div'); + if (viewLocals && viewLocals.$template) { + containerEle.innerHTML = viewLocals.$template; + if (containerEle.children.length === 1) { + containerEle.children[0].classList.add('pane'); + return jqLite(containerEle.children[0]); + } + } + containerEle.className = "pane"; + return jqLite(containerEle); + }, + + viewEleIsActive: function(viewEle, isActiveAttr) { + navViewAttr(viewEle, isActiveAttr ? VIEW_STATUS_ACTIVE : VIEW_STATUS_CACHED); + }, + + getTransitionData: getTransitionData, + navViewAttr: navViewAttr, + destroyViewEle: destroyViewEle + + }; + + return ionicViewSwitcher; + + + function getViewElementIdentifier(locals, view) { + if (viewState(locals).abstract) return viewState(locals).name; + if (view) return view.stateId || view.viewId; + return ionic.Utils.nextUid(); + } + + function viewState(locals) { + return locals && locals.$$state && locals.$$state.self || {}; + } + + function getTransitionData(viewLocals, enteringEle, direction, view) { + // Priority + // 1) attribute directive on the button/link to this view + // 2) entering element's attribute + // 3) entering view's $state config property + // 4) view registration data + // 5) global config + // 6) fallback value + + var state = viewState(viewLocals); + var viewTransition = nextTransition || cachedAttr(enteringEle, 'view-transition') || state.viewTransition || $ionicConfig.views.transition() || 'ios'; + var navBarTransition = $ionicConfig.navBar.transition(); + direction = nextDirection || cachedAttr(enteringEle, 'view-direction') || state.viewDirection || direction || 'none'; + + return extend(getViewData(view), { + transition: viewTransition, + navBarTransition: navBarTransition === 'view' ? viewTransition : navBarTransition, + direction: direction, + shouldAnimate: (viewTransition !== 'none' && direction !== 'none') + }); + } + + function getViewData(view) { + view = view || {}; + return { + viewId: view.viewId, + historyId: view.historyId, + stateId: view.stateId, + stateName: view.stateName, + stateParams: view.stateParams + }; + } + + function navViewAttr(ele, value) { + if (arguments.length > 1) { + cachedAttr(ele, NAV_VIEW_ATTR, value); + } else { + return cachedAttr(ele, NAV_VIEW_ATTR); + } + } + + function destroyViewEle(ele) { + // we found an element that should be removed + // destroy its scope, then remove the element + if (ele && ele.length) { + var viewScope = ele.scope(); + if (viewScope) { + viewScope.$emit('$ionicView.unloaded', ele.data(DATA_VIEW)); + viewScope.$destroy(); + } + ele.remove(); + } + } + +}]); + +/** + * @private + * Parts of Ionic requires that $scope data is attached to the element. + * We do not want to disable adding $scope data to the $element when + * $compileProvider.debugInfoEnabled(false) is used. + */ +IonicModule.config(['$provide', function($provide) { + $provide.decorator('$compile', ['$delegate', function($compile) { + $compile.$$addScopeInfo = function $$addScopeInfo($element, scope, isolated, noTemplate) { + var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope'; + $element.data(dataName, scope); + }; + return $compile; + }]); +}]); + +/** + * @private + */ +IonicModule.config([ + '$provide', +function($provide) { + function $LocationDecorator($location, $timeout) { + + $location.__hash = $location.hash; + //Fix: when window.location.hash is set, the scrollable area + //found nearest to body's scrollTop is set to scroll to an element + //with that ID. + $location.hash = function(value) { + if (angular.isDefined(value)) { + $timeout(function() { + var scroll = document.querySelector('.scroll-content'); + if (scroll) + scroll.scrollTop = 0; + }, 0, false); + } + return $location.__hash(value); + }; + + return $location; + } + + $provide.decorator('$location', ['$delegate', '$timeout', $LocationDecorator]); +}]); + +IonicModule + +.controller('$ionicHeaderBar', [ + '$scope', + '$element', + '$attrs', + '$q', + '$ionicConfig', + '$ionicHistory', +function($scope, $element, $attrs, $q, $ionicConfig, $ionicHistory) { + var TITLE = 'title'; + var BACK_TEXT = 'back-text'; + var BACK_BUTTON = 'back-button'; + var DEFAULT_TITLE = 'default-title'; + var PREVIOUS_TITLE = 'previous-title'; + var HIDE = 'hide'; + + var self = this; + var titleText = ''; + var previousTitleText = ''; + var titleLeft = 0; + var titleRight = 0; + var titleCss = ''; + var isBackEnabled = false; + var isBackShown = true; + var isNavBackShown = true; + var isBackElementShown = false; + var titleTextWidth = 0; + + + self.beforeEnter = function(viewData) { + $scope.$broadcast('$ionicView.beforeEnter', viewData); + }; + + + self.title = function(newTitleText) { + if (arguments.length && newTitleText !== titleText) { + getEle(TITLE).innerHTML = newTitleText; + titleText = newTitleText; + titleTextWidth = 0; + } + return titleText; + }; + + + self.enableBack = function(shouldEnable, disableReset) { + // whether or not the back button show be visible, according + // to the navigation and history + if (arguments.length) { + isBackEnabled = shouldEnable; + if (!disableReset) self.updateBackButton(); + } + return isBackEnabled; + }; + + + self.showBack = function(shouldShow, disableReset) { + // different from enableBack() because this will always have the back + // visually hidden if false, even if the history says it should show + if (arguments.length) { + isBackShown = shouldShow; + if (!disableReset) self.updateBackButton(); + } + return isBackShown; + }; + + + self.showNavBack = function(shouldShow) { + // different from showBack() because this is for the entire nav bar's + // setting for all of it's child headers. For internal use. + isNavBackShown = shouldShow; + self.updateBackButton(); + }; + + + self.updateBackButton = function() { + if ((isBackShown && isNavBackShown && isBackEnabled) !== isBackElementShown) { + isBackElementShown = isBackShown && isNavBackShown && isBackEnabled; + var backBtnEle = getEle(BACK_BUTTON); + backBtnEle && backBtnEle.classList[ isBackElementShown ? 'remove' : 'add' ](HIDE); + } + }; + + + self.titleTextWidth = function() { + if (!titleTextWidth) { + var bounds = ionic.DomUtil.getTextBounds(getEle(TITLE)); + titleTextWidth = Math.min(bounds && bounds.width || 30); + } + return titleTextWidth; + }; + + + self.titleWidth = function() { + var titleWidth = self.titleTextWidth(); + var offsetWidth = getEle(TITLE).offsetWidth; + if (offsetWidth < titleWidth) { + titleWidth = offsetWidth + (titleLeft - titleRight - 5); + } + return titleWidth; + }; + + + self.titleTextX = function() { + return ($element[0].offsetWidth / 2) - (self.titleWidth() / 2); + }; + + + self.titleLeftRight = function() { + return titleLeft - titleRight; + }; + + + self.backButtonTextLeft = function() { + var offsetLeft = 0; + var ele = getEle(BACK_TEXT); + while (ele) { + offsetLeft += ele.offsetLeft; + ele = ele.parentElement; + } + return offsetLeft; + }; + + + self.resetBackButton = function() { + if ($ionicConfig.backButton.previousTitleText()) { + var previousTitleEle = getEle(PREVIOUS_TITLE); + if (previousTitleEle) { + previousTitleEle.classList.remove(HIDE); + + var newPreviousTitleText = $ionicHistory.backTitle(); + + if (newPreviousTitleText !== previousTitleText) { + previousTitleText = previousTitleEle.innerHTML = newPreviousTitleText; + } + } + var defaultTitleEle = getEle(DEFAULT_TITLE); + if (defaultTitleEle) { + defaultTitleEle.classList.remove(HIDE); + } + } + }; + + + self.align = function(textAlign) { + var titleEle = getEle(TITLE); + + textAlign = textAlign || $attrs.alignTitle || $ionicConfig.navBar.alignTitle(); + + var widths = self.calcWidths(textAlign, false); + + if (isBackShown && previousTitleText && $ionicConfig.backButton.previousTitleText()) { + var previousTitleWidths = self.calcWidths(textAlign, true); + + var availableTitleWidth = $element[0].offsetWidth - previousTitleWidths.titleLeft - previousTitleWidths.titleRight; + + if (self.titleTextWidth() <= availableTitleWidth) { + widths = previousTitleWidths; + } + } + + return self.updatePositions(titleEle, widths.titleLeft, widths.titleRight, widths.buttonsLeft, widths.buttonsRight, widths.css, widths.showPrevTitle); + }; + + + self.calcWidths = function(textAlign, isPreviousTitle) { + var titleEle = getEle(TITLE); + var backBtnEle = getEle(BACK_BUTTON); + var x, y, z, b, c, d, childSize, bounds; + var childNodes = $element[0].childNodes; + var buttonsLeft = 0; + var buttonsRight = 0; + var isCountRightOfTitle; + var updateTitleLeft = 0; + var updateTitleRight = 0; + var updateCss = ''; + var backButtonWidth = 0; + + // Compute how wide the left children are + // Skip all titles (there may still be two titles, one leaving the dom) + // Once we encounter a titleEle, realize we are now counting the right-buttons, not left + for (x = 0; x < childNodes.length; x++) { + c = childNodes[x]; + + childSize = 0; + if (c.nodeType == 1) { + // element node + if (c === titleEle) { + isCountRightOfTitle = true; + continue; + } + + if (c.classList.contains(HIDE)) { + continue; + } + + if (isBackShown && c === backBtnEle) { + + for (y = 0; y < c.childNodes.length; y++) { + b = c.childNodes[y]; + + if (b.nodeType == 1) { + + if (b.classList.contains(BACK_TEXT)) { + for (z = 0; z < b.children.length; z++) { + d = b.children[z]; + + if (isPreviousTitle) { + if (d.classList.contains(DEFAULT_TITLE)) continue; + backButtonWidth += d.offsetWidth; + } else { + if (d.classList.contains(PREVIOUS_TITLE)) continue; + backButtonWidth += d.offsetWidth; + } + } + + } else { + backButtonWidth += b.offsetWidth; + } + + } else if (b.nodeType == 3 && b.nodeValue.trim()) { + bounds = ionic.DomUtil.getTextBounds(b); + backButtonWidth += bounds && bounds.width || 0; + } + + } + childSize = backButtonWidth || c.offsetWidth; + + } else { + // not the title, not the back button, not a hidden element + childSize = c.offsetWidth; + } + + } else if (c.nodeType == 3 && c.nodeValue.trim()) { + // text node + bounds = ionic.DomUtil.getTextBounds(c); + childSize = bounds && bounds.width || 0; + } + + if (isCountRightOfTitle) { + buttonsRight += childSize; + } else { + buttonsLeft += childSize; + } + } + + // Size and align the header titleEle based on the sizes of the left and + // right children, and the desired alignment mode + if (textAlign == 'left') { + updateCss = 'title-left'; + if (buttonsLeft) { + updateTitleLeft = buttonsLeft + 15; + } + if (buttonsRight) { + updateTitleRight = buttonsRight + 15; + } + + } else if (textAlign == 'right') { + updateCss = 'title-right'; + if (buttonsLeft) { + updateTitleLeft = buttonsLeft + 15; + } + if (buttonsRight) { + updateTitleRight = buttonsRight + 15; + } + + } else { + // center the default + var margin = Math.max(buttonsLeft, buttonsRight) + 10; + if (margin > 10) { + updateTitleLeft = updateTitleRight = margin; + } + } + + return { + backButtonWidth: backButtonWidth, + buttonsLeft: buttonsLeft, + buttonsRight: buttonsRight, + titleLeft: updateTitleLeft, + titleRight: updateTitleRight, + showPrevTitle: isPreviousTitle, + css: updateCss + }; + }; + + + self.updatePositions = function(titleEle, updateTitleLeft, updateTitleRight, buttonsLeft, buttonsRight, updateCss, showPreviousTitle) { + var deferred = $q.defer(); + + // only make DOM updates when there are actual changes + if (titleEle) { + if (updateTitleLeft !== titleLeft) { + titleEle.style.left = updateTitleLeft ? updateTitleLeft + 'px' : ''; + titleLeft = updateTitleLeft; + } + if (updateTitleRight !== titleRight) { + titleEle.style.right = updateTitleRight ? updateTitleRight + 'px' : ''; + titleRight = updateTitleRight; + } + + if (updateCss !== titleCss) { + updateCss && titleEle.classList.add(updateCss); + titleCss && titleEle.classList.remove(titleCss); + titleCss = updateCss; + } + } + + if ($ionicConfig.backButton.previousTitleText()) { + var prevTitle = getEle(PREVIOUS_TITLE); + var defaultTitle = getEle(DEFAULT_TITLE); + + prevTitle && prevTitle.classList[ showPreviousTitle ? 'remove' : 'add'](HIDE); + defaultTitle && defaultTitle.classList[ showPreviousTitle ? 'add' : 'remove'](HIDE); + } + + ionic.requestAnimationFrame(function() { + if (titleEle && titleEle.offsetWidth + 10 < titleEle.scrollWidth) { + var minRight = buttonsRight + 5; + var testRight = $element[0].offsetWidth - titleLeft - self.titleTextWidth() - 20; + updateTitleRight = testRight < minRight ? minRight : testRight; + if (updateTitleRight !== titleRight) { + titleEle.style.right = updateTitleRight + 'px'; + titleRight = updateTitleRight; + } + } + deferred.resolve(); + }); + + return deferred.promise; + }; + + + self.setCss = function(elementClassname, css) { + ionic.DomUtil.cachedStyles(getEle(elementClassname), css); + }; + + + var eleCache = {}; + function getEle(className) { + if (!eleCache[className]) { + eleCache[className] = $element[0].querySelector('.' + className); + } + return eleCache[className]; + } + + + $scope.$on('$destroy', function() { + for (var n in eleCache) eleCache[n] = null; + }); + +}]); + + +/** + * @ngdoc service + * @name $ionicListDelegate + * @module ionic + * + * @description + * Delegate for controlling the {@link ionic.directive:ionList} directive. + * + * Methods called directly on the $ionicListDelegate service will control all lists. + * Use the {@link ionic.service:$ionicListDelegate#$getByHandle $getByHandle} + * method to control specific ionList instances. + * + * @usage + * + * ````html + * + * + * + * + * {% raw %}Hello, {{i}}!{% endraw %} + * + * + * + * + * ``` + * ```js + * function MyCtrl($scope, $ionicListDelegate) { + * $scope.showDeleteButtons = function() { + * $ionicListDelegate.showDelete(true); + * }; + * } + * ``` + */ +IonicModule +.service('$ionicListDelegate', ionic.DelegateService([ + /** + * @ngdoc method + * @name $ionicListDelegate#showReorder + * @param {boolean=} showReorder Set whether or not this list is showing its reorder buttons. + * @returns {boolean} Whether the reorder buttons are shown. + */ + 'showReorder', + /** + * @ngdoc method + * @name $ionicListDelegate#showDelete + * @param {boolean=} showDelete Set whether or not this list is showing its delete buttons. + * @returns {boolean} Whether the delete buttons are shown. + */ + 'showDelete', + /** + * @ngdoc method + * @name $ionicListDelegate#canSwipeItems + * @param {boolean=} canSwipeItems Set whether or not this list is able to swipe to show + * option buttons. + * @returns {boolean} Whether the list is able to swipe to show option buttons. + */ + 'canSwipeItems', + /** + * @ngdoc method + * @name $ionicListDelegate#closeOptionButtons + * @description Closes any option buttons on the list that are swiped open. + */ + 'closeOptionButtons', + /** + * @ngdoc method + * @name $ionicListDelegate#$getByHandle + * @param {string} handle + * @returns `delegateInstance` A delegate instance that controls only the + * {@link ionic.directive:ionList} directives with `delegate-handle` matching + * the given handle. + * + * Example: `$ionicListDelegate.$getByHandle('my-handle').showReorder(true);` + */ +])) + +.controller('$ionicList', [ + '$scope', + '$attrs', + '$ionicListDelegate', + '$ionicHistory', +function($scope, $attrs, $ionicListDelegate, $ionicHistory) { + var self = this; + var isSwipeable = true; + var isReorderShown = false; + var isDeleteShown = false; + + var deregisterInstance = $ionicListDelegate._registerInstance( + self, $attrs.delegateHandle, function() { + return $ionicHistory.isActiveScope($scope); + } + ); + $scope.$on('$destroy', deregisterInstance); + + self.showReorder = function(show) { + if (arguments.length) { + isReorderShown = !!show; + } + return isReorderShown; + }; + + self.showDelete = function(show) { + if (arguments.length) { + isDeleteShown = !!show; + } + return isDeleteShown; + }; + + self.canSwipeItems = function(can) { + if (arguments.length) { + isSwipeable = !!can; + } + return isSwipeable; + }; + + self.closeOptionButtons = function() { + self.listView && self.listView.clearDragEffects(); + }; +}]); + +IonicModule + +.controller('$ionicNavBar', [ + '$scope', + '$element', + '$attrs', + '$compile', + '$timeout', + '$ionicNavBarDelegate', + '$ionicConfig', + '$ionicHistory', +function($scope, $element, $attrs, $compile, $timeout, $ionicNavBarDelegate, $ionicConfig, $ionicHistory) { + + var CSS_HIDE = 'hide'; + var DATA_NAV_BAR_CTRL = '$ionNavBarController'; + var PRIMARY_BUTTONS = 'primaryButtons'; + var SECONDARY_BUTTONS = 'secondaryButtons'; + var BACK_BUTTON = 'backButton'; + var ITEM_TYPES = 'primaryButtons secondaryButtons leftButtons rightButtons title'.split(' '); + + var self = this; + var headerBars = []; + var navElementHtml = {}; + var isVisible = true; + var queuedTransitionStart, queuedTransitionEnd, latestTransitionId; + + $element.parent().data(DATA_NAV_BAR_CTRL, self); + + var delegateHandle = $attrs.delegateHandle || 'navBar' + ionic.Utils.nextUid(); + + var deregisterInstance = $ionicNavBarDelegate._registerInstance(self, delegateHandle); + + + self.init = function() { + $element.addClass('nav-bar-container'); + ionic.DomUtil.cachedAttr($element, 'nav-bar-transition', $ionicConfig.views.transition()); + + // create two nav bar blocks which will trade out which one is shown + self.createHeaderBar(false); + self.createHeaderBar(true); + + $scope.$emit('ionNavBar.init', delegateHandle); + }; + + + self.createHeaderBar = function(isActive, navBarClass) { + var containerEle = jqLite('