ionic-rails-engine 0.9.17 → 0.9.26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/README.md +1 -1
- data/app/assets/fonts/ionic/ionicons.eot +0 -0
- data/app/assets/fonts/ionic/ionicons.svg +527 -527
- data/app/assets/fonts/ionic/ionicons.ttf +0 -0
- data/app/assets/fonts/ionic/ionicons.woff +0 -0
- data/app/assets/javascripts/angular-ui/angular-ui-router.js +1769 -0
- data/app/assets/javascripts/angular-ui/angular-ui-router.min.js +7 -0
- data/app/assets/javascripts/ionic/ionic-angular.js +2289 -1168
- data/app/assets/javascripts/ionic/ionic-angular.min.js +5 -5
- data/app/assets/javascripts/ionic/ionic.bundle.js +35369 -0
- data/app/assets/javascripts/ionic/ionic.bundle.min.js +289 -0
- data/app/assets/javascripts/ionic/ionic.js +1049 -440
- data/app/assets/javascripts/ionic/ionic.min.js +6 -6
- data/app/assets/stylesheets/ionic/ionic.css.erb +819 -1289
- data/app/assets/stylesheets/ionic/ionic.min.css.erb +6 -6
- data/gem-public_cert.pem +11 -10
- data/lib/ionic-rails-engine/version.rb +1 -1
- metadata +17 -14
- metadata.gz.sig +0 -0
- data/app/assets/stylesheets/ionic/themes/ionic-ios7.css +0 -150
- data/app/assets/stylesheets/ionic/themes/ionic-ios7.min.css +0 -13
@@ -0,0 +1,7 @@
|
|
1
|
+
/**
|
2
|
+
* State-based routing for AngularJS
|
3
|
+
* @version v0.2.7
|
4
|
+
* @link http://angular-ui.github.com/
|
5
|
+
* @license MIT License, http://www.opensource.org/licenses/MIT
|
6
|
+
*/
|
7
|
+
"undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="ui.router"),function(a,b,c){"use strict";function d(a,b){return E(new(E(function(){},{prototype:a})),b)}function e(a){return D(arguments,function(b){b!==a&&D(b,function(b,c){a.hasOwnProperty(c)||(a[c]=b)})}),a}function f(a,b){var c=[];for(var d in a.path)if(""!==a.path[d]){if(!b.path[d])break;c.push(a.path[d])}return c}function g(a,b){if(Array.prototype.indexOf)return a.indexOf(b,Number(arguments[2])||0);var c=a.length>>>0,d=Number(arguments[2])||0;for(d=0>d?Math.ceil(d):Math.floor(d),0>d&&(d+=c);c>d;d++)if(d in a&&a[d]===b)return d;return-1}function h(a,b,c,d){var e,h=f(c,d),i={},j=[];for(var k in h)if(h[k].params&&h[k].params.length){e=h[k].params;for(var l in e)g(j,e[l])>=0||(j.push(e[l]),i[e[l]]=a[e[l]])}return E({},i,b)}function i(a,b){var c={};return D(a,function(a){var d=b[a];c[a]=null!=d?String(d):null}),c}function j(a,b,c){if(!c){c=[];for(var d in a)c.push(d)}for(var e=0;e<c.length;e++){var f=c[e];if(a[f]!=b[f])return!1}return!0}function k(a,b){var c={};return D(a,function(a){c[a]=b[a]}),c}function l(a,b){var d=1,f=2,g={},h=[],i=g,j=E(a.when(g),{$$promises:g,$$values:g});this.study=function(g){function k(a,c){if(o[c]!==f){if(n.push(c),o[c]===d)throw n.splice(0,n.indexOf(c)),new Error("Cyclic dependency: "+n.join(" -> "));if(o[c]=d,A(a))m.push(c,[function(){return b.get(a)}],h);else{var e=b.annotate(a);D(e,function(a){a!==c&&g.hasOwnProperty(a)&&k(g[a],a)}),m.push(c,a,e)}n.pop(),o[c]=f}}function l(a){return B(a)&&a.then&&a.$$promises}if(!B(g))throw new Error("'invocables' must be an object");var m=[],n=[],o={};return D(g,k),g=n=o=null,function(d,f,g){function h(){--s||(t||e(r,f.$$values),p.$$values=r,p.$$promises=!0,o.resolve(r))}function k(a){p.$$failure=a,o.reject(a)}function n(c,e,f){function i(a){l.reject(a),k(a)}function j(){if(!y(p.$$failure))try{l.resolve(b.invoke(e,g,r)),l.promise.then(function(a){r[c]=a,h()},i)}catch(a){i(a)}}var l=a.defer(),m=0;D(f,function(a){q.hasOwnProperty(a)&&!d.hasOwnProperty(a)&&(m++,q[a].then(function(b){r[a]=b,--m||j()},i))}),m||j(),q[c]=l.promise}if(l(d)&&g===c&&(g=f,f=d,d=null),d){if(!B(d))throw new Error("'locals' must be an object")}else d=i;if(f){if(!l(f))throw new Error("'parent' must be a promise returned by $resolve.resolve()")}else f=j;var o=a.defer(),p=o.promise,q=p.$$promises={},r=E({},d),s=1+m.length/3,t=!1;if(y(f.$$failure))return k(f.$$failure),p;f.$$values?(t=e(r,f.$$values),h()):(E(q,f.$$promises),f.then(h,k));for(var u=0,v=m.length;v>u;u+=3)d.hasOwnProperty(m[u])?h():n(m[u],m[u+1],m[u+2]);return p}},this.resolve=function(a,b,c,d){return this.study(a)(b,c,d)}}function m(a,b,c){this.fromConfig=function(a,b,c){return y(a.template)?this.fromString(a.template,b):y(a.templateUrl)?this.fromUrl(a.templateUrl,b):y(a.templateProvider)?this.fromProvider(a.templateProvider,b,c):null},this.fromString=function(a,b){return z(a)?a(b):a},this.fromUrl=function(c,d){return z(c)&&(c=c(d)),null==c?null:a.get(c,{cache:b}).then(function(a){return a.data})},this.fromProvider=function(a,b,d){return c.invoke(a,null,d||{params:b})}}function n(a){function b(b){if(!/^\w+(-+\w+)*$/.test(b))throw new Error("Invalid parameter name '"+b+"' in pattern '"+a+"'");if(f[b])throw new Error("Duplicate parameter name '"+b+"' in pattern '"+a+"'");f[b]=!0,j.push(b)}function c(a){return a.replace(/[\\\[\]\^$*+?.()|{}]/g,"\\$&")}var d,e=/([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,f={},g="^",h=0,i=this.segments=[],j=this.params=[];this.source=a;for(var k,l,m;(d=e.exec(a))&&(k=d[2]||d[3],l=d[4]||("*"==d[1]?".*":"[^/]*"),m=a.substring(h,d.index),!(m.indexOf("?")>=0));)g+=c(m)+"("+l+")",b(k),i.push(m),h=e.lastIndex;m=a.substring(h);var n=m.indexOf("?");if(n>=0){var o=this.sourceSearch=m.substring(n);m=m.substring(0,n),this.sourcePath=a.substring(0,h+n),D(o.substring(1).split(/[&?]/),b)}else this.sourcePath=a,this.sourceSearch="";g+=c(m)+"$",i.push(m),this.regexp=new RegExp(g),this.prefix=i[0]}function o(){this.compile=function(a){return new n(a)},this.isMatcher=function(a){return B(a)&&z(a.exec)&&z(a.format)&&z(a.concat)},this.$get=function(){return this}}function p(a){function b(a){var b=/^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(a.source);return null!=b?b[1].replace(/\\(.)/g,"$1"):""}function c(a,b){return a.replace(/\$(\$|\d{1,2})/,function(a,c){return b["$"===c?0:Number(c)]})}function d(a,b,c){if(!c)return!1;var d=a.invoke(b,b,{$match:c});return y(d)?d:!0}var e=[],f=null;this.rule=function(a){if(!z(a))throw new Error("'rule' must be a function");return e.push(a),this},this.otherwise=function(a){if(A(a)){var b=a;a=function(){return b}}else if(!z(a))throw new Error("'rule' must be a function");return f=a,this},this.when=function(e,f){var g,h=A(f);if(A(e)&&(e=a.compile(e)),!h&&!z(f)&&!C(f))throw new Error("invalid 'handler' in when()");var i={matcher:function(b,c){return h&&(g=a.compile(c),c=["$match",function(a){return g.format(a)}]),E(function(a,e){return d(a,c,b.exec(e.path(),e.search()))},{prefix:A(b.prefix)?b.prefix:""})},regex:function(a,e){if(a.global||a.sticky)throw new Error("when() RegExp must not be global or sticky");return h&&(g=e,e=["$match",function(a){return c(g,a)}]),E(function(b,c){return d(b,e,a.exec(c.path()))},{prefix:b(a)})}},j={matcher:a.isMatcher(e),regex:e instanceof RegExp};for(var k in j)if(j[k])return this.rule(i[k](e,f));throw new Error("invalid 'what' in when()")},this.$get=["$location","$rootScope","$injector",function(a,b,c){function d(b){function d(b){var d=b(c,a);return d?(A(d)&&a.replace().url(d),!0):!1}if(!b||!b.defaultPrevented){var g,h=e.length;for(g=0;h>g;g++)if(d(e[g]))return;f&&d(f)}}return b.$on("$locationChangeSuccess",d),{sync:function(){d()}}}]}function q(a,e,f){function g(a){return 0===a.indexOf(".")||0===a.indexOf("^")}function l(a,b){var d=A(a),e=d?a:a.name,f=g(e);if(f){if(!b)throw new Error("No reference point given for path '"+e+"'");for(var h=e.split("."),i=0,j=h.length,k=b;j>i;i++)if(""!==h[i]||0!==i){if("^"!==h[i])break;if(!k.parent)throw new Error("Path '"+e+"' not valid for state '"+b.name+"'");k=k.parent}else k=b;h=h.slice(i).join("."),e=k.name+(k.name&&h?".":"")+h}var l=u[e];return!l||!d&&(d||l!==a&&l.self!==a)?c:l}function m(a,b){v[a]||(v[a]=[]),v[a].push(b)}function n(b){b=d(b,{self:b,resolve:b.resolve||{},toString:function(){return this.name}});var c=b.name;if(!A(c)||c.indexOf("@")>=0)throw new Error("State must have a valid name");if(u.hasOwnProperty(c))throw new Error("State '"+c+"'' is already defined");var e=-1!==c.indexOf(".")?c.substring(0,c.lastIndexOf(".")):A(b.parent)?b.parent:"";if(e&&!u[e])return m(e,b.self);for(var f in x)z(x[f])&&(b[f]=x[f](b,x.$delegates[f]));if(u[c]=b,!b[w]&&b.url&&a.when(b.url,["$match","$stateParams",function(a,c){t.$current.navigable==b&&j(a,c)||t.transitionTo(b,a,{location:!1})}]),v[c])for(var g=0;g<v[c].length;g++)n(v[c][g]);return b}function o(a,b){return A(a)&&!y(b)?x[a]:z(b)&&A(a)?(x[a]&&!x.$delegates[a]&&(x.$delegates[a]=x[a]),x[a]=b,this):this}function p(a,b){return B(a)?b=a:b.name=a,n(b),this}function q(a,e,g,m,n,o,p){function q(){p.url()!==H&&(p.url(H),p.replace())}function v(a,c,d,f,h){var i=d?c:k(a.params,c),j={$stateParams:i};h.resolve=n.resolve(a.resolve,j,h.resolve,a);var l=[h.resolve.then(function(a){h.globals=a})];return f&&l.push(f),D(a.views,function(c,d){var e=c.resolve&&c.resolve!==a.resolve?c.resolve:{};e.$template=[function(){return g.load(d,{view:c,locals:j,params:i,notify:!1})||""}],l.push(n.resolve(e,j,h.resolve,a).then(function(f){if(z(c.controllerProvider)||C(c.controllerProvider)){var g=b.extend({},e,j);f.$$controller=m.invoke(c.controllerProvider,null,g)}else f.$$controller=c.controller;f.$$state=a,h[d]=f}))}),e.all(l).then(function(){return h})}var x=e.reject(new Error("transition superseded")),A=e.reject(new Error("transition prevented")),B=e.reject(new Error("transition aborted")),G=e.reject(new Error("transition failed")),H=p.url();return s.locals={resolve:null,globals:{$stateParams:{}}},t={params:{},current:s.self,$current:s,transition:null},t.reload=function(){t.transitionTo(t.current,o,{reload:!0,inherit:!1,notify:!1})},t.go=function(a,b,c){return this.transitionTo(a,b,E({inherit:!0,relative:t.$current},c))},t.transitionTo=function(b,c,f){c=c||{},f=E({location:!0,inherit:!1,relative:null,notify:!0,reload:!1,$retry:!1},f||{});var g,k=t.$current,n=t.params,u=k.path,z=l(b,f.relative);if(!y(z)){var C={to:b,toParams:c,options:f};if(g=a.$broadcast("$stateNotFound",C,k.self,n),g.defaultPrevented)return q(),B;if(g.retry){if(f.$retry)return q(),G;var D=t.transition=e.when(g.retry);return D.then(function(){return D!==t.transition?x:(C.options.$retry=!0,t.transitionTo(C.to,C.toParams,C.options))},function(){return B}),q(),D}if(b=C.to,c=C.toParams,f=C.options,z=l(b,f.relative),!y(z)){if(f.relative)throw new Error("Could not resolve '"+b+"' from state '"+f.relative+"'");throw new Error("No such state '"+b+"'")}}if(z[w])throw new Error("Cannot transition to abstract state '"+b+"'");f.inherit&&(c=h(o,c||{},t.$current,z)),b=z;var I,J,K=b.path,L=s.locals,M=[];for(I=0,J=K[I];J&&J===u[I]&&j(c,n,J.ownParams)&&!f.reload;I++,J=K[I])L=M[I]=J.locals;if(r(b,k,L,f))return b.self.reloadOnSearch!==!1&&q(),t.transition=null,e.when(t.current);if(c=i(b.params,c||{}),f.notify&&(g=a.$broadcast("$stateChangeStart",b.self,c,k.self,n),g.defaultPrevented))return q(),A;for(var N=e.when(L),O=I;O<K.length;O++,J=K[O])L=M[O]=d(L),N=v(J,c,J===b,N,L);var P=t.transition=N.then(function(){var d,e,g;if(t.transition!==P)return x;for(d=u.length-1;d>=I;d--)g=u[d],g.self.onExit&&m.invoke(g.self.onExit,g.self,g.locals.globals),g.locals=null;for(d=I;d<K.length;d++)e=K[d],e.locals=M[d],e.self.onEnter&&m.invoke(e.self.onEnter,e.self,e.locals.globals);if(t.transition!==P)return x;t.$current=b,t.current=b.self,t.params=c,F(t.params,o),t.transition=null;var h=b.navigable;return f.location&&h&&(p.url(h.url.format(h.locals.globals.$stateParams)),"replace"===f.location&&p.replace()),f.notify&&a.$broadcast("$stateChangeSuccess",b.self,c,k.self,n),H=p.url(),t.current},function(d){return t.transition!==P?x:(t.transition=null,a.$broadcast("$stateChangeError",b.self,c,k.self,n,d),q(),e.reject(d))});return P},t.is=function(a,d){var e=l(a);return y(e)?t.$current!==e?!1:y(d)?b.equals(o,d):!0:c},t.includes=function(a,d){var e=l(a);if(!y(e))return c;if(!y(t.$current.includes[e.name]))return!1;var f=!0;return b.forEach(d,function(a,b){y(o[b])&&o[b]===a||(f=!1)}),f},t.href=function(a,b,c){c=E({lossy:!0,inherit:!1,absolute:!1,relative:t.$current},c||{});var d=l(a,c.relative);if(!y(d))return null;b=h(o,b||{},t.$current,d);var e=d&&c.lossy?d.navigable:d,g=e&&e.url?e.url.format(i(d.params,b||{})):null;return!f.html5Mode()&&g&&(g="#"+f.hashPrefix()+g),c.absolute&&g&&(g=p.protocol()+"://"+p.host()+(80==p.port()||443==p.port()?"":":"+p.port())+(!f.html5Mode()&&g?"/":"")+g),g},t.get=function(a,b){if(!y(a)){var c=[];return D(u,function(a){c.push(a.self)}),c}var d=l(a,b);return d&&d.self?d.self:null},t}function r(a,b,c,d){return a!==b||(c!==b.locals||d.reload)&&a.self.reloadOnSearch!==!1?void 0:!0}var s,t,u={},v={},w="abstract",x={parent:function(a){if(y(a.parent)&&a.parent)return l(a.parent);var b=/^(.+)\.[^.]+$/.exec(a.name);return b?l(b[1]):s},data:function(a){return a.parent&&a.parent.data&&(a.data=a.self.data=E({},a.parent.data,a.data)),a.data},url:function(a){var b=a.url;if(A(b))return"^"==b.charAt(0)?e.compile(b.substring(1)):(a.parent.navigable||s).url.concat(b);if(e.isMatcher(b)||null==b)return b;throw new Error("Invalid url '"+b+"' in state '"+a+"'")},navigable:function(a){return a.url?a:a.parent?a.parent.navigable:null},params:function(a){if(!a.params)return a.url?a.url.parameters():a.parent.params;if(!C(a.params))throw new Error("Invalid params in state '"+a+"'");if(a.url)throw new Error("Both params and url specicified in state '"+a+"'");return a.params},views:function(a){var b={};return D(y(a.views)?a.views:{"":a},function(c,d){d.indexOf("@")<0&&(d+="@"+a.parent.name),b[d]=c}),b},ownParams:function(a){if(!a.parent)return a.params;var b={};D(a.params,function(a){b[a]=!0}),D(a.parent.params,function(c){if(!b[c])throw new Error("Missing required parameter '"+c+"' in state '"+a.name+"'");b[c]=!1});var c=[];return D(b,function(a,b){a&&c.push(b)}),c},path:function(a){return a.parent?a.parent.path.concat(a):[]},includes:function(a){var b=a.parent?E({},a.parent.includes):{};return b[a.name]=!0,b},$delegates:{}};s=n({name:"",url:"^",views:null,"abstract":!0}),s.navigable=null,this.decorator=o,this.state=p,this.$get=q,q.$inject=["$rootScope","$q","$view","$injector","$resolve","$stateParams","$location","$urlRouter"]}function r(){function a(a,b){return{load:function(c,d){var e,f={template:null,controller:null,view:null,locals:null,notify:!0,async:!0,params:{}};return d=E(f,d),d.view&&(e=b.fromConfig(d.view,d.params,d.locals)),e&&d.notify&&a.$broadcast("$viewContentLoading",d),e}}}this.$get=a,a.$inject=["$rootScope","$templateFactory"]}function s(a,c,d,e,f){var g=e.has("$animator")?e.get("$animator"):!1,h=!1,i={restrict:"ECA",terminal:!0,priority:1e3,transclude:!0,compile:function(e,j,k){return function(e,j,l){function m(b){var g=a.$current&&a.$current.locals[p];if(g!==o){var h=t(r&&b);if(h.remove(j),n&&(n.$destroy(),n=null),!g)return o=null,v.state=null,h.restore(s,j);o=g,v.state=g.$$state;var i=c(h.populate(g.$template,j));if(n=e.$new(),g.$$controller){g.$scope=n;var k=d(g.$$controller,g);j.children().data("$ngControllerController",k)}i(n),n.$emit("$viewContentLoaded"),q&&n.$eval(q),f()}}var n,o,p=l[i.name]||l.name||"",q=l.onload||"",r=g&&g(e,l),s=k(e),t=function(a){return{"true":{remove:function(a){r.leave(a.contents(),a)},restore:function(a,b){r.enter(a,b)},populate:function(a,c){var d=b.element("<div></div>").html(a).contents();return r.enter(d,c),d}},"false":{remove:function(a){a.html("")},restore:function(a,b){b.append(a)},populate:function(a,b){return b.html(a),b.contents()}}}[a.toString()]};j.append(s);var u=j.parent().inheritedData("$uiView");p.indexOf("@")<0&&(p=p+"@"+(u?u.state.name:""));var v={name:p,state:null};j.data("$uiView",v);var w=function(){if(!h){h=!0;try{m(!0)}catch(a){throw h=!1,a}h=!1}};e.$on("$stateChangeSuccess",w),e.$on("$viewContentLoading",w),m(!1)}}};return i}function t(a){var b=a.replace(/\n/g," ").match(/^([^(]+?)\s*(\((.*)\))?$/);if(!b||4!==b.length)throw new Error("Invalid state ref '"+a+"'");return{state:b[1],paramExpr:b[3]||null}}function u(a){var b=a.parent().inheritedData("$uiView");return b&&b.state&&b.state.name?b.state:void 0}function v(a,b){return{restrict:"A",require:"?^uiSrefActive",link:function(c,d,e,f){var g=t(e.uiSref),h=null,i=u(d)||a.$current,j="FORM"===d[0].nodeName,k=j?"action":"href",l=!0,m=function(b){if(b&&(h=b),l){var c=a.href(g.state,h,{relative:i});if(!c)return l=!1,!1;d[0][k]=c,f&&f.$$setStateInfo(g.state,h)}};g.paramExpr&&(c.$watch(g.paramExpr,function(a){a!==h&&m(a)},!0),h=c.$eval(g.paramExpr)),m(),j||d.bind("click",function(d){var e=d.which||d.button;0!==e&&1!=e||d.ctrlKey||d.metaKey||d.shiftKey||(b(function(){c.$apply(function(){a.go(g.state,h,{relative:i})})}),d.preventDefault())})}}}function w(a,b,c){return{restrict:"A",controller:function(d,e,f){function g(){a.$current.self===i&&h()?e.addClass(l):e.removeClass(l)}function h(){return!k||j(k,b)}var i,k,l;l=c(f.uiSrefActive||"",!1)(d),this.$$setStateInfo=function(b,c){i=a.get(b,u(e)),k=c,g()},d.$on("$stateChangeSuccess",g)}}}function x(a,b){function e(a){this.locals=a.locals.globals,this.params=this.locals.$stateParams}function f(){this.locals=null,this.params=null}function g(c,g){if(null!=g.redirectTo){var h,j=g.redirectTo;if(A(j))h=j;else{if(!z(j))throw new Error("Invalid 'redirectTo' in when()");h=function(a,b){return j(a,b.path(),b.search())}}b.when(c,h)}else a.state(d(g,{parent:null,name:"route:"+encodeURIComponent(c),url:c,onEnter:e,onExit:f}));return i.push(g),this}function h(a,b,d){function e(a){return""!==a.name?a:c}var f={routes:i,params:d,current:c};return b.$on("$stateChangeStart",function(a,c,d,f){b.$broadcast("$routeChangeStart",e(c),e(f))}),b.$on("$stateChangeSuccess",function(a,c,d,g){f.current=e(c),b.$broadcast("$routeChangeSuccess",e(c),e(g)),F(d,f.params)}),b.$on("$stateChangeError",function(a,c,d,f,g,h){b.$broadcast("$routeChangeError",e(c),e(f),h)}),f}var i=[];e.$inject=["$$state"],this.when=g,this.$get=h,h.$inject=["$state","$rootScope","$routeParams"]}var y=b.isDefined,z=b.isFunction,A=b.isString,B=b.isObject,C=b.isArray,D=b.forEach,E=b.extend,F=b.copy;b.module("ui.router.util",["ng"]),b.module("ui.router.router",["ui.router.util"]),b.module("ui.router.state",["ui.router.router","ui.router.util"]),b.module("ui.router",["ui.router.state"]),b.module("ui.router.compat",["ui.router"]),l.$inject=["$q","$injector"],b.module("ui.router.util").service("$resolve",l),m.$inject=["$http","$templateCache","$injector"],b.module("ui.router.util").service("$templateFactory",m),n.prototype.concat=function(a){return new n(this.sourcePath+a+this.sourceSearch)},n.prototype.toString=function(){return this.source},n.prototype.exec=function(a,b){var c=this.regexp.exec(a);if(!c)return null;var d,e=this.params,f=e.length,g=this.segments.length-1,h={};if(g!==c.length-1)throw new Error("Unbalanced capture group in route '"+this.source+"'");for(d=0;g>d;d++)h[e[d]]=c[d+1];for(;f>d;d++)h[e[d]]=b[e[d]];return h},n.prototype.parameters=function(){return this.params},n.prototype.format=function(a){var b=this.segments,c=this.params;if(!a)return b.join("");var d,e,f,g=b.length-1,h=c.length,i=b[0];for(d=0;g>d;d++)f=a[c[d]],null!=f&&(i+=encodeURIComponent(f)),i+=b[d+1];for(;h>d;d++)f=a[c[d]],null!=f&&(i+=(e?"&":"?")+c[d]+"="+encodeURIComponent(f),e=!0);return i},b.module("ui.router.util").provider("$urlMatcherFactory",o),p.$inject=["$urlMatcherFactoryProvider"],b.module("ui.router.router").provider("$urlRouter",p),q.$inject=["$urlRouterProvider","$urlMatcherFactoryProvider","$locationProvider"],b.module("ui.router.state").value("$stateParams",{}).provider("$state",q),r.$inject=[],b.module("ui.router.state").provider("$view",r),s.$inject=["$state","$compile","$controller","$injector","$anchorScroll"],b.module("ui.router.state").directive("uiView",s),v.$inject=["$state","$timeout"],w.$inject=["$state","$stateParams","$interpolate"],b.module("ui.router.state").directive("uiSref",v).directive("uiSrefActive",w),x.$inject=["$stateProvider","$urlRouterProvider"],b.module("ui.router.compat").provider("$route",x).directive("ngView",s)}(window,window.angular);
|
@@ -1,59 +1,354 @@
|
|
1
1
|
/*!
|
2
|
-
* Copyright
|
2
|
+
* Copyright 2014 Drifty Co.
|
3
3
|
* http://drifty.com/
|
4
4
|
*
|
5
|
-
* Ionic, v0.9.
|
5
|
+
* Ionic, v0.9.26
|
6
6
|
* A powerful HTML5 mobile app framework.
|
7
7
|
* http://ionicframework.com/
|
8
8
|
*
|
9
|
-
* By @maxlynch, @
|
9
|
+
* By @maxlynch, @benjsperry, @adamdbradley <3
|
10
10
|
*
|
11
11
|
* Licensed under the MIT license. Please see LICENSE for more information.
|
12
12
|
*
|
13
|
-
|
13
|
+
*/
|
14
|
+
;
|
14
15
|
/**
|
15
16
|
* Create a wrapping module to ease having to include too many
|
16
17
|
* modules.
|
17
18
|
*/
|
18
19
|
angular.module('ionic.service', [
|
20
|
+
'ionic.service.bind',
|
19
21
|
'ionic.service.platform',
|
20
22
|
'ionic.service.actionSheet',
|
21
23
|
'ionic.service.gesture',
|
22
24
|
'ionic.service.loading',
|
23
25
|
'ionic.service.modal',
|
24
26
|
'ionic.service.popup',
|
25
|
-
'ionic.service.templateLoad'
|
27
|
+
'ionic.service.templateLoad',
|
28
|
+
'ionic.service.view',
|
29
|
+
'ionic.decorator.location'
|
30
|
+
]);
|
31
|
+
|
32
|
+
// UI specific services and delegates
|
33
|
+
angular.module('ionic.ui.service', [
|
34
|
+
'ionic.ui.service.scrollDelegate',
|
35
|
+
'ionic.ui.service.slideBoxDelegate',
|
36
|
+
'ionic.ui.service.sideMenuDelegate',
|
26
37
|
]);
|
27
38
|
|
28
39
|
angular.module('ionic.ui', [
|
29
40
|
'ionic.ui.content',
|
30
41
|
'ionic.ui.scroll',
|
31
42
|
'ionic.ui.tabs',
|
32
|
-
'ionic.ui.
|
43
|
+
'ionic.ui.viewState',
|
33
44
|
'ionic.ui.header',
|
34
45
|
'ionic.ui.sideMenu',
|
35
46
|
'ionic.ui.slideBox',
|
36
47
|
'ionic.ui.list',
|
37
48
|
'ionic.ui.checkbox',
|
38
49
|
'ionic.ui.toggle',
|
39
|
-
'ionic.ui.radio'
|
50
|
+
'ionic.ui.radio',
|
51
|
+
'ionic.ui.touch'
|
40
52
|
]);
|
41
53
|
|
54
|
+
|
42
55
|
angular.module('ionic', [
|
43
56
|
'ionic.service',
|
57
|
+
'ionic.ui.service',
|
44
58
|
'ionic.ui',
|
45
|
-
|
59
|
+
|
46
60
|
// Angular deps
|
47
61
|
'ngAnimate',
|
48
|
-
'
|
49
|
-
'
|
50
|
-
'ngSanitize'
|
62
|
+
'ngSanitize',
|
63
|
+
'ui.router'
|
51
64
|
]);
|
52
65
|
;
|
53
|
-
angular.module('ionic.service.actionSheet', ['ionic.service.templateLoad', 'ionic.ui.actionSheet', 'ngAnimate'])
|
54
66
|
|
55
|
-
.
|
56
|
-
|
67
|
+
angular.element.prototype.addClass = function(cssClasses) {
|
68
|
+
var x, y, cssClass, el, splitClasses, existingClasses;
|
69
|
+
if (cssClasses && cssClasses != 'ng-scope' && cssClasses != 'ng-isolate-scope') {
|
70
|
+
for(x=0; x<this.length; x++) {
|
71
|
+
el = this[x];
|
72
|
+
if(el.setAttribute) {
|
73
|
+
|
74
|
+
if(cssClasses.indexOf(' ') < 0) {
|
75
|
+
el.classList.add(cssClasses);
|
76
|
+
} else {
|
77
|
+
existingClasses = (' ' + (el.getAttribute('class') || '') + ' ')
|
78
|
+
.replace(/[\n\t]/g, " ");
|
79
|
+
splitClasses = cssClasses.split(' ');
|
80
|
+
|
81
|
+
for (y=0; y<splitClasses.length; y++) {
|
82
|
+
cssClass = splitClasses[y].trim();
|
83
|
+
if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
|
84
|
+
existingClasses += cssClass + ' ';
|
85
|
+
}
|
86
|
+
}
|
87
|
+
el.setAttribute('class', existingClasses.trim());
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}
|
92
|
+
return this;
|
93
|
+
};
|
94
|
+
|
95
|
+
angular.element.prototype.removeClass = function(cssClasses) {
|
96
|
+
var x, y, splitClasses, cssClass, el;
|
97
|
+
if (cssClasses) {
|
98
|
+
for(x=0; x<this.length; x++) {
|
99
|
+
el = this[x];
|
100
|
+
if(el.getAttribute) {
|
101
|
+
if(cssClasses.indexOf(' ') < 0) {
|
102
|
+
el.classList.remove(cssClasses);
|
103
|
+
} else {
|
104
|
+
splitClasses = cssClasses.split(' ');
|
105
|
+
|
106
|
+
for (y=0; y<splitClasses.length; y++) {
|
107
|
+
cssClass = splitClasses[y];
|
108
|
+
el.setAttribute('class', (
|
109
|
+
(" " + (el.getAttribute('class') || '') + " ")
|
110
|
+
.replace(/[\n\t]/g, " ")
|
111
|
+
.replace(" " + cssClass.trim() + " ", " ")).trim()
|
112
|
+
);
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
return this;
|
119
|
+
};;
|
120
|
+
angular.module('ionic.decorator.location', [])
|
121
|
+
|
122
|
+
.config(['$provide', function($provide) {
|
123
|
+
$provide.decorator('$location', ['$delegate', '$timeout', $LocationDecorator]);
|
124
|
+
}]);
|
125
|
+
|
126
|
+
function $LocationDecorator($location, $timeout) {
|
127
|
+
|
128
|
+
$location.__hash = $location.hash;
|
129
|
+
//Fix: first time window.location.hash is set, the scrollable area
|
130
|
+
//found nearest to body's scrollTop is set to scroll to an element
|
131
|
+
//with that ID.
|
132
|
+
$location.hash = function(value) {
|
133
|
+
if (angular.isDefined(value)) {
|
134
|
+
$timeout(function() {
|
135
|
+
var scroll = document.querySelector('.scroll-content');
|
136
|
+
if (scroll)
|
137
|
+
scroll.scrollTop = 0;
|
138
|
+
}, 0, false);
|
139
|
+
}
|
140
|
+
return $location.__hash(value);
|
141
|
+
};
|
142
|
+
|
143
|
+
return $location;
|
144
|
+
}
|
145
|
+
;
|
146
|
+
(function() {
|
147
|
+
'use strict';
|
148
|
+
|
149
|
+
angular.module('ionic.ui.service.scrollDelegate', [])
|
150
|
+
|
151
|
+
.factory('$ionicScrollDelegate', ['$rootScope', '$timeout', '$q', '$anchorScroll', '$location', '$document', function($rootScope, $timeout, $q, $anchorScroll, $location, $document) {
|
152
|
+
return {
|
153
|
+
/**
|
154
|
+
* Trigger a scroll-to-top event on child scrollers.
|
155
|
+
*/
|
156
|
+
scrollTop: function(animate) {
|
157
|
+
$rootScope.$broadcast('scroll.scrollTop', animate);
|
158
|
+
},
|
159
|
+
scrollBottom: function(animate) {
|
160
|
+
$rootScope.$broadcast('scroll.scrollBottom', animate);
|
161
|
+
},
|
162
|
+
scrollTo: function(left, top, animate) {
|
163
|
+
$rootScope.$broadcast('scroll.scrollTo', left, top, animate);
|
164
|
+
},
|
165
|
+
resize: function() {
|
166
|
+
$rootScope.$broadcast('scroll.resize');
|
167
|
+
},
|
168
|
+
anchorScroll: function(animate) {
|
169
|
+
$rootScope.$broadcast('scroll.anchorScroll', animate);
|
170
|
+
},
|
171
|
+
tapScrollToTop: function(element, animate) {
|
172
|
+
var _this = this;
|
173
|
+
if (!angular.isDefined(animate)) {
|
174
|
+
animate = true;
|
175
|
+
}
|
176
|
+
|
177
|
+
ionic.on('tap', function(e) {
|
178
|
+
var target = e.target;
|
179
|
+
//Don't scroll to top for a button click
|
180
|
+
if (ionic.DomUtil.getParentOrSelfWithClass(target, 'button')) {
|
181
|
+
return;
|
182
|
+
}
|
183
|
+
|
184
|
+
var el = element[0];
|
185
|
+
var bounds = el.getBoundingClientRect();
|
186
|
+
|
187
|
+
if(ionic.DomUtil.rectContains(e.gesture.touches[0].pageX, e.gesture.touches[0].pageY, bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + 20)) {
|
188
|
+
_this.scrollTop(animate);
|
189
|
+
}
|
190
|
+
}, element[0]);
|
191
|
+
},
|
192
|
+
|
193
|
+
finishRefreshing: function($scope) {
|
194
|
+
$scope.$broadcast('scroll.refreshComplete');
|
195
|
+
},
|
196
|
+
|
197
|
+
/**
|
198
|
+
* Attempt to get the current scroll view in scope (if any)
|
199
|
+
*
|
200
|
+
* Note: will not work in an isolated scope context.
|
201
|
+
*/
|
202
|
+
getScrollView: function($scope) {
|
203
|
+
return $scope.scrollView;
|
204
|
+
},
|
205
|
+
|
206
|
+
/**
|
207
|
+
* Register a scope and scroll view for scroll event handling.
|
208
|
+
* $scope {Scope} the scope to register and listen for events
|
209
|
+
*/
|
210
|
+
register: function($scope, $element, scrollView) {
|
211
|
+
|
212
|
+
var scrollEl = $element[0];
|
213
|
+
|
214
|
+
function scrollViewResize() {
|
215
|
+
// Run the resize after this digest
|
216
|
+
return $timeout(function() {
|
217
|
+
scrollView.resize();
|
218
|
+
});
|
219
|
+
}
|
220
|
+
|
221
|
+
$element.on('scroll', function(e) {
|
222
|
+
var detail = (e.originalEvent || e).detail || {};
|
223
|
+
|
224
|
+
$scope.$onScroll && $scope.$onScroll({
|
225
|
+
event: e,
|
226
|
+
scrollTop: detail.scrollTop || 0,
|
227
|
+
scrollLeft: detail.scrollLeft || 0
|
228
|
+
});
|
229
|
+
|
230
|
+
});
|
231
|
+
|
232
|
+
$scope.$parent.$on('scroll.resize', scrollViewResize);
|
233
|
+
|
234
|
+
// Called to stop refreshing on the scroll view
|
235
|
+
$scope.$parent.$on('scroll.refreshComplete', function(e) {
|
236
|
+
scrollView.finishPullToRefresh();
|
237
|
+
});
|
238
|
+
|
239
|
+
$scope.$parent.$on('scroll.anchorScroll', function(e, animate) {
|
240
|
+
scrollViewResize().then(function() {
|
241
|
+
var hash = $location.hash();
|
242
|
+
var elm;
|
243
|
+
if (hash && (elm = document.getElementById(hash)) ) {
|
244
|
+
var scroll = ionic.DomUtil.getPositionInParent(elm, scrollEl);
|
245
|
+
scrollView.scrollTo(scroll.left, scroll.top, !!animate);
|
246
|
+
} else {
|
247
|
+
scrollView.scrollTo(0,0, !!animate);
|
248
|
+
}
|
249
|
+
});
|
250
|
+
});
|
251
|
+
|
252
|
+
$scope.$parent.$on('scroll.scrollTo', function(e, left, top, animate) {
|
253
|
+
scrollViewResize().then(function() {
|
254
|
+
scrollView.scrollTo(left, top, !!animate);
|
255
|
+
});
|
256
|
+
});
|
257
|
+
$scope.$parent.$on('scroll.scrollTop', function(e, animate) {
|
258
|
+
scrollViewResize().then(function() {
|
259
|
+
scrollView.scrollTo(0, 0, !!animate);
|
260
|
+
});
|
261
|
+
});
|
262
|
+
$scope.$parent.$on('scroll.scrollBottom', function(e, animate) {
|
263
|
+
scrollViewResize().then(function() {
|
264
|
+
var sv = scrollView;
|
265
|
+
if (sv) {
|
266
|
+
var max = sv.getScrollMax();
|
267
|
+
sv.scrollTo(max.left, max.top, !!animate);
|
268
|
+
}
|
269
|
+
});
|
270
|
+
});
|
271
|
+
}
|
272
|
+
};
|
273
|
+
}]);
|
274
|
+
|
275
|
+
})(ionic);
|
276
|
+
;
|
277
|
+
(function() {
|
278
|
+
'use strict';
|
279
|
+
|
280
|
+
angular.module('ionic.ui.service.sideMenuDelegate', [])
|
281
|
+
|
282
|
+
.factory('$ionicSideMenuDelegate', ['$rootScope', '$timeout', '$q', function($rootScope, $timeout, $q) {
|
283
|
+
return {
|
284
|
+
getSideMenuController: function($scope) {
|
285
|
+
return $scope.sideMenuController;
|
286
|
+
},
|
287
|
+
close: function($scope) {
|
288
|
+
if($scope.sideMenuController) {
|
289
|
+
$scope.sideMenuController.close();
|
290
|
+
}
|
291
|
+
},
|
292
|
+
toggleLeft: function($scope) {
|
293
|
+
if($scope.sideMenuController) {
|
294
|
+
$scope.sideMenuController.toggleLeft();
|
295
|
+
}
|
296
|
+
},
|
297
|
+
toggleRight: function($scope) {
|
298
|
+
if($scope.sideMenuController) {
|
299
|
+
$scope.sideMenuController.toggleRight();
|
300
|
+
}
|
301
|
+
},
|
302
|
+
openLeft: function($scope) {
|
303
|
+
if($scope.sideMenuController) {
|
304
|
+
$scope.sideMenuController.openPercentage(100);
|
305
|
+
}
|
306
|
+
},
|
307
|
+
openRight: function($scope) {
|
308
|
+
if($scope.sideMenuController) {
|
309
|
+
$scope.sideMenuController.openPercentage(-100);
|
310
|
+
}
|
311
|
+
}
|
312
|
+
};
|
313
|
+
}]);
|
314
|
+
|
315
|
+
})();
|
316
|
+
;
|
317
|
+
(function() {
|
318
|
+
'use strict';
|
319
|
+
|
320
|
+
angular.module('ionic.ui.service.slideBoxDelegate', [])
|
321
|
+
|
322
|
+
.factory('$ionicSlideBoxDelegate', ['$rootScope', '$timeout', function($rootScope, $timeout) {
|
323
|
+
return {
|
324
|
+
/**
|
325
|
+
* Trigger a slidebox to update and resize itself
|
326
|
+
*/
|
327
|
+
update: function(animate) {
|
328
|
+
$rootScope.$broadcast('slideBox.update');
|
329
|
+
},
|
330
|
+
|
331
|
+
register: function($scope, $element) {
|
332
|
+
$scope.$parent.$on('slideBox.update', function(e) {
|
333
|
+
if(e.defaultPrevented) {
|
334
|
+
return;
|
335
|
+
}
|
336
|
+
$timeout(function() {
|
337
|
+
$scope.$parent.slideBox.setup();
|
338
|
+
});
|
339
|
+
e.preventDefault();
|
340
|
+
});
|
341
|
+
}
|
342
|
+
};
|
343
|
+
}]);
|
344
|
+
|
345
|
+
})(ionic);
|
346
|
+
;
|
347
|
+
angular.module('ionic.service.actionSheet', ['ionic.service.templateLoad', 'ionic.service.platform', 'ionic.ui.actionSheet', 'ngAnimate'])
|
348
|
+
|
349
|
+
.factory('$ionicActionSheet', ['$rootScope', '$document', '$compile', '$animate', '$timeout',
|
350
|
+
'$ionicTemplateLoader', '$ionicPlatform',
|
351
|
+
function($rootScope, $document, $compile, $animate, $timeout, $ionicTemplateLoader, $ionicPlatform) {
|
57
352
|
|
58
353
|
return {
|
59
354
|
/**
|
@@ -69,12 +364,11 @@ angular.module('ionic.service.actionSheet', ['ionic.service.templateLoad', 'ioni
|
|
69
364
|
|
70
365
|
angular.extend(scope, opts);
|
71
366
|
|
72
|
-
|
73
367
|
// Compile the template
|
74
|
-
var element = $compile('<action-sheet buttons="buttons"></action-sheet>')(scope);
|
368
|
+
var element = $compile('<ion-action-sheet buttons="buttons"></ion-action-sheet>')(scope);
|
75
369
|
|
76
370
|
// Grab the sheet element for animation
|
77
|
-
var sheetEl = angular.element(element[0].querySelector('.action-sheet'));
|
371
|
+
var sheetEl = angular.element(element[0].querySelector('.action-sheet-wrapper'));
|
78
372
|
|
79
373
|
var hideSheet = function(didCancel) {
|
80
374
|
$animate.leave(sheetEl, function() {
|
@@ -86,8 +380,21 @@ angular.module('ionic.service.actionSheet', ['ionic.service.templateLoad', 'ioni
|
|
86
380
|
$animate.removeClass(element, 'active', function() {
|
87
381
|
scope.$destroy();
|
88
382
|
});
|
383
|
+
|
384
|
+
$document[0].body.classList.remove('action-sheet-open');
|
385
|
+
};
|
386
|
+
|
387
|
+
var onHardwareBackButton = function() {
|
388
|
+
hideSheet();
|
89
389
|
};
|
90
390
|
|
391
|
+
scope.$on('$destroy', function() {
|
392
|
+
$ionicPlatform.offHardwareBackButton(onHardwareBackButton);
|
393
|
+
});
|
394
|
+
|
395
|
+
// Support Android back button to close
|
396
|
+
$ionicPlatform.onHardwareBackButton(onHardwareBackButton);
|
397
|
+
|
91
398
|
scope.cancel = function() {
|
92
399
|
hideSheet(true);
|
93
400
|
};
|
@@ -110,6 +417,8 @@ angular.module('ionic.service.actionSheet', ['ionic.service.templateLoad', 'ioni
|
|
110
417
|
|
111
418
|
$document[0].body.appendChild(element[0]);
|
112
419
|
|
420
|
+
$document[0].body.classList.add('action-sheet-open');
|
421
|
+
|
113
422
|
var sheet = new ionic.views.ActionSheet({el: element[0] });
|
114
423
|
scope.sheet = sheet;
|
115
424
|
|
@@ -123,9 +432,63 @@ angular.module('ionic.service.actionSheet', ['ionic.service.templateLoad', 'ioni
|
|
123
432
|
|
124
433
|
}]);
|
125
434
|
;
|
435
|
+
angular.module('ionic.service.bind', [])
|
436
|
+
.factory('$ionicBind', ['$parse', '$interpolate', function($parse, $interpolate) {
|
437
|
+
var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
|
438
|
+
return function(scope, attrs, bindDefinition) {
|
439
|
+
angular.forEach(bindDefinition || {}, function (definition, scopeName) {
|
440
|
+
//Adapted from angular.js $compile
|
441
|
+
var match = definition.match(LOCAL_REGEXP) || [],
|
442
|
+
attrName = match[3] || scopeName,
|
443
|
+
mode = match[1], // @, =, or &
|
444
|
+
parentGet,
|
445
|
+
unwatch;
|
446
|
+
|
447
|
+
switch(mode) {
|
448
|
+
case '@':
|
449
|
+
if (!attrs[attrName]) {
|
450
|
+
return;
|
451
|
+
}
|
452
|
+
attrs.$observe(attrName, function(value) {
|
453
|
+
scope[scopeName] = value;
|
454
|
+
});
|
455
|
+
// we trigger an interpolation to ensure
|
456
|
+
// the value is there for use immediately
|
457
|
+
if (attrs[attrName]) {
|
458
|
+
scope[scopeName] = $interpolate(attrs[attrName])(scope);
|
459
|
+
}
|
460
|
+
break;
|
461
|
+
|
462
|
+
case '=':
|
463
|
+
if (!attrs[attrName]) {
|
464
|
+
return;
|
465
|
+
}
|
466
|
+
unwatch = scope.$watch(attrs[attrName], function(value) {
|
467
|
+
scope[scopeName] = value;
|
468
|
+
});
|
469
|
+
//Destroy parent scope watcher when this scope is destroyed
|
470
|
+
scope.$on('$destroy', unwatch);
|
471
|
+
break;
|
472
|
+
|
473
|
+
case '&':
|
474
|
+
/* jshint -W044 */
|
475
|
+
if (attrs[attrName] && attrs[attrName].match(RegExp(scopeName + '\(.*?\)'))) {
|
476
|
+
throw new Error('& expression binding "' + scopeName + '" looks like it will recursively call "' +
|
477
|
+
attrs[attrName] + '" and cause a stack overflow! Please choose a different scopeName.');
|
478
|
+
}
|
479
|
+
parentGet = $parse(attrs[attrName]);
|
480
|
+
scope[scopeName] = function(locals) {
|
481
|
+
return parentGet(scope, locals);
|
482
|
+
};
|
483
|
+
break;
|
484
|
+
}
|
485
|
+
});
|
486
|
+
};
|
487
|
+
}]);
|
488
|
+
;
|
126
489
|
angular.module('ionic.service.gesture', [])
|
127
490
|
|
128
|
-
.factory('
|
491
|
+
.factory('$ionicGesture', [function() {
|
129
492
|
return {
|
130
493
|
on: function(eventType, cb, $element) {
|
131
494
|
return window.ionic.onGesture(eventType, cb, $element[0]);
|
@@ -138,12 +501,12 @@ angular.module('ionic.service.gesture', [])
|
|
138
501
|
;
|
139
502
|
angular.module('ionic.service.loading', ['ionic.ui.loading'])
|
140
503
|
|
141
|
-
.factory('
|
504
|
+
.factory('$ionicLoading', ['$rootScope', '$document', '$compile', function($rootScope, $document, $compile) {
|
142
505
|
return {
|
143
506
|
/**
|
144
507
|
* Load an action sheet with the given template string.
|
145
508
|
*
|
146
|
-
* A new isolated scope will be created for the
|
509
|
+
* A new isolated scope will be created for the
|
147
510
|
* action sheet and the new element will be appended into the body.
|
148
511
|
*
|
149
512
|
* @param {object} opts the options for this ActionSheet (see docs)
|
@@ -154,7 +517,7 @@ angular.module('ionic.service.loading', ['ionic.ui.loading'])
|
|
154
517
|
animation: 'fade-in',
|
155
518
|
showBackdrop: true,
|
156
519
|
maxWidth: 200,
|
157
|
-
showDelay:
|
520
|
+
showDelay: 0
|
158
521
|
};
|
159
522
|
|
160
523
|
opts = angular.extend(defaults, opts);
|
@@ -165,15 +528,11 @@ angular.module('ionic.service.loading', ['ionic.ui.loading'])
|
|
165
528
|
// Make sure there is only one loading element on the page at one point in time
|
166
529
|
var existing = angular.element($document[0].querySelector('.loading-backdrop'));
|
167
530
|
if(existing.length) {
|
168
|
-
|
169
|
-
if(scope.loading) {
|
170
|
-
scope.loading.show();
|
171
|
-
return scope.loading;
|
172
|
-
}
|
531
|
+
existing.remove();
|
173
532
|
}
|
174
533
|
|
175
534
|
// Compile the template
|
176
|
-
var element = $compile('<loading>' + opts.content + '</loading>')(scope);
|
535
|
+
var element = $compile('<ion-loading>' + opts.content + '</ion-loading>')(scope);
|
177
536
|
|
178
537
|
$document[0].body.appendChild(element[0]);
|
179
538
|
|
@@ -192,10 +551,10 @@ angular.module('ionic.service.loading', ['ionic.ui.loading'])
|
|
192
551
|
};
|
193
552
|
}]);
|
194
553
|
;
|
195
|
-
angular.module('ionic.service.modal', ['ionic.service.templateLoad', 'ngAnimate'])
|
554
|
+
angular.module('ionic.service.modal', ['ionic.service.templateLoad', 'ionic.service.platform', 'ngAnimate'])
|
196
555
|
|
197
556
|
|
198
|
-
.factory('
|
557
|
+
.factory('$ionicModal', ['$rootScope', '$document', '$compile', '$animate', '$q', '$timeout', '$ionicPlatform', '$ionicTemplateLoader', function($rootScope, $document, $compile, $animate, $q, $timeout, $ionicPlatform, $ionicTemplateLoader) {
|
199
558
|
var ModalView = ionic.views.Modal.inherit({
|
200
559
|
initialize: function(opts) {
|
201
560
|
ionic.views.Modal.prototype.initialize.call(this, opts);
|
@@ -203,32 +562,75 @@ angular.module('ionic.service.modal', ['ionic.service.templateLoad', 'ngAnimate'
|
|
203
562
|
},
|
204
563
|
// Show the modal
|
205
564
|
show: function() {
|
206
|
-
var
|
565
|
+
var self = this;
|
207
566
|
var element = angular.element(this.el);
|
567
|
+
|
568
|
+
document.body.classList.add('modal-open');
|
569
|
+
|
570
|
+
self._isShown = true;
|
571
|
+
|
208
572
|
if(!element.parent().length) {
|
209
|
-
|
210
|
-
|
573
|
+
element.addClass(this.animation);
|
574
|
+
$animate.enter(element, angular.element($document[0].body), null, function() {
|
575
|
+
});
|
576
|
+
ionic.views.Modal.prototype.show.call(self);
|
577
|
+
} else {
|
578
|
+
$animate.addClass(element, this.animation, function() {
|
579
|
+
});
|
211
580
|
}
|
212
|
-
|
213
|
-
|
581
|
+
|
582
|
+
if(!this.didInitEvents) {
|
583
|
+
var onHardwareBackButton = function() {
|
584
|
+
self.hide();
|
585
|
+
};
|
586
|
+
|
587
|
+
self.scope.$on('$destroy', function() {
|
588
|
+
$ionicPlatform.offHardwareBackButton(onHardwareBackButton);
|
589
|
+
});
|
590
|
+
|
591
|
+
// Support Android back button to close
|
592
|
+
$ionicPlatform.onHardwareBackButton(onHardwareBackButton);
|
593
|
+
|
594
|
+
this.didInitEvents = true;
|
595
|
+
}
|
596
|
+
|
597
|
+
this.scope.$parent.$broadcast('modal.shown', this);
|
598
|
+
|
214
599
|
},
|
215
600
|
// Hide the modal
|
216
601
|
hide: function() {
|
602
|
+
this._isShown = false;
|
217
603
|
var element = angular.element(this.el);
|
218
|
-
$animate.removeClass(element, this.animation)
|
604
|
+
$animate.removeClass(element, this.animation, function() {
|
605
|
+
onHideModal(element[0]);
|
606
|
+
});
|
219
607
|
|
220
608
|
ionic.views.Modal.prototype.hide.call(this);
|
609
|
+
|
610
|
+
this.scope.$parent.$broadcast('modal.hidden', this);
|
221
611
|
},
|
222
612
|
|
223
613
|
// Remove and destroy the modal scope
|
224
614
|
remove: function() {
|
225
|
-
var
|
615
|
+
var self = this,
|
616
|
+
element = angular.element(this.el);
|
617
|
+
this._isShown = false;
|
226
618
|
$animate.leave(angular.element(this.el), function() {
|
227
|
-
|
619
|
+
onHideModal(element[0]);
|
620
|
+
self.scope.$parent.$broadcast('modal.removed', self);
|
621
|
+
self.scope.$destroy();
|
228
622
|
});
|
623
|
+
},
|
624
|
+
|
625
|
+
isShown: function() {
|
626
|
+
return !!this._isShown;
|
229
627
|
}
|
230
628
|
});
|
231
629
|
|
630
|
+
function onHideModal(element) {
|
631
|
+
document.body.classList.remove('modal-open');
|
632
|
+
}
|
633
|
+
|
232
634
|
var createModal = function(templateString, options) {
|
233
635
|
// Create a new scope for the modal
|
234
636
|
var scope = options.scope && options.scope.$new() || $rootScope.$new(true);
|
@@ -254,7 +656,7 @@ angular.module('ionic.service.modal', ['ionic.service.templateLoad', 'ngAnimate'
|
|
254
656
|
/**
|
255
657
|
* Load a modal with the given template string.
|
256
658
|
*
|
257
|
-
* A new isolated scope will be created for the
|
659
|
+
* A new isolated scope will be created for the
|
258
660
|
* modal and the new element will be appended into the body.
|
259
661
|
*/
|
260
662
|
fromTemplate: function(templateString, options) {
|
@@ -262,16 +664,16 @@ angular.module('ionic.service.modal', ['ionic.service.templateLoad', 'ngAnimate'
|
|
262
664
|
return modal;
|
263
665
|
},
|
264
666
|
fromTemplateUrl: function(url, cb, options) {
|
265
|
-
|
667
|
+
return $ionicTemplateLoader.load(url).then(function(templateString) {
|
266
668
|
var modal = createModal(templateString, options || {});
|
267
|
-
cb(modal);
|
669
|
+
cb ? cb(modal) : null;
|
670
|
+
return modal;
|
268
671
|
});
|
269
672
|
},
|
270
673
|
};
|
271
674
|
}]);
|
272
675
|
;
|
273
|
-
(function() {
|
274
|
-
'use strict';
|
676
|
+
(function(ionic) {'use strict';
|
275
677
|
|
276
678
|
angular.module('ionic.service.platform', [])
|
277
679
|
|
@@ -282,39 +684,10 @@ angular.module('ionic.service.platform', [])
|
|
282
684
|
* initializing some defaults that depend on the platform, such as the
|
283
685
|
* height of header bars on iOS 7.
|
284
686
|
*/
|
285
|
-
.provider('
|
286
|
-
var platform = 'web';
|
287
|
-
var isPlatformReady = false;
|
288
|
-
|
289
|
-
if(window.cordova || window.PhoneGap || window.phonegap) {
|
290
|
-
platform = 'cordova';
|
291
|
-
}
|
292
|
-
|
293
|
-
var isReady = function() {
|
294
|
-
if(platform == 'cordova') {
|
295
|
-
return window.device || window.Cordova;
|
296
|
-
}
|
297
|
-
return true;
|
298
|
-
};
|
299
|
-
|
300
|
-
// We need to do some stuff as soon as we know the platform,
|
301
|
-
// like adjust header margins for iOS 7, etc.
|
302
|
-
setTimeout(function afterReadyWait() {
|
303
|
-
if(isReady()) {
|
304
|
-
ionic.Platform.detect();
|
305
|
-
} else {
|
306
|
-
setTimeout(afterReadyWait, 50);
|
307
|
-
}
|
308
|
-
}, 10);
|
309
|
-
|
310
|
-
|
311
|
-
|
687
|
+
.provider('$ionicPlatform', function() {
|
312
688
|
|
313
689
|
return {
|
314
|
-
|
315
|
-
platform = p;
|
316
|
-
},
|
317
|
-
$get: ['$q', '$timeout', function($q, $timeout) {
|
690
|
+
$get: ['$q', function($q) {
|
318
691
|
return {
|
319
692
|
/**
|
320
693
|
* Some platforms have hardware back buttons, so this is one way to bind to it.
|
@@ -322,7 +695,7 @@ angular.module('ionic.service.platform', [])
|
|
322
695
|
* @param {function} cb the callback to trigger when this event occurs
|
323
696
|
*/
|
324
697
|
onHardwareBackButton: function(cb) {
|
325
|
-
|
698
|
+
ionic.Platform.ready(function() {
|
326
699
|
document.addEventListener('backbutton', cb, false);
|
327
700
|
});
|
328
701
|
},
|
@@ -333,34 +706,33 @@ angular.module('ionic.service.platform', [])
|
|
333
706
|
* @param {function} fn the listener function that was originally bound.
|
334
707
|
*/
|
335
708
|
offHardwareBackButton: function(fn) {
|
336
|
-
|
709
|
+
ionic.Platform.ready(function() {
|
337
710
|
document.removeEventListener('backbutton', fn);
|
338
711
|
});
|
339
712
|
},
|
340
713
|
|
714
|
+
is: function(type) {
|
715
|
+
return ionic.Platform.is(type);
|
716
|
+
},
|
717
|
+
|
341
718
|
/**
|
342
719
|
* Trigger a callback once the device is ready, or immediately if the device is already
|
343
720
|
* ready.
|
344
721
|
*/
|
345
722
|
ready: function(cb) {
|
346
|
-
var self = this;
|
347
723
|
var q = $q.defer();
|
348
724
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
cb();
|
354
|
-
} else {
|
355
|
-
$timeout(readyWait, 50);
|
356
|
-
}
|
357
|
-
}, 50);
|
725
|
+
ionic.Platform.ready(function(){
|
726
|
+
q.resolve();
|
727
|
+
cb();
|
728
|
+
});
|
358
729
|
|
359
730
|
return q.promise;
|
360
731
|
}
|
361
732
|
};
|
362
733
|
}]
|
363
734
|
};
|
735
|
+
|
364
736
|
});
|
365
737
|
|
366
738
|
})(ionic);
|
@@ -368,7 +740,7 @@ angular.module('ionic.service.platform', [])
|
|
368
740
|
angular.module('ionic.service.popup', ['ionic.service.templateLoad'])
|
369
741
|
|
370
742
|
|
371
|
-
.factory('
|
743
|
+
.factory('$ionicPopup', ['$rootScope', '$document', '$compile', 'TemplateLoader', function($rootScope, $document, $compile, TemplateLoader) {
|
372
744
|
|
373
745
|
var getPopup = function() {
|
374
746
|
// Make sure there is only one loading element on the page at one point in time
|
@@ -425,94 +797,635 @@ angular.module('ionic.service.popup', ['ionic.service.templateLoad'])
|
|
425
797
|
;
|
426
798
|
angular.module('ionic.service.templateLoad', [])
|
427
799
|
|
428
|
-
.factory('
|
800
|
+
.factory('$ionicTemplateLoader', ['$q', '$http', '$templateCache', function($q, $http, $templateCache) {
|
429
801
|
return {
|
430
802
|
load: function(url) {
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
method: 'GET',
|
435
|
-
url: url,
|
436
|
-
cache: $templateCache
|
437
|
-
}).success(function(html) {
|
438
|
-
deferred.resolve(html && html.trim());
|
439
|
-
}).error(function(err) {
|
440
|
-
deferred.reject(err);
|
803
|
+
return $http.get(url, {cache: $templateCache})
|
804
|
+
.then(function(response) {
|
805
|
+
return response.data && response.data.trim();
|
441
806
|
});
|
442
|
-
|
443
|
-
return deferred.promise;
|
444
807
|
}
|
445
808
|
};
|
446
809
|
}]);
|
447
810
|
;
|
448
|
-
(
|
449
|
-
'use strict';
|
450
|
-
|
451
|
-
angular.module('ionic.ui.actionSheet', [])
|
811
|
+
angular.module('ionic.service.view', ['ui.router', 'ionic.service.platform'])
|
452
812
|
|
453
|
-
.directive('actionSheet', ['$document', function($document) {
|
454
|
-
return {
|
455
|
-
restrict: 'E',
|
456
|
-
scope: true,
|
457
|
-
replace: true,
|
458
|
-
link: function($scope, $element){
|
459
|
-
var keyUp = function(e) {
|
460
|
-
if(e.which == 27) {
|
461
|
-
$scope.cancel();
|
462
|
-
$scope.$apply();
|
463
|
-
}
|
464
|
-
};
|
465
813
|
|
466
|
-
|
467
|
-
|
468
|
-
$scope.cancel();
|
469
|
-
$scope.$apply();
|
470
|
-
}
|
471
|
-
};
|
472
|
-
$scope.$on('$destroy', function() {
|
473
|
-
$element.remove();
|
474
|
-
$document.unbind('keyup', keyUp);
|
475
|
-
});
|
814
|
+
.run( ['$rootScope', '$state', '$location', '$document', '$animate', '$ionicPlatform',
|
815
|
+
function( $rootScope, $state, $location, $document, $animate, $ionicPlatform) {
|
476
816
|
|
477
|
-
|
478
|
-
|
479
|
-
},
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
'<button class="button" ng-click="buttonClicked($index)" ng-repeat="button in buttons">{{button.text}}</button>' +
|
485
|
-
'</div>' +
|
486
|
-
'<div class="action-sheet-group" ng-if="destructiveText">' +
|
487
|
-
'<button class="button destructive" ng-click="destructiveButtonClicked()">{{destructiveText}}</button>' +
|
488
|
-
'</div>' +
|
489
|
-
'<div class="action-sheet-group" ng-if="cancelText">' +
|
490
|
-
'<button class="button" ng-click="cancel()">{{cancelText}}</button>' +
|
491
|
-
'</div>' +
|
492
|
-
'</div>' +
|
493
|
-
'</div>'
|
817
|
+
// init the variables that keep track of the view history
|
818
|
+
$rootScope.$viewHistory = {
|
819
|
+
histories: { root: { historyId: 'root', parentHistoryId: null, stack: [], cursor: -1 } },
|
820
|
+
backView: null,
|
821
|
+
forwardView: null,
|
822
|
+
currentView: null,
|
823
|
+
disabledRegistrableTagNames: []
|
494
824
|
};
|
495
|
-
}]);
|
496
825
|
|
497
|
-
|
498
|
-
;
|
499
|
-
(function(ionic) {
|
500
|
-
'use strict';
|
826
|
+
$rootScope.$on('viewState.changeHistory', function(e, data) {
|
827
|
+
if(!data) return;
|
501
828
|
|
502
|
-
|
829
|
+
var hist = (data.historyId ? $rootScope.$viewHistory.histories[ data.historyId ] : null );
|
830
|
+
if(hist && hist.cursor > -1 && hist.cursor < hist.stack.length) {
|
831
|
+
// the history they're going to already exists
|
832
|
+
// go to it's last view in its stack
|
833
|
+
var view = hist.stack[ hist.cursor ];
|
834
|
+
return view.go(data);
|
835
|
+
}
|
503
836
|
|
837
|
+
// this history does not have a URL, but it does have a uiSref
|
838
|
+
// figure out its URL from the uiSref
|
839
|
+
if(!data.url && data.uiSref) {
|
840
|
+
data.url = $state.href(data.uiSref);
|
841
|
+
}
|
504
842
|
|
505
|
-
.
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
843
|
+
if(data.url) {
|
844
|
+
// don't let it start with a #, messes with $location.url()
|
845
|
+
if(data.url.indexOf('#') === 0) {
|
846
|
+
data.url = data.url.replace('#', '');
|
847
|
+
}
|
848
|
+
if(data.url !== $location.url()) {
|
849
|
+
// we've got a good URL, ready GO!
|
850
|
+
$location.url(data.url);
|
851
|
+
}
|
852
|
+
}
|
853
|
+
});
|
854
|
+
|
855
|
+
// Set the document title when a new view is shown
|
856
|
+
$rootScope.$on('viewState.viewEnter', function(e, data) {
|
857
|
+
if(data && data.title) {
|
858
|
+
$document[0].title = data.title;
|
859
|
+
}
|
860
|
+
});
|
861
|
+
|
862
|
+
// Triggered when devices with a hardware back button (Android) is clicked by the user
|
863
|
+
// This is a Cordova/Phonegap platform specifc method
|
864
|
+
function onHardwareBackButton(e) {
|
865
|
+
if($rootScope.$viewHistory.backView) {
|
866
|
+
// there is a back view, go to it
|
867
|
+
$rootScope.$viewHistory.backView.go();
|
868
|
+
} else {
|
869
|
+
// there is no back view, so close the app instead
|
870
|
+
ionic.Platform.exitApp();
|
871
|
+
}
|
872
|
+
e.preventDefault();
|
873
|
+
return false;
|
874
|
+
}
|
875
|
+
$ionicPlatform.onHardwareBackButton(onHardwareBackButton);
|
876
|
+
|
877
|
+
}])
|
878
|
+
|
879
|
+
.factory('$ionicViewService', ['$rootScope', '$state', '$location', '$window', '$injector',
|
880
|
+
function( $rootScope, $state, $location, $window, $injector) {
|
881
|
+
var $animate = $injector.has('$animate') ? $injector.get('$animate') : false;
|
882
|
+
|
883
|
+
var View = function(){};
|
884
|
+
View.prototype.initialize = function(data) {
|
885
|
+
if(data) {
|
886
|
+
for(var name in data) this[name] = data[name];
|
887
|
+
return this;
|
888
|
+
}
|
889
|
+
return null;
|
890
|
+
};
|
891
|
+
View.prototype.go = function() {
|
892
|
+
|
893
|
+
if(this.stateName) {
|
894
|
+
return $state.go(this.stateName, this.stateParams);
|
895
|
+
}
|
896
|
+
|
897
|
+
if(this.url && this.url !== $location.url()) {
|
898
|
+
|
899
|
+
if($rootScope.$viewHistory.backView === this) {
|
900
|
+
return $window.history.go(-1);
|
901
|
+
} else if($rootScope.$viewHistory.forwardView === this) {
|
902
|
+
return $window.history.go(1);
|
903
|
+
}
|
904
|
+
|
905
|
+
$location.url(this.url);
|
906
|
+
return;
|
907
|
+
}
|
908
|
+
|
909
|
+
return null;
|
910
|
+
};
|
911
|
+
View.prototype.destory = function() {
|
912
|
+
if(this.scope) {
|
913
|
+
this.scope.destory && this.scope.destory();
|
914
|
+
this.scope = null;
|
915
|
+
}
|
916
|
+
};
|
917
|
+
|
918
|
+
function createViewId(stateId) {
|
919
|
+
return ionic.Utils.nextUid();
|
920
|
+
}
|
921
|
+
|
922
|
+
return {
|
923
|
+
|
924
|
+
register: function(containerScope, element) {
|
925
|
+
|
926
|
+
var viewHistory = $rootScope.$viewHistory,
|
927
|
+
currentStateId = this.getCurrentStateId(),
|
928
|
+
hist = this._getHistory(containerScope),
|
929
|
+
currentView = viewHistory.currentView,
|
930
|
+
backView = viewHistory.backView,
|
931
|
+
forwardView = viewHistory.forwardView,
|
932
|
+
rsp = {
|
933
|
+
viewId: null,
|
934
|
+
navAction: null,
|
935
|
+
navDirection: null,
|
936
|
+
historyId: hist.historyId
|
937
|
+
};
|
938
|
+
|
939
|
+
if(element && !this.isTagNameRegistrable(element)) {
|
940
|
+
// first check to see if this element can even be registered as a view.
|
941
|
+
// Certain tags are only containers for views, but are not views themselves.
|
942
|
+
// For example, the <ion-tabs> directive contains a <ion-tab> and the <ion-tab> is the
|
943
|
+
// view, but the <ion-tabs> directive itself should not be registered as a view.
|
944
|
+
rsp.navAction = 'disabledByTagName';
|
945
|
+
return rsp;
|
946
|
+
}
|
947
|
+
|
948
|
+
if(currentView &&
|
949
|
+
currentView.stateId === currentStateId &&
|
950
|
+
currentView.historyId === hist.historyId) {
|
951
|
+
// do nothing if its the same stateId in the same history
|
952
|
+
rsp.navAction = 'noChange';
|
953
|
+
return rsp;
|
954
|
+
}
|
955
|
+
|
956
|
+
if(viewHistory.forcedNav) {
|
957
|
+
// we've previously set exactly what to do
|
958
|
+
ionic.Utils.extend(rsp, viewHistory.forcedNav);
|
959
|
+
$rootScope.$viewHistory.forcedNav = null;
|
960
|
+
|
961
|
+
} else if(backView && backView.stateId === currentStateId) {
|
962
|
+
// they went back one, set the old current view as a forward view
|
963
|
+
rsp.viewId = backView.viewId;
|
964
|
+
rsp.navAction = 'moveBack';
|
965
|
+
currentView.scrollValues = {}; //when going back, erase scrollValues
|
966
|
+
if(backView.historyId === currentView.historyId) {
|
967
|
+
// went back in the same history
|
968
|
+
rsp.navDirection = 'back';
|
969
|
+
}
|
970
|
+
|
971
|
+
} else if(forwardView && forwardView.stateId === currentStateId) {
|
972
|
+
// they went to the forward one, set the forward view to no longer a forward view
|
973
|
+
rsp.viewId = forwardView.viewId;
|
974
|
+
rsp.navAction = 'moveForward';
|
975
|
+
if(forwardView.historyId === currentView.historyId) {
|
976
|
+
rsp.navDirection = 'forward';
|
977
|
+
}
|
978
|
+
|
979
|
+
var parentHistory = this._getParentHistoryObj(containerScope);
|
980
|
+
if(forwardView.historyId && parentHistory.scope) {
|
981
|
+
// if a history has already been created by the forward view then make sure it stays the same
|
982
|
+
parentHistory.scope.$historyId = forwardView.historyId;
|
983
|
+
rsp.historyId = forwardView.historyId;
|
984
|
+
}
|
985
|
+
|
986
|
+
} else if(currentView && currentView.historyId !== hist.historyId &&
|
987
|
+
hist.cursor > -1 && hist.stack.length > 0 && hist.cursor < hist.stack.length &&
|
988
|
+
hist.stack[hist.cursor].stateId === currentStateId) {
|
989
|
+
// they just changed to a different history and the history already has views in it
|
990
|
+
rsp.viewId = hist.stack[hist.cursor].viewId;
|
991
|
+
rsp.navAction = 'moveBack';
|
992
|
+
|
993
|
+
} else {
|
994
|
+
|
995
|
+
// set a new unique viewId
|
996
|
+
rsp.viewId = createViewId(currentStateId);
|
997
|
+
|
998
|
+
if(currentView) {
|
999
|
+
// set the forward view if there is a current view (ie: if its not the first view)
|
1000
|
+
currentView.forwardViewId = rsp.viewId;
|
1001
|
+
|
1002
|
+
// its only moving forward if its in the same history
|
1003
|
+
if(hist.historyId === currentView.historyId) {
|
1004
|
+
rsp.navDirection = 'forward';
|
1005
|
+
}
|
1006
|
+
rsp.navAction = 'newView';
|
1007
|
+
|
1008
|
+
// check if there is a new forward view
|
1009
|
+
if(forwardView && currentView.stateId !== forwardView.stateId) {
|
1010
|
+
// they navigated to a new view but the stack already has a forward view
|
1011
|
+
// since its a new view remove any forwards that existed
|
1012
|
+
var forwardsHistory = this._getView(forwardView.historyId);
|
1013
|
+
if(forwardsHistory) {
|
1014
|
+
// the forward has a history
|
1015
|
+
for(var x=forwardsHistory.stack.length - 1; x >= forwardView.index; x--) {
|
1016
|
+
// starting from the end destory all forwards in this history from this point
|
1017
|
+
forwardsHistory.stack[x].destory();
|
1018
|
+
forwardsHistory.stack.splice(x);
|
1019
|
+
}
|
1020
|
+
}
|
1021
|
+
}
|
1022
|
+
|
1023
|
+
} else {
|
1024
|
+
// there's no current view, so this must be the initial view
|
1025
|
+
rsp.navAction = 'initialView';
|
1026
|
+
}
|
1027
|
+
|
1028
|
+
// add the new view to the stack
|
1029
|
+
viewHistory.histories[rsp.viewId] = this.createView({
|
1030
|
+
viewId: rsp.viewId,
|
1031
|
+
index: hist.stack.length,
|
1032
|
+
historyId: hist.historyId,
|
1033
|
+
backViewId: (currentView && currentView.viewId ? currentView.viewId : null),
|
1034
|
+
forwardViewId: null,
|
1035
|
+
stateId: currentStateId,
|
1036
|
+
stateName: this.getCurrentStateName(),
|
1037
|
+
stateParams: this.getCurrentStateParams(),
|
1038
|
+
url: $location.url(),
|
1039
|
+
scrollValues: null
|
1040
|
+
});
|
1041
|
+
|
1042
|
+
// add the new view to this history's stack
|
1043
|
+
hist.stack.push(viewHistory.histories[rsp.viewId]);
|
1044
|
+
}
|
1045
|
+
|
1046
|
+
this.setNavViews(rsp.viewId);
|
1047
|
+
|
1048
|
+
hist.cursor = viewHistory.currentView.index;
|
1049
|
+
|
1050
|
+
return rsp;
|
1051
|
+
},
|
1052
|
+
|
1053
|
+
setNavViews: function(viewId) {
|
1054
|
+
var viewHistory = $rootScope.$viewHistory;
|
1055
|
+
|
1056
|
+
viewHistory.currentView = this._getView(viewId);
|
1057
|
+
viewHistory.backView = this._getBackView(viewHistory.currentView);
|
1058
|
+
viewHistory.forwardView = this._getForwardView(viewHistory.currentView);
|
1059
|
+
|
1060
|
+
$rootScope.$broadcast('$viewHistory.historyChange', {
|
1061
|
+
showBack: (viewHistory.backView && viewHistory.backView.historyId === viewHistory.currentView.historyId)
|
1062
|
+
});
|
1063
|
+
},
|
1064
|
+
|
1065
|
+
registerHistory: function(scope) {
|
1066
|
+
scope.$historyId = ionic.Utils.nextUid();
|
1067
|
+
},
|
1068
|
+
|
1069
|
+
createView: function(data) {
|
1070
|
+
var newView = new View();
|
1071
|
+
return newView.initialize(data);
|
1072
|
+
},
|
1073
|
+
|
1074
|
+
getCurrentView: function() {
|
1075
|
+
return $rootScope.$viewHistory.currentView;
|
1076
|
+
},
|
1077
|
+
|
1078
|
+
getBackView: function() {
|
1079
|
+
return $rootScope.$viewHistory.backView;
|
1080
|
+
},
|
1081
|
+
|
1082
|
+
getForwardView: function() {
|
1083
|
+
return $rootScope.$viewHistory.forwardView;
|
1084
|
+
},
|
1085
|
+
|
1086
|
+
getNavDirection: function() {
|
1087
|
+
return $rootScope.$viewHistory.navDirection;
|
1088
|
+
},
|
1089
|
+
|
1090
|
+
getCurrentStateName: function() {
|
1091
|
+
return ($state && $state.current ? $state.current.name : null);
|
1092
|
+
},
|
1093
|
+
|
1094
|
+
isCurrentStateNavView: function(navView) {
|
1095
|
+
return ($state &&
|
1096
|
+
$state.current &&
|
1097
|
+
$state.current.views &&
|
1098
|
+
$state.current.views[navView] ? true : false);
|
1099
|
+
},
|
1100
|
+
|
1101
|
+
getCurrentStateParams: function() {
|
1102
|
+
var rtn;
|
1103
|
+
if ($state && $state.params) {
|
1104
|
+
for(var key in $state.params) {
|
1105
|
+
if($state.params.hasOwnProperty(key)) {
|
1106
|
+
rtn = rtn || {};
|
1107
|
+
rtn[key] = $state.params[key];
|
1108
|
+
}
|
1109
|
+
}
|
1110
|
+
}
|
1111
|
+
return rtn;
|
1112
|
+
},
|
1113
|
+
|
1114
|
+
getCurrentStateId: function() {
|
1115
|
+
var id;
|
1116
|
+
if($state && $state.current && $state.current.name) {
|
1117
|
+
id = $state.current.name;
|
1118
|
+
if($state.params) {
|
1119
|
+
for(var key in $state.params) {
|
1120
|
+
if($state.params.hasOwnProperty(key) && $state.params[key]) {
|
1121
|
+
id += "_" + key + "=" + $state.params[key];
|
1122
|
+
}
|
1123
|
+
}
|
1124
|
+
}
|
1125
|
+
return id;
|
1126
|
+
}
|
1127
|
+
// if something goes wrong make sure its got a unique stateId
|
1128
|
+
return ionic.Utils.nextUid();
|
1129
|
+
},
|
1130
|
+
|
1131
|
+
goToHistoryRoot: function(historyId) {
|
1132
|
+
if(historyId) {
|
1133
|
+
var hist = $rootScope.$viewHistory.histories[ historyId ];
|
1134
|
+
if(hist && hist.stack.length) {
|
1135
|
+
if($rootScope.$viewHistory.currentView && $rootScope.$viewHistory.currentView.viewId === hist.stack[0].viewId) {
|
1136
|
+
return;
|
1137
|
+
}
|
1138
|
+
$rootScope.$viewHistory.forcedNav = {
|
1139
|
+
viewId: hist.stack[0].viewId,
|
1140
|
+
navAction: 'moveBack',
|
1141
|
+
navDirection: 'back'
|
1142
|
+
};
|
1143
|
+
hist.stack[0].go();
|
1144
|
+
}
|
1145
|
+
}
|
1146
|
+
},
|
1147
|
+
|
1148
|
+
_getView: function(viewId) {
|
1149
|
+
return (viewId ? $rootScope.$viewHistory.histories[ viewId ] : null );
|
1150
|
+
},
|
1151
|
+
|
1152
|
+
_getBackView: function(view) {
|
1153
|
+
return (view ? this._getView(view.backViewId) : null );
|
1154
|
+
},
|
1155
|
+
|
1156
|
+
_getForwardView: function(view) {
|
1157
|
+
return (view ? this._getView(view.forwardViewId) : null );
|
1158
|
+
},
|
1159
|
+
|
1160
|
+
_getHistory: function(scope) {
|
1161
|
+
var histObj = this._getParentHistoryObj(scope);
|
1162
|
+
|
1163
|
+
if( !$rootScope.$viewHistory.histories[ histObj.historyId ] ) {
|
1164
|
+
// this history object exists in parent scope, but doesn't
|
1165
|
+
// exist in the history data yet
|
1166
|
+
$rootScope.$viewHistory.histories[ histObj.historyId ] = {
|
1167
|
+
historyId: histObj.historyId,
|
1168
|
+
parentHistoryId: this._getParentHistoryObj(histObj.scope.$parent).historyId,
|
1169
|
+
stack: [],
|
1170
|
+
cursor: -1
|
1171
|
+
};
|
1172
|
+
}
|
1173
|
+
|
1174
|
+
return $rootScope.$viewHistory.histories[ histObj.historyId ];
|
1175
|
+
},
|
1176
|
+
|
1177
|
+
_getParentHistoryObj: function(scope) {
|
1178
|
+
var parentScope = scope;
|
1179
|
+
while(parentScope) {
|
1180
|
+
if(parentScope.hasOwnProperty('$historyId')) {
|
1181
|
+
// this parent scope has a historyId
|
1182
|
+
return { historyId: parentScope.$historyId, scope: parentScope };
|
1183
|
+
}
|
1184
|
+
// nothing found keep climbing up
|
1185
|
+
parentScope = parentScope.$parent;
|
1186
|
+
}
|
1187
|
+
// no history for for the parent, use the root
|
1188
|
+
return { historyId: 'root', scope: $rootScope };
|
1189
|
+
},
|
1190
|
+
|
1191
|
+
getRenderer: function(navViewElement, navViewAttrs, navViewScope) {
|
1192
|
+
var service = this;
|
1193
|
+
var registerData;
|
1194
|
+
var doAnimation;
|
1195
|
+
|
1196
|
+
// climb up the DOM and see which animation classname to use, if any
|
1197
|
+
var animationClass = angular.isDefined(navViewScope.$nextAnimation) ?
|
1198
|
+
navViewScope.$nextAnimation :
|
1199
|
+
getParentAnimationClass(navViewElement[0]);
|
1200
|
+
|
1201
|
+
navViewScope.$nextAnimation = undefined;
|
1202
|
+
|
1203
|
+
function getParentAnimationClass(el) {
|
1204
|
+
var className = '';
|
1205
|
+
while(!className && el) {
|
1206
|
+
className = el.getAttribute('animation');
|
1207
|
+
el = el.parentElement;
|
1208
|
+
}
|
1209
|
+
return className;
|
1210
|
+
}
|
1211
|
+
|
1212
|
+
function setAnimationClass() {
|
1213
|
+
// add the animation CSS class we're gonna use to transition between views
|
1214
|
+
if (animationClass) {
|
1215
|
+
navViewElement[0].classList.add(animationClass);
|
1216
|
+
}
|
1217
|
+
|
1218
|
+
if(registerData.navDirection === 'back') {
|
1219
|
+
// animate like we're moving backward
|
1220
|
+
navViewElement[0].classList.add('reverse');
|
1221
|
+
} else {
|
1222
|
+
// defaults to animate forward
|
1223
|
+
// make sure the reverse class isn't already added
|
1224
|
+
navViewElement[0].classList.remove('reverse');
|
1225
|
+
}
|
1226
|
+
}
|
1227
|
+
|
1228
|
+
return function(shouldAnimate) {
|
1229
|
+
|
1230
|
+
return {
|
1231
|
+
|
1232
|
+
enter: function(element) {
|
1233
|
+
|
1234
|
+
if(doAnimation && shouldAnimate) {
|
1235
|
+
// enter with an animation
|
1236
|
+
setAnimationClass();
|
1237
|
+
|
1238
|
+
element.addClass('ng-enter');
|
1239
|
+
document.body.classList.add('disable-pointer-events');
|
1240
|
+
|
1241
|
+
$animate.enter(element, navViewElement, null, function() {
|
1242
|
+
document.body.classList.remove('disable-pointer-events');
|
1243
|
+
if (animationClass) {
|
1244
|
+
navViewElement[0].classList.remove(animationClass);
|
1245
|
+
}
|
1246
|
+
});
|
1247
|
+
return;
|
1248
|
+
}
|
1249
|
+
|
1250
|
+
// no animation
|
1251
|
+
navViewElement.append(element);
|
1252
|
+
},
|
1253
|
+
|
1254
|
+
leave: function() {
|
1255
|
+
var element = navViewElement.contents();
|
1256
|
+
|
1257
|
+
if(doAnimation && shouldAnimate) {
|
1258
|
+
// leave with an animation
|
1259
|
+
setAnimationClass();
|
1260
|
+
|
1261
|
+
$animate.leave(element, function() {
|
1262
|
+
element.remove();
|
1263
|
+
});
|
1264
|
+
return;
|
1265
|
+
}
|
1266
|
+
|
1267
|
+
// no animation
|
1268
|
+
element.remove();
|
1269
|
+
},
|
1270
|
+
|
1271
|
+
register: function(element) {
|
1272
|
+
// register a new view
|
1273
|
+
registerData = service.register(navViewScope, element);
|
1274
|
+
doAnimation = (animationClass !== null && registerData.navDirection !== null);
|
1275
|
+
return registerData;
|
1276
|
+
}
|
1277
|
+
|
1278
|
+
};
|
1279
|
+
};
|
1280
|
+
},
|
1281
|
+
|
1282
|
+
disableRegisterByTagName: function(tagName) {
|
1283
|
+
// not every element should animate betwee transitions
|
1284
|
+
// For example, the <ion-tabs> directive should not animate when it enters,
|
1285
|
+
// but instead the <ion-tabs> directve would just show, and its children
|
1286
|
+
// <ion-tab> directives would do the animating, but <ion-tabs> itself is not a view
|
1287
|
+
$rootScope.$viewHistory.disabledRegistrableTagNames.push(tagName.toUpperCase());
|
1288
|
+
},
|
1289
|
+
|
1290
|
+
isTagNameRegistrable: function(element) {
|
1291
|
+
// check if this element has a tagName (at its root, not recursively)
|
1292
|
+
// that shouldn't be animated, like <ion-tabs> or <ion-side-menu>
|
1293
|
+
var x, y, disabledTags = $rootScope.$viewHistory.disabledRegistrableTagNames;
|
1294
|
+
for(x=0; x<element.length; x++) {
|
1295
|
+
if(element[x].nodeType !== 1) continue;
|
1296
|
+
for(y=0; y<disabledTags.length; y++) {
|
1297
|
+
if(element[x].tagName === disabledTags[y]) {
|
1298
|
+
return false;
|
1299
|
+
}
|
1300
|
+
}
|
1301
|
+
}
|
1302
|
+
return true;
|
1303
|
+
},
|
1304
|
+
|
1305
|
+
clearHistory: function() {
|
1306
|
+
var historyId, x, view,
|
1307
|
+
histories = $rootScope.$viewHistory.histories,
|
1308
|
+
currentView = $rootScope.$viewHistory.currentView;
|
1309
|
+
|
1310
|
+
for(historyId in histories) {
|
1311
|
+
|
1312
|
+
if(histories[historyId].stack) {
|
1313
|
+
histories[historyId].stack = [];
|
1314
|
+
histories[historyId].cursor = -1;
|
1315
|
+
}
|
1316
|
+
|
1317
|
+
if(currentView.historyId === historyId) {
|
1318
|
+
currentView.backViewId = null;
|
1319
|
+
currentView.forwardViewId = null;
|
1320
|
+
histories[historyId].stack.push(currentView);
|
1321
|
+
} else if(histories[historyId].destroy) {
|
1322
|
+
histories[historyId].destroy();
|
1323
|
+
}
|
1324
|
+
|
1325
|
+
}
|
1326
|
+
|
1327
|
+
this.setNavViews(currentView.viewId);
|
1328
|
+
}
|
1329
|
+
|
1330
|
+
};
|
1331
|
+
|
1332
|
+
}]);
|
1333
|
+
;
|
1334
|
+
angular.module('ionic.ui.navAnimation', [])
|
1335
|
+
.directive('ionNavAnimation', function() {
|
1336
|
+
return {
|
1337
|
+
restrict: 'A',
|
1338
|
+
require: '^?ionNavView',
|
1339
|
+
link: function($scope, $element, $attrs, navViewCtrl) {
|
1340
|
+
if (!navViewCtrl) {
|
1341
|
+
return;
|
1342
|
+
}
|
1343
|
+
ionic.on('tap', function() {
|
1344
|
+
navViewCtrl.setNextAnimation($attrs.ionNavAnimation);
|
1345
|
+
}, $element[0]);
|
1346
|
+
}
|
1347
|
+
};
|
1348
|
+
});
|
1349
|
+
;
|
1350
|
+
(function() {
|
1351
|
+
'use strict';
|
1352
|
+
|
1353
|
+
angular.module('ionic.ui.actionSheet', [])
|
1354
|
+
|
1355
|
+
.directive('ionActionSheet', ['$document', function($document) {
|
1356
|
+
return {
|
1357
|
+
restrict: 'E',
|
1358
|
+
scope: true,
|
1359
|
+
replace: true,
|
1360
|
+
link: function($scope, $element){
|
1361
|
+
var keyUp = function(e) {
|
1362
|
+
if(e.which == 27) {
|
1363
|
+
$scope.cancel();
|
1364
|
+
$scope.$apply();
|
1365
|
+
}
|
1366
|
+
};
|
1367
|
+
|
1368
|
+
var backdropClick = function(e) {
|
1369
|
+
if(e.target == $element[0]) {
|
1370
|
+
$scope.cancel();
|
1371
|
+
$scope.$apply();
|
1372
|
+
}
|
1373
|
+
};
|
1374
|
+
$scope.$on('$destroy', function() {
|
1375
|
+
$element.remove();
|
1376
|
+
$document.unbind('keyup', keyUp);
|
1377
|
+
});
|
1378
|
+
|
1379
|
+
$document.bind('keyup', keyUp);
|
1380
|
+
$element.bind('click', backdropClick);
|
1381
|
+
},
|
1382
|
+
template: '<div class="action-sheet-backdrop">' +
|
1383
|
+
'<div class="action-sheet-wrapper action-sheet-up">' +
|
1384
|
+
'<div class="action-sheet">' +
|
1385
|
+
'<div class="action-sheet-group">' +
|
1386
|
+
'<div class="action-sheet-title" ng-if="titleText">{{titleText}}</div>' +
|
1387
|
+
'<button class="button" ng-click="buttonClicked($index)" ng-repeat="button in buttons">{{button.text}}</button>' +
|
1388
|
+
'</div>' +
|
1389
|
+
'<div class="action-sheet-group" ng-if="destructiveText">' +
|
1390
|
+
'<button class="button destructive" ng-click="destructiveButtonClicked()">{{destructiveText}}</button>' +
|
1391
|
+
'</div>' +
|
1392
|
+
'<div class="action-sheet-group" ng-if="cancelText">' +
|
1393
|
+
'<button class="button" ng-click="cancel()">{{cancelText}}</button>' +
|
1394
|
+
'</div>' +
|
1395
|
+
'</div>' +
|
1396
|
+
'</div>' +
|
1397
|
+
'</div>'
|
1398
|
+
};
|
1399
|
+
}]);
|
1400
|
+
|
1401
|
+
})();
|
1402
|
+
;
|
1403
|
+
(function(ionic) {
|
1404
|
+
'use strict';
|
1405
|
+
|
1406
|
+
angular.module('ionic.ui.header', ['ngAnimate', 'ngSanitize'])
|
1407
|
+
|
1408
|
+
.directive('barHeader', ['$ionicScrollDelegate', function($ionicScrollDelegate) {
|
1409
|
+
return {
|
1410
|
+
restrict: 'C',
|
1411
|
+
link: function($scope, $element, $attr) {
|
1412
|
+
// We want to scroll to top when the top of this element is clicked
|
1413
|
+
$ionicScrollDelegate.tapScrollToTop($element);
|
1414
|
+
}
|
1415
|
+
};
|
1416
|
+
}])
|
1417
|
+
|
1418
|
+
.directive('ionHeaderBar', ['$ionicScrollDelegate', function($ionicScrollDelegate) {
|
1419
|
+
return {
|
1420
|
+
restrict: 'E',
|
1421
|
+
replace: true,
|
1422
|
+
transclude: true,
|
1423
|
+
template: '<header class="bar bar-header">\
|
1424
|
+
<div class="buttons">\
|
1425
|
+
<button ng-repeat="button in leftButtons" class="button no-animation" ng-class="button.type" ng-click="button.tap($event, $index)" ng-bind-html="button.content">\
|
1426
|
+
</button>\
|
1427
|
+
</div>\
|
1428
|
+
<h1 class="title" ng-bind-html="title"></h1>\
|
516
1429
|
<div class="buttons">\
|
517
1430
|
<button ng-repeat="button in rightButtons" class="button no-animation" ng-class="button.type" ng-click="button.tap($event, $index)" ng-bind-html="button.content">\
|
518
1431
|
</button>\
|
@@ -543,7 +1456,6 @@ angular.module('ionic.ui.header', ['ngAnimate'])
|
|
543
1456
|
});
|
544
1457
|
|
545
1458
|
$scope.$watch('rightButtons', function(val) {
|
546
|
-
console.log('Right buttons changed');
|
547
1459
|
// Resize the title since the buttons have changed
|
548
1460
|
hb.align();
|
549
1461
|
});
|
@@ -554,9 +1466,9 @@ angular.module('ionic.ui.header', ['ngAnimate'])
|
|
554
1466
|
});
|
555
1467
|
}
|
556
1468
|
};
|
557
|
-
})
|
1469
|
+
}])
|
558
1470
|
|
559
|
-
.directive('
|
1471
|
+
.directive('ionFooterBar', function() {
|
560
1472
|
return {
|
561
1473
|
restrict: 'E',
|
562
1474
|
replace: true,
|
@@ -582,43 +1494,34 @@ angular.module('ionic.ui.header', ['ngAnimate'])
|
|
582
1494
|
angular.module('ionic.ui.checkbox', [])
|
583
1495
|
|
584
1496
|
|
585
|
-
.directive('
|
1497
|
+
.directive('ionCheckbox', function() {
|
586
1498
|
return {
|
587
1499
|
restrict: 'E',
|
588
1500
|
replace: true,
|
589
1501
|
require: '?ngModel',
|
590
|
-
scope: {
|
1502
|
+
scope: {
|
1503
|
+
ngModel: '=?',
|
1504
|
+
ngValue: '=?',
|
1505
|
+
ngChecked: '=?',
|
1506
|
+
ngChange: '&'
|
1507
|
+
},
|
591
1508
|
transclude: true,
|
592
|
-
template: '<li class="item item-checkbox">\
|
593
|
-
<label class="checkbox">\
|
594
|
-
<input type="checkbox">\
|
595
|
-
</label>\
|
596
|
-
<div class="item-content" ng-transclude>\
|
597
|
-
</div>\
|
598
|
-
</li>',
|
599
1509
|
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
});
|
614
|
-
});
|
615
|
-
|
616
|
-
if(ngModel) {
|
617
|
-
ngModel.$render = function() {
|
618
|
-
checkbox[0].checked = ngModel.$viewValue;
|
619
|
-
};
|
620
|
-
}
|
1510
|
+
template: '<div class="item item-checkbox disable-pointer-events">' +
|
1511
|
+
'<label class="checkbox enable-pointer-events">' +
|
1512
|
+
'<input type="checkbox" ng-model="ngModel" ng-value="ngValue" ng-change="ngChange()">' +
|
1513
|
+
'</label>' +
|
1514
|
+
'<div class="item-content" ng-transclude></div>' +
|
1515
|
+
'</div>',
|
1516
|
+
|
1517
|
+
compile: function(element, attr) {
|
1518
|
+
var input = element.find('input');
|
1519
|
+
if(attr.name) input.attr('name', attr.name);
|
1520
|
+
if(attr.ngChecked) input.attr('ng-checked', 'ngChecked');
|
1521
|
+
if(attr.ngTrueValue) input.attr('ng-true-value', attr.ngTrueValue);
|
1522
|
+
if(attr.ngFalseValue) input.attr('ng-false-value', attr.ngFalseValue);
|
621
1523
|
}
|
1524
|
+
|
622
1525
|
};
|
623
1526
|
});
|
624
1527
|
|
@@ -627,13 +1530,13 @@ angular.module('ionic.ui.checkbox', [])
|
|
627
1530
|
(function() {
|
628
1531
|
'use strict';
|
629
1532
|
|
630
|
-
angular.module('ionic.ui.content', [])
|
1533
|
+
angular.module('ionic.ui.content', ['ionic.ui.service', 'ionic.ui.scroll'])
|
631
1534
|
|
632
1535
|
/**
|
633
1536
|
* Panel is a simple 100% width and height, fixed panel. It's meant for content to be
|
634
1537
|
* added to it, or animated around.
|
635
1538
|
*/
|
636
|
-
.directive('
|
1539
|
+
.directive('ionPane', function() {
|
637
1540
|
return {
|
638
1541
|
restrict: 'E',
|
639
1542
|
link: function(scope, element, attr) {
|
@@ -642,160 +1545,219 @@ angular.module('ionic.ui.content', [])
|
|
642
1545
|
};
|
643
1546
|
})
|
644
1547
|
|
645
|
-
|
646
|
-
|
647
|
-
|
1548
|
+
/*
|
1549
|
+
* @ngdoc directive
|
1550
|
+
* @name ionContent
|
1551
|
+
*
|
1552
|
+
* @description
|
1553
|
+
* The ionContent directive provides an easy to use content area that can be configured to use
|
1554
|
+
* Ionic's custom Scroll View, or the built in overflow scorlling of the browser.
|
1555
|
+
*
|
1556
|
+
* While we recommend using the custom Scroll features in Ionic in most cases, sometimes (for performance reasons) only the browser's native overflow scrolling will suffice, and so we've made it easy to toggle between the Ionic scroll implementation and overflow scrolling.
|
1557
|
+
*
|
1558
|
+
* When using the Ionic scroll features, you'll get pull-to-refresh, customizable scroll mechanics (like bounce easing, momentum acceleration, etc.) which aligns Ionic with native SDKs that give you access to scroll behavior. You'll also get events while in a momentum scroll, which -webkit-overflow-scrolling: touch will not, making it of limited use in real applications.
|
1559
|
+
*
|
1560
|
+
* Also, we are working on virtual list rendering which will only work when using Ionic's scroll view. That is on the upcoming roadmap.
|
1561
|
+
*
|
1562
|
+
* @restrict E
|
1563
|
+
* @param {boolean=} scroll Whether to allow scrolling of content. Defaults to true.
|
1564
|
+
* @param {boolean=} overflow-scroll Whether to use overflow-scrolling instead of Ionic scroll.
|
1565
|
+
* @param {boolean=} padding Whether to add padding to the content.
|
1566
|
+
* @param {boolean=} has-header Whether to offset the content for a header bar.
|
1567
|
+
* @param {boolean=} has-subheader Whether to offset the content for a subheader bar.
|
1568
|
+
* @param {boolean=} has-footer Whether to offset the content for a footer bar.
|
1569
|
+
* @param {boolean=} has-bouncing Whether to allow scrolling to bounce past the edges of the content. Defaults to true on iOS, false on Android.
|
1570
|
+
* @param {expression=} on-refresh Expression to evaluate on refresh completion.
|
1571
|
+
* @param {expression=} on-refresh-opening Expression to evaluate on refresh opening.
|
1572
|
+
* @param {expression=} on-scroll Expression to evaluate when the content is scrolled.
|
1573
|
+
* @param {expression=} on-scroll-complete Expression to evaluate when a scroll action completes.
|
1574
|
+
*/
|
1575
|
+
.directive('ionContent', [
|
1576
|
+
'$parse',
|
1577
|
+
'$timeout',
|
1578
|
+
'$ionicScrollDelegate',
|
1579
|
+
'$controller',
|
1580
|
+
'$ionicBind',
|
1581
|
+
function($parse, $timeout, $ionicScrollDelegate, $controller, $ionicBind) {
|
648
1582
|
return {
|
649
1583
|
restrict: 'E',
|
650
1584
|
replace: true,
|
651
|
-
template: '<div class="scroll-content"></div>',
|
652
1585
|
transclude: true,
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
scroll: '@',
|
660
|
-
hasScrollX: '@',
|
661
|
-
hasScrollY: '@',
|
662
|
-
scrollbarX: '@',
|
663
|
-
scrollbarY: '@',
|
664
|
-
scrollEventInterval: '@'
|
665
|
-
},
|
1586
|
+
require: '^?ionNavView',
|
1587
|
+
scope: true,
|
1588
|
+
template:
|
1589
|
+
'<div class="scroll-content">' +
|
1590
|
+
'<div class="scroll"></div>' +
|
1591
|
+
'</div>',
|
666
1592
|
compile: function(element, attr, transclude) {
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
if(attr.hasHeader == "true") { c.addClass('has-header'); }
|
673
|
-
if(attr.hasSubheader == "true") { c.addClass('has-subheader'); }
|
674
|
-
if(attr.hasFooter == "true") { c.addClass('has-footer'); }
|
675
|
-
if(attr.hasTabs == "true") { c.addClass('has-tabs'); }
|
1593
|
+
if(attr.hasHeader == "true") { element.addClass('has-header'); }
|
1594
|
+
if(attr.hasSubheader == "true") { element.addClass('has-subheader'); }
|
1595
|
+
if(attr.hasFooter == "true") { element.addClass('has-footer'); }
|
1596
|
+
if(attr.hasTabs == "true") { element.addClass('has-tabs'); }
|
1597
|
+
if(attr.padding == "true") { element.find('div').addClass('padding'); }
|
676
1598
|
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
c.addClass('overflow-scroll');
|
683
|
-
clone = transclude($scope.$parent);
|
684
|
-
$element.append(clone);
|
685
|
-
} else {
|
686
|
-
sc = document.createElement('div');
|
687
|
-
sc.className = 'scroll';
|
688
|
-
if(attr.padding == "true") {
|
689
|
-
sc.className += ' padding';
|
690
|
-
addedPadding = true;
|
691
|
-
}
|
692
|
-
$element.append(sc);
|
1599
|
+
return {
|
1600
|
+
//Prelink <ion-content> so it can compile before other directives compile.
|
1601
|
+
//Then other directives can require ionicScrollCtrl
|
1602
|
+
pre: prelink
|
1603
|
+
};
|
693
1604
|
|
694
|
-
|
695
|
-
|
696
|
-
angular.element($element[0].
|
1605
|
+
function prelink($scope, $element, $attr, navViewCtrl) {
|
1606
|
+
var clone, sc, scrollView, scrollCtrl,
|
1607
|
+
scrollContent = angular.element($element[0].querySelector('.scroll'));
|
697
1608
|
|
698
|
-
|
699
|
-
|
1609
|
+
transclude($scope, function(clone) {
|
1610
|
+
scrollContent.append(clone);
|
1611
|
+
});
|
700
1612
|
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
1613
|
+
$ionicBind($scope, $attr, {
|
1614
|
+
//Use $ to stop onRefresh from recursively calling itself
|
1615
|
+
$onRefresh: '&onRefresh',
|
1616
|
+
$onRefreshOpening: '&onRefreshOpening',
|
1617
|
+
$onScroll: '&onScroll',
|
1618
|
+
$onScrollComplete: '&onScrollComplete',
|
1619
|
+
$onInfiniteScroll: '&onInfiniteScroll',
|
1620
|
+
refreshComplete: '=',
|
1621
|
+
infiniteScrollDistance: '@',
|
1622
|
+
hasBouncing: '@',
|
1623
|
+
scroll: '@',
|
1624
|
+
padding: '@',
|
1625
|
+
hasScrollX: '@',
|
1626
|
+
hasScrollY: '@',
|
1627
|
+
scrollbarX: '@',
|
1628
|
+
scrollbarY: '@',
|
1629
|
+
startX: '@',
|
1630
|
+
startY: '@',
|
1631
|
+
scrollEventInterval: '@'
|
1632
|
+
});
|
710
1633
|
|
1634
|
+
if($scope.scroll === "false") {
|
1635
|
+
// No scrolling
|
1636
|
+
return;
|
1637
|
+
}
|
711
1638
|
|
712
|
-
|
713
|
-
$
|
714
|
-
|
715
|
-
|
716
|
-
scrollbarX: $scope.$eval($scope.scrollbarX) !== false,
|
717
|
-
scrollbarY: $scope.$eval($scope.scrollbarY) !== false,
|
718
|
-
scrollingX: $scope.$eval($scope.hasScrollX) === true,
|
719
|
-
scrollingY: $scope.$eval($scope.hasScrollY) !== false,
|
720
|
-
scrollEventInterval: parseInt($scope.scrollEventInterval, 10) || 20,
|
721
|
-
scrollingComplete: function() {
|
722
|
-
$scope.onScrollComplete({
|
723
|
-
scrollTop: this.__scrollTop,
|
724
|
-
scrollLeft: this.__scrollLeft
|
725
|
-
});
|
726
|
-
}
|
727
|
-
});
|
1639
|
+
if(attr.overflowScroll === "true") {
|
1640
|
+
$element.addClass('overflow-scroll');
|
1641
|
+
return;
|
1642
|
+
}
|
728
1643
|
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
1644
|
+
scrollCtrl = $controller('$ionicScroll', {
|
1645
|
+
$scope: $scope,
|
1646
|
+
scrollViewOptions: {
|
1647
|
+
el: $element[0],
|
1648
|
+
bouncing: $scope.$eval($scope.hasBouncing),
|
1649
|
+
startX: $scope.$eval($scope.startX) || 0,
|
1650
|
+
startY: $scope.$eval($scope.startY) || 0,
|
1651
|
+
scrollbarX: $scope.$eval($scope.scrollbarX) !== false,
|
1652
|
+
scrollbarY: $scope.$eval($scope.scrollbarY) !== false,
|
1653
|
+
scrollingX: $scope.$eval($scope.hasScrollX) === true,
|
1654
|
+
scrollingY: $scope.$eval($scope.hasScrollY) !== false,
|
1655
|
+
scrollEventInterval: parseInt($scope.scrollEventInterval, 10) || 20,
|
1656
|
+
scrollingComplete: function() {
|
1657
|
+
$scope.$onScrollComplete({
|
1658
|
+
scrollTop: this.__scrollTop,
|
1659
|
+
scrollLeft: this.__scrollLeft
|
740
1660
|
});
|
741
1661
|
}
|
1662
|
+
}
|
1663
|
+
});
|
742
1664
|
|
743
|
-
|
744
|
-
|
745
|
-
event: e,
|
746
|
-
scrollTop: e.detail ? e.detail.scrollTop : e.originalEvent ? e.originalEvent.detail.scrollTop : 0,
|
747
|
-
scrollLeft: e.detail ? e.detail.scrollLeft: e.originalEvent ? e.originalEvent.detail.scrollLeft : 0
|
748
|
-
});
|
749
|
-
});
|
1665
|
+
//Publish scrollView to parent so children can access it
|
1666
|
+
scrollView = $scope.$parent.scrollView = scrollCtrl.scrollView;
|
750
1667
|
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
1668
|
+
$scope.$on('$viewContentLoaded', function(e, viewHistoryData) {
|
1669
|
+
viewHistoryData || (viewHistoryData = {});
|
1670
|
+
var scroll = viewHistoryData.scrollValues;
|
1671
|
+
if (scroll) {
|
1672
|
+
$timeout(function() {
|
1673
|
+
scrollView.scrollTo(+scroll.left || null, +scroll.top || null);
|
1674
|
+
}, 0);
|
1675
|
+
}
|
757
1676
|
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
// Let child scopes access this
|
763
|
-
$scope.$parent.scrollView = sv;
|
1677
|
+
//Save scroll onto viewHistoryData when scope is destroyed
|
1678
|
+
$scope.$on('$destroy', function() {
|
1679
|
+
viewHistoryData.scrollValues = scrollView.getValues();
|
764
1680
|
});
|
1681
|
+
});
|
765
1682
|
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
1683
|
+
if(attr.refreshComplete) {
|
1684
|
+
$scope.refreshComplete = function() {
|
1685
|
+
if($scope.scrollView) {
|
1686
|
+
scrollCtrl.refresher && scrollCtrl.refresher.classList.remove('active');
|
1687
|
+
scrollView.finishPullToRefresh();
|
1688
|
+
$scope.$parent.$broadcast('scroll.onRefreshComplete');
|
1689
|
+
}
|
1690
|
+
};
|
773
1691
|
}
|
774
|
-
|
775
|
-
};
|
1692
|
+
}
|
776
1693
|
}
|
777
1694
|
};
|
778
1695
|
}])
|
779
1696
|
|
780
|
-
.directive('
|
1697
|
+
.directive('ionRefresher', function() {
|
781
1698
|
return {
|
782
1699
|
restrict: 'E',
|
783
1700
|
replace: true,
|
784
|
-
require: ['^?
|
1701
|
+
require: ['^?ionContent', '^?ionList'],
|
785
1702
|
template: '<div class="scroll-refresher"><div class="ionic-refresher-content"><i class="icon ion-arrow-down-c icon-pulling"></i><i class="icon ion-loading-d icon-refreshing"></i></div></div>',
|
786
1703
|
scope: true
|
787
1704
|
};
|
788
1705
|
})
|
789
1706
|
|
790
|
-
.directive('
|
1707
|
+
.directive('ionScrollRefresher', function() {
|
791
1708
|
return {
|
792
1709
|
restrict: 'E',
|
793
1710
|
replace: true,
|
794
1711
|
transclude: true,
|
795
1712
|
template: '<div class="scroll-refresher"><div class="scroll-refresher-content" ng-transclude></div></div>'
|
796
1713
|
};
|
797
|
-
})
|
1714
|
+
})
|
1715
|
+
|
1716
|
+
.directive('ionInfiniteScroll', ['$ionicBind', function($ionicBind) {
|
1717
|
+
return {
|
1718
|
+
restrict: 'E',
|
1719
|
+
require: '^?$ionicScroll',
|
1720
|
+
template:
|
1721
|
+
'<div class="scroll-infinite">' +
|
1722
|
+
'<div class="scroll-infinite-content">' +
|
1723
|
+
'<i class="icon ion-loading-d icon-refreshing"></i>' +
|
1724
|
+
'</div>' +
|
1725
|
+
'</div>',
|
1726
|
+
link: function($scope, $element, $attrs, scrollCtrl) {
|
1727
|
+
setTimeout(function() {
|
1728
|
+
var scrollCtrl = $element.controller('$ionicScroll');
|
1729
|
+
var scrollView = scrollCtrl.scrollView;
|
798
1730
|
|
1731
|
+
$ionicBind($scope, $attrs, {
|
1732
|
+
distance: '@infiniteScrollDistance'
|
1733
|
+
});
|
1734
|
+
function maxScroll() {
|
1735
|
+
var dist = $scope.distance || '1%';
|
1736
|
+
return dist.indexOf('%') > -1 ?
|
1737
|
+
scrollView.getScrollMax().top * (1 - parseInt(dist,10) / 100) :
|
1738
|
+
scrollView.getScrollMax().top - parseInt(dist, 10);
|
1739
|
+
}
|
1740
|
+
|
1741
|
+
var infiniteScrolling = false;
|
1742
|
+
$scope.$on('scroll.infiniteScrollComplete', function() {
|
1743
|
+
$element[0].classList.remove('active');
|
1744
|
+
setTimeout(function() {
|
1745
|
+
scrollView.resize();
|
1746
|
+
});
|
1747
|
+
infiniteScrolling = false;
|
1748
|
+
});
|
1749
|
+
|
1750
|
+
scrollCtrl.$element.on('scroll', ionic.animationFrameThrottle(function() {
|
1751
|
+
if (!infiniteScrolling && scrollView.getValues().top >= maxScroll()) {
|
1752
|
+
$element[0].classList.add('active');
|
1753
|
+
infiniteScrolling = true;
|
1754
|
+
$scope.$apply(angular.bind($scope, $scope.$onInfiniteScroll));
|
1755
|
+
}
|
1756
|
+
}));
|
1757
|
+
});
|
1758
|
+
}
|
1759
|
+
};
|
1760
|
+
}]);
|
799
1761
|
|
800
1762
|
})();
|
801
1763
|
;
|
@@ -804,10 +1766,10 @@ angular.module('ionic.ui.content', [])
|
|
804
1766
|
|
805
1767
|
angular.module('ionic.ui.list', ['ngAnimate'])
|
806
1768
|
|
807
|
-
.directive('
|
1769
|
+
.directive('ionItem', ['$timeout', '$parse', function($timeout, $parse) {
|
808
1770
|
return {
|
809
1771
|
restrict: 'E',
|
810
|
-
require: '?^
|
1772
|
+
require: '?^ionList',
|
811
1773
|
replace: true,
|
812
1774
|
transclude: true,
|
813
1775
|
|
@@ -823,22 +1785,22 @@ angular.module('ionic.ui.list', ['ngAnimate'])
|
|
823
1785
|
reorderIcon: '@'
|
824
1786
|
},
|
825
1787
|
|
826
|
-
template: '<div class="item item-complex"
|
1788
|
+
template: '<div class="item item-complex">\
|
827
1789
|
<div class="item-edit" ng-if="deleteClick !== undefined">\
|
828
|
-
<button class="button button-icon icon" ng-class="deleteIconClass" ng-click="deleteClick()"></button>\
|
1790
|
+
<button class="button button-icon icon" ng-class="deleteIconClass" ng-click="deleteClick()" ion-stop-event="click"></button>\
|
829
1791
|
</div>\
|
830
1792
|
<a class="item-content" ng-href="{{ href }}" ng-transclude></a>\
|
831
1793
|
<div class="item-drag" ng-if="reorderIconClass !== undefined">\
|
832
1794
|
<button data-ionic-action="reorder" class="button button-icon icon" ng-class="reorderIconClass"></button>\
|
833
1795
|
</div>\
|
834
1796
|
<div class="item-options" ng-if="itemOptionButtons">\
|
835
|
-
<button ng-click="b.onTap(item, b)" class="button" ng-class="b.type" ng-repeat="b in itemOptionButtons" ng-bind="b.text"></button>\
|
1797
|
+
<button ng-click="b.onTap(item, b)" ion-stop-event="click" class="button" ng-class="b.type" ng-repeat="b in itemOptionButtons" ng-bind="b.text"></button>\
|
836
1798
|
</div>\
|
837
1799
|
</div>',
|
838
1800
|
|
839
1801
|
link: function($scope, $element, $attr, list) {
|
840
1802
|
if(!list) return;
|
841
|
-
|
1803
|
+
|
842
1804
|
var $parentScope = list.scope;
|
843
1805
|
var $parentAttrs = list.attrs;
|
844
1806
|
|
@@ -846,10 +1808,16 @@ angular.module('ionic.ui.list', ['ngAnimate'])
|
|
846
1808
|
if(value) $scope.href = value.trim();
|
847
1809
|
});
|
848
1810
|
|
1811
|
+
if(!$scope.itemType) {
|
1812
|
+
$scope.itemType = $parentScope.itemType;
|
1813
|
+
}
|
1814
|
+
|
849
1815
|
// Set this item's class, first from the item directive attr, and then the list attr if item not set
|
850
|
-
$
|
1816
|
+
$element.addClass($scope.itemType || $parentScope.itemType);
|
851
1817
|
|
852
|
-
|
1818
|
+
$scope.itemClass = $scope.itemType;
|
1819
|
+
|
1820
|
+
// Decide if this item can do stuff, and follow a certain priority
|
853
1821
|
// depending on where the value comes from
|
854
1822
|
if(($attr.canDelete ? $scope.canDelete : $parentScope.canDelete) !== "false") {
|
855
1823
|
if($attr.onDelete || $parentAttrs.onDelete) {
|
@@ -890,12 +1858,12 @@ angular.module('ionic.ui.list', ['ngAnimate'])
|
|
890
1858
|
};
|
891
1859
|
}])
|
892
1860
|
|
893
|
-
.directive('
|
1861
|
+
.directive('ionList', ['$timeout', function($timeout) {
|
894
1862
|
return {
|
895
1863
|
restrict: 'E',
|
896
1864
|
replace: true,
|
897
1865
|
transclude: true,
|
898
|
-
|
1866
|
+
require: '^?$ionicScroll',
|
899
1867
|
scope: {
|
900
1868
|
itemType: '@',
|
901
1869
|
canDelete: '@',
|
@@ -912,15 +1880,22 @@ angular.module('ionic.ui.list', ['ngAnimate'])
|
|
912
1880
|
|
913
1881
|
template: '<div class="list" ng-class="{\'list-editing\': showDelete, \'list-reordering\': showReorder}" ng-transclude></div>',
|
914
1882
|
|
915
|
-
controller: function($scope, $attrs) {
|
1883
|
+
controller: ['$scope', '$attrs', function($scope, $attrs) {
|
916
1884
|
this.scope = $scope;
|
917
1885
|
this.attrs = $attrs;
|
918
|
-
},
|
1886
|
+
}],
|
919
1887
|
|
920
|
-
link: function($scope, $element, $attr) {
|
1888
|
+
link: function($scope, $element, $attr, ionicScrollCtrl) {
|
921
1889
|
$scope.listView = new ionic.views.ListView({
|
922
1890
|
el: $element[0],
|
923
|
-
listEl: $element[0].children[0]
|
1891
|
+
listEl: $element[0].children[0],
|
1892
|
+
scrollEl: ionicScrollCtrl && ionicScrollCtrl.element,
|
1893
|
+
scrollView: ionicScrollCtrl && ionicScrollCtrl.scrollView,
|
1894
|
+
onReorder: function(el, oldIndex, newIndex) {
|
1895
|
+
$scope.$apply(function() {
|
1896
|
+
$scope.onReorder({el: el, start: oldIndex, end: newIndex});
|
1897
|
+
});
|
1898
|
+
}
|
924
1899
|
});
|
925
1900
|
|
926
1901
|
if($attr.animation) {
|
@@ -954,7 +1929,7 @@ angular.module('ionic.ui.list', ['ngAnimate'])
|
|
954
1929
|
|
955
1930
|
angular.module('ionic.ui.loading', [])
|
956
1931
|
|
957
|
-
.directive('
|
1932
|
+
.directive('ionLoading', function() {
|
958
1933
|
return {
|
959
1934
|
restrict: 'E',
|
960
1935
|
replace: true,
|
@@ -967,420 +1942,7 @@ angular.module('ionic.ui.loading', [])
|
|
967
1942
|
'</div>' +
|
968
1943
|
'</div>'
|
969
1944
|
};
|
970
|
-
});
|
971
|
-
|
972
|
-
})();
|
973
|
-
;
|
974
|
-
(function() {
|
975
|
-
'use strict';
|
976
|
-
|
977
|
-
/**
|
978
|
-
* @description
|
979
|
-
* The NavController is a navigation stack View Controller modelled off of
|
980
|
-
* UINavigationController from Cocoa Touch. With the Nav Controller, you can
|
981
|
-
* "push" new "pages" on to the navigation stack, and then pop them off to go
|
982
|
-
* back. The NavController controls a navigation bar with a back button and title
|
983
|
-
* which updates as the pages switch.
|
984
|
-
*
|
985
|
-
* The NavController makes sure to not recycle scopes of old pages
|
986
|
-
* so that a pop will still show the same state that the user left.
|
987
|
-
*
|
988
|
-
* However, once a page is popped, its scope is destroyed and will have to be
|
989
|
-
* recreated then next time it is pushed.
|
990
|
-
*
|
991
|
-
*/
|
992
|
-
|
993
|
-
var actualLocation = null;
|
994
|
-
|
995
|
-
angular.module('ionic.ui.navRouter', ['ionic.service.gesture'])
|
996
|
-
|
997
|
-
.run(['$rootScope', function($rootScope) {
|
998
|
-
$rootScope.stackCursorPosition = 0;
|
999
|
-
}])
|
1000
|
-
|
1001
|
-
.directive('navRouter', ['$rootScope', '$timeout', '$location', '$window', '$route', function($rootScope, $timeout, $location, $window, $route) {
|
1002
|
-
return {
|
1003
|
-
restrict: 'AC',
|
1004
|
-
// So you can require being under this
|
1005
|
-
controller: ['$scope', '$element', function($scope, $element) {
|
1006
|
-
this.navBar = {
|
1007
|
-
isVisible: true
|
1008
|
-
};
|
1009
|
-
$scope.navController = this;
|
1010
|
-
|
1011
|
-
this.goBack = function() {
|
1012
|
-
$scope.direction = 'back';
|
1013
|
-
};
|
1014
|
-
}],
|
1015
|
-
|
1016
|
-
link: function($scope, $element, $attr, ctrl) {
|
1017
|
-
if(!$element.length) return;
|
1018
|
-
|
1019
|
-
$scope.animation = $attr.animation;
|
1020
|
-
|
1021
|
-
$element[0].classList.add('noop-animation');
|
1022
|
-
|
1023
|
-
var isFirst = true;
|
1024
|
-
// Store whether we did an animation yet, to know if
|
1025
|
-
// we should let the first state animate
|
1026
|
-
var didAnimate = false;
|
1027
|
-
|
1028
|
-
var initTransition = function() {
|
1029
|
-
//$element.addClass($scope.animation);
|
1030
|
-
};
|
1031
|
-
|
1032
|
-
var reverseTransition = function() {
|
1033
|
-
$element[0].classList.remove('noop-animation');
|
1034
|
-
$element[0].classList.add($scope.animation);
|
1035
|
-
$element[0].classList.add('reverse');
|
1036
|
-
};
|
1037
|
-
|
1038
|
-
var forwardTransition = function() {
|
1039
|
-
$element[0].classList.remove('noop-animation');
|
1040
|
-
$element[0].classList.remove('reverse');
|
1041
|
-
$element[0].classList.add($scope.animation);
|
1042
|
-
};
|
1043
|
-
|
1044
|
-
$scope.$on('$routeChangeSuccess', function(e, a) {
|
1045
|
-
});
|
1046
|
-
$scope.$on('$routeChangeStart', function(e, next, current) {
|
1047
|
-
var back, historyState = $window.history.state;
|
1048
|
-
|
1049
|
-
back = $scope.direction == 'back' || (!!(historyState && historyState.position <= $rootScope.stackCursorPosition));
|
1050
|
-
|
1051
|
-
if(isFirst || (next && next.$$route && next.$$route.originalPath === "")) {
|
1052
|
-
// Don't animate
|
1053
|
-
isFirst = false;
|
1054
|
-
return;
|
1055
|
-
}
|
1056
|
-
|
1057
|
-
if(didAnimate || $rootScope.stackCursorPosition > 0) {
|
1058
|
-
didAnimate = true;
|
1059
|
-
if(back) {
|
1060
|
-
reverseTransition();
|
1061
|
-
} else {
|
1062
|
-
forwardTransition();
|
1063
|
-
}
|
1064
|
-
}
|
1065
|
-
});
|
1066
|
-
|
1067
|
-
$scope.$on('$locationChangeSuccess', function(a, b, c) {
|
1068
|
-
// Store the new location
|
1069
|
-
$rootScope.actualLocation = $location.path();
|
1070
|
-
if(isFirst && $location.path() !== '/') {
|
1071
|
-
isFirst = false;
|
1072
|
-
}
|
1073
|
-
});
|
1074
|
-
|
1075
|
-
$scope.$on('navRouter.goBack', function(e) {
|
1076
|
-
ctrl.goBack();
|
1077
|
-
});
|
1078
|
-
|
1079
|
-
|
1080
|
-
// Keep track of location changes and update a stack pointer that tracks whether we are
|
1081
|
-
// going forwards or back
|
1082
|
-
$scope.$watch(function () { return $location.path(); }, function (newLocation, oldLocation) {
|
1083
|
-
if($rootScope.actualLocation === newLocation) {
|
1084
|
-
if(oldLocation === '') {// || newLocation == '/') {
|
1085
|
-
// initial route, skip this
|
1086
|
-
return;
|
1087
|
-
}
|
1088
|
-
|
1089
|
-
var back, historyState = $window.history.state;
|
1090
|
-
|
1091
|
-
back = $scope.direction == 'back' || (!!(historyState && historyState.position <= $rootScope.stackCursorPosition));
|
1092
|
-
|
1093
|
-
if (back) {
|
1094
|
-
//back button
|
1095
|
-
$rootScope.stackCursorPosition--;
|
1096
|
-
} else {
|
1097
|
-
//forward button
|
1098
|
-
$rootScope.stackCursorPosition++;
|
1099
|
-
}
|
1100
|
-
|
1101
|
-
$scope.direction = 'forwards';
|
1102
|
-
|
1103
|
-
} else {
|
1104
|
-
var currentRouteBeforeChange = $route.current;
|
1105
|
-
|
1106
|
-
if (currentRouteBeforeChange) {
|
1107
|
-
|
1108
|
-
$window.history.replaceState({
|
1109
|
-
position: $rootScope.stackCursorPosition
|
1110
|
-
});
|
1111
|
-
|
1112
|
-
$rootScope.stackCursorPosition++;
|
1113
|
-
}
|
1114
|
-
}
|
1115
|
-
});
|
1116
|
-
}
|
1117
|
-
};
|
1118
|
-
}])
|
1119
|
-
|
1120
|
-
/**
|
1121
|
-
* Our Nav Bar directive which updates as the controller state changes.
|
1122
|
-
*/
|
1123
|
-
.directive('navBar', ['$rootScope', '$animate', '$compile', function($rootScope, $animate, $compile) {
|
1124
|
-
|
1125
|
-
/**
|
1126
|
-
* Perform an animation between one tab bar state and the next.
|
1127
|
-
* Right now this just animates the titles.
|
1128
|
-
*/
|
1129
|
-
var animate = function($scope, $element, oldTitle, data, cb) {
|
1130
|
-
var title, nTitle, oTitle, titles = $element[0].querySelectorAll('.title');
|
1131
|
-
|
1132
|
-
var newTitle = data.title;
|
1133
|
-
if(!oldTitle || oldTitle === newTitle) {
|
1134
|
-
cb();
|
1135
|
-
return;
|
1136
|
-
}
|
1137
|
-
|
1138
|
-
// Clone the old title and add a new one so we can show two animating in and out
|
1139
|
-
// add ng-leave and ng-enter during creation to prevent flickering when they are swapped during animation
|
1140
|
-
title = angular.element(titles[0]);
|
1141
|
-
oTitle = $compile('<h1 class="title ng-leave" ng-bind="oldTitle"></h1>')($scope);
|
1142
|
-
title.replaceWith(oTitle);
|
1143
|
-
nTitle = $compile('<h1 class="title ng-enter" ng-bind="currentTitle"></h1>')($scope);
|
1144
|
-
|
1145
|
-
var insert = $element[0].firstElementChild || null;
|
1146
|
-
|
1147
|
-
// Insert the new title
|
1148
|
-
$animate.enter(nTitle, $element, insert && angular.element(insert), function() {
|
1149
|
-
cb();
|
1150
|
-
});
|
1151
|
-
|
1152
|
-
// Remove the old title
|
1153
|
-
$animate.leave(angular.element(oTitle), function() {
|
1154
|
-
});
|
1155
|
-
};
|
1156
|
-
|
1157
|
-
return {
|
1158
|
-
restrict: 'E',
|
1159
|
-
require: '^navRouter',
|
1160
|
-
replace: true,
|
1161
|
-
scope: {
|
1162
|
-
type: '@',
|
1163
|
-
backButtonType: '@',
|
1164
|
-
backButtonLabel: '@',
|
1165
|
-
backButtonIcon: '@',
|
1166
|
-
alignTitle: '@'
|
1167
|
-
},
|
1168
|
-
template: '<header class="bar bar-header nav-bar" ng-class="{invisible: !navController.navBar.isVisible}">' +
|
1169
|
-
'<div class="buttons"> ' +
|
1170
|
-
'<button nav-back class="button" ng-if="enableBackButton && showBackButton" ng-class="backButtonClass" ng-bind-html="backButtonLabel"></button>' +
|
1171
|
-
'<button ng-click="button.tap($event)" ng-repeat="button in leftButtons" class="button no-animation {{button.type}}" ng-bind-html="button.content"></button>' +
|
1172
|
-
'</div>' +
|
1173
|
-
'<h1 class="title" ng-bind="currentTitle"></h1>' +
|
1174
|
-
'<div class="buttons" ng-if="rightButtons.length"> ' +
|
1175
|
-
'<button ng-click="button.tap($event)" ng-repeat="button in rightButtons" class="button no-animation {{button.type}}" ng-bind-html="button.content"></button>' +
|
1176
|
-
'</div>' +
|
1177
|
-
'</header>',
|
1178
|
-
link: function($scope, $element, $attr, navCtrl) {
|
1179
|
-
var backButton;
|
1180
|
-
|
1181
|
-
$element.addClass($attr.animation);
|
1182
|
-
|
1183
|
-
// Create the back button content and show/hide it based on scope settings
|
1184
|
-
$scope.enableBackButton = true;
|
1185
|
-
$scope.backButtonClass = $attr.backButtonType;
|
1186
|
-
if($attr.backButtonIcon) {
|
1187
|
-
$scope.backButtonClass += ' icon ' + $attr.backButtonIcon;
|
1188
|
-
}
|
1189
|
-
|
1190
|
-
// Listen for changes in the stack cursor position to indicate whether a back
|
1191
|
-
// button should be shown (this can still be disabled by the $scope.enableBackButton
|
1192
|
-
$rootScope.$watch('stackCursorPosition', function(value) {
|
1193
|
-
if(value > 0) {
|
1194
|
-
$scope.showBackButton = true;
|
1195
|
-
} else {
|
1196
|
-
$scope.showBackButton = false;
|
1197
|
-
}
|
1198
|
-
});
|
1199
|
-
|
1200
|
-
// Store a reference to our nav controller
|
1201
|
-
$scope.navController = navCtrl;
|
1202
|
-
|
1203
|
-
// Initialize our header bar view which will handle resizing and aligning our title labels
|
1204
|
-
var hb = new ionic.views.HeaderBar({
|
1205
|
-
el: $element[0],
|
1206
|
-
alignTitle: $scope.alignTitle || 'center'
|
1207
|
-
});
|
1208
|
-
$scope.headerBarView = hb;
|
1209
|
-
|
1210
|
-
// Add the type of header bar class to this element
|
1211
|
-
$element.addClass($scope.type);
|
1212
|
-
|
1213
|
-
var updateHeaderData = function(data) {
|
1214
|
-
var oldTitle = $scope.currentTitle;
|
1215
|
-
$scope.oldTitle = oldTitle;
|
1216
|
-
|
1217
|
-
if(typeof data.title !== 'undefined') {
|
1218
|
-
$scope.currentTitle = data.title;
|
1219
|
-
}
|
1220
|
-
|
1221
|
-
$scope.leftButtons = data.leftButtons;
|
1222
|
-
$scope.rightButtons = data.rightButtons;
|
1223
|
-
|
1224
|
-
if(typeof data.hideBackButton !== 'undefined') {
|
1225
|
-
$scope.enableBackButton = data.hideBackButton !== true;
|
1226
|
-
}
|
1227
|
-
|
1228
|
-
if(data.animate !== false && typeof data.title !== 'undefined') {
|
1229
|
-
animate($scope, $element, oldTitle, data, function() {
|
1230
|
-
hb.align();
|
1231
|
-
});
|
1232
|
-
} else {
|
1233
|
-
hb.align();
|
1234
|
-
}
|
1235
|
-
};
|
1236
|
-
|
1237
|
-
$scope.$parent.$on('navRouter.showBackButton', function(e, data) {
|
1238
|
-
$scope.enableBackButton = true;
|
1239
|
-
});
|
1240
|
-
|
1241
|
-
$scope.$parent.$on('navRouter.hideBackButton', function(e, data) {
|
1242
|
-
$scope.enableBackButton = false;
|
1243
|
-
});
|
1244
|
-
|
1245
|
-
// Listen for changes on title change, and update the title
|
1246
|
-
$scope.$parent.$on('navRouter.pageChanged', function(e, data) {
|
1247
|
-
updateHeaderData(data);
|
1248
|
-
});
|
1249
|
-
|
1250
|
-
$scope.$parent.$on('navRouter.pageShown', function(e, data) {
|
1251
|
-
updateHeaderData(data);
|
1252
|
-
});
|
1253
|
-
|
1254
|
-
$scope.$parent.$on('navRouter.titleChanged', function(e, data) {
|
1255
|
-
var oldTitle = $scope.currentTitle;
|
1256
|
-
$scope.oldTitle = oldTitle;
|
1257
|
-
|
1258
|
-
if(typeof data.title !== 'undefined') {
|
1259
|
-
$scope.currentTitle = data.title;
|
1260
|
-
}
|
1261
|
-
|
1262
|
-
if(data.animate !== false && typeof data.title !== 'undefined') {
|
1263
|
-
animate($scope, $element, oldTitle, data, function() {
|
1264
|
-
hb.align();
|
1265
|
-
});
|
1266
|
-
} else {
|
1267
|
-
hb.align();
|
1268
|
-
}
|
1269
|
-
});
|
1270
|
-
|
1271
|
-
// If a nav page changes the left or right buttons, update our scope vars
|
1272
|
-
$scope.$parent.$on('navRouter.leftButtonsChanged', function(e, data) {
|
1273
|
-
$scope.leftButtons = data;
|
1274
|
-
});
|
1275
|
-
$scope.$parent.$on('navRouter.rightButtonsChanged', function(e, data) {
|
1276
|
-
$scope.rightButtons = data;
|
1277
|
-
});
|
1278
|
-
|
1279
|
-
/*
|
1280
|
-
$scope.$parent.$on('navigation.push', function() {
|
1281
|
-
backButton = angular.element($element[0].querySelector('.button'));
|
1282
|
-
backButton.addClass($scope.backButtonType);
|
1283
|
-
hb.align();
|
1284
|
-
});
|
1285
|
-
$scope.$parent.$on('navigation.pop', function() {
|
1286
|
-
hb.align();
|
1287
|
-
});
|
1288
|
-
*/
|
1289
|
-
|
1290
|
-
$scope.$on('$destroy', function() {
|
1291
|
-
//
|
1292
|
-
});
|
1293
|
-
}
|
1294
|
-
};
|
1295
|
-
}])
|
1296
|
-
|
1297
|
-
.directive('navPage', ['$parse', function($parse) {
|
1298
|
-
return {
|
1299
|
-
restrict: 'E',
|
1300
|
-
require: '^navRouter',
|
1301
|
-
scope: {
|
1302
|
-
leftButtons: '=',
|
1303
|
-
rightButtons: '=',
|
1304
|
-
title: '=',
|
1305
|
-
icon: '@',
|
1306
|
-
iconOn: '@',
|
1307
|
-
iconOff: '@',
|
1308
|
-
type: '@',
|
1309
|
-
alignTitle: '@',
|
1310
|
-
hideBackButton: '@',
|
1311
|
-
hideNavBar: '@',
|
1312
|
-
animate: '@',
|
1313
|
-
},
|
1314
|
-
link: function($scope, $element, $attr, navCtrl) {
|
1315
|
-
$element.addClass('pane');
|
1316
|
-
|
1317
|
-
// Should we hide a back button when this tab is shown
|
1318
|
-
$scope.hideBackButton = $scope.$eval($scope.hideBackButton);
|
1319
|
-
|
1320
|
-
$scope.hideNavBar = $scope.$eval($scope.hideNavBar);
|
1321
|
-
|
1322
|
-
navCtrl.navBar.isVisible = !$scope.hideNavBar;
|
1323
|
-
|
1324
|
-
if($scope.hideBackButton === true) {
|
1325
|
-
$scope.$emit('navRouter.hideBackButton');
|
1326
|
-
} else {
|
1327
|
-
$scope.$emit('navRouter.showBackButton');
|
1328
|
-
}
|
1329
|
-
|
1330
|
-
// Whether we should animate on tab change, also impacts whether we
|
1331
|
-
// tell any parent nav controller to animate
|
1332
|
-
$scope.animate = $scope.$eval($scope.animate);
|
1333
|
-
|
1334
|
-
|
1335
|
-
// watch for changes in the left buttons
|
1336
|
-
$scope.$watch('leftButtons', function(value) {
|
1337
|
-
$scope.$emit('navRouter.leftButtonsChanged', $scope.leftButtons);
|
1338
|
-
});
|
1339
|
-
|
1340
|
-
$scope.$watch('rightButtons', function(val) {
|
1341
|
-
$scope.$emit('navRouter.rightButtonsChanged', $scope.rightButtons);
|
1342
|
-
});
|
1343
|
-
|
1344
|
-
/*
|
1345
|
-
$scope.$watch('hideBackButton', function(value) {
|
1346
|
-
if(value === true) {
|
1347
|
-
navCtrl.hideBackButton();
|
1348
|
-
} else {
|
1349
|
-
navCtrl.showBackButton();
|
1350
|
-
}
|
1351
|
-
});
|
1352
|
-
*/
|
1353
|
-
|
1354
|
-
// watch for changes in the title
|
1355
|
-
$scope.$watch('title', function(value) {
|
1356
|
-
$scope.$emit('navRouter.titleChanged', {
|
1357
|
-
title: value,
|
1358
|
-
animate: $scope.animate
|
1359
|
-
});
|
1360
|
-
});
|
1361
|
-
}
|
1362
|
-
};
|
1363
|
-
}])
|
1364
|
-
|
1365
|
-
.directive('navBack', ['$window', '$rootScope', 'Gesture', function($window, $rootScope, Gesture) {
|
1366
|
-
return {
|
1367
|
-
restrict: 'AC',
|
1368
|
-
link: function($scope, $element, $attr, navCtrl) {
|
1369
|
-
var goBack = function(e) {
|
1370
|
-
// Only trigger back if the stack is greater than zero
|
1371
|
-
if($rootScope.stackCursorPosition > 0) {
|
1372
|
-
$window.history.back();
|
1373
|
-
|
1374
|
-
// Fallback for bad history supporting devices
|
1375
|
-
$scope.$emit('navRouter.goBack');
|
1376
|
-
}
|
1377
|
-
e.alreadyHandled = true;
|
1378
|
-
return false;
|
1379
|
-
};
|
1380
|
-
$element.bind('click', goBack);
|
1381
|
-
}
|
1382
|
-
};
|
1383
|
-
}]);
|
1945
|
+
});
|
1384
1946
|
|
1385
1947
|
})();
|
1386
1948
|
;
|
@@ -1391,56 +1953,35 @@ angular.module('ionic.ui.radio', [])
|
|
1391
1953
|
|
1392
1954
|
// The radio button is a radio powered element with only
|
1393
1955
|
// one possible selection in a set of options.
|
1394
|
-
.directive('
|
1956
|
+
.directive('ionRadio', function() {
|
1395
1957
|
return {
|
1396
1958
|
restrict: 'E',
|
1397
1959
|
replace: true,
|
1398
1960
|
require: '?ngModel',
|
1399
1961
|
scope: {
|
1400
|
-
|
1962
|
+
ngModel: '=?',
|
1963
|
+
ngValue: '=?',
|
1964
|
+
ngChange: '&',
|
1965
|
+
icon: '@'
|
1401
1966
|
},
|
1402
1967
|
transclude: true,
|
1403
|
-
template: '<label class="item item-radio"
|
1404
|
-
<input type="radio" name="radio-group"
|
1405
|
-
|
1406
|
-
|
1407
|
-
<i class="radio-icon icon ion-checkmark"></i
|
1408
|
-
</label>',
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
if(!ngModel) { return; }
|
1414
|
-
|
1415
|
-
radio = $element.children().eq(0);
|
1416
|
-
|
1417
|
-
if(!radio.length) { return; }
|
1418
|
-
|
1419
|
-
if(ngModel) {
|
1420
|
-
radio.bind('click', function(e) {
|
1421
|
-
console.log('RADIO CLICK');
|
1422
|
-
$scope.$apply(function() {
|
1423
|
-
ngModel.$setViewValue($scope.$eval($attr.ngValue));
|
1424
|
-
});
|
1425
|
-
e.alreadyHandled = true;
|
1426
|
-
});
|
1427
|
-
|
1428
|
-
ngModel.$render = function() {
|
1429
|
-
var val = $scope.$eval($attr.ngValue);
|
1430
|
-
if(val === ngModel.$viewValue) {
|
1431
|
-
radio.attr('checked', 'checked');
|
1432
|
-
} else {
|
1433
|
-
radio.removeAttr('checked');
|
1434
|
-
}
|
1435
|
-
};
|
1436
|
-
}
|
1968
|
+
template: '<label class="item item-radio">' +
|
1969
|
+
'<input type="radio" name="radio-group"' +
|
1970
|
+
' ng-model="ngModel" ng-value="ngValue" ng-change="ngChange()">' +
|
1971
|
+
'<div class="item-content disable-pointer-events" ng-transclude></div>' +
|
1972
|
+
'<i class="radio-icon disable-pointer-events icon ion-checkmark"></i>' +
|
1973
|
+
'</label>',
|
1974
|
+
|
1975
|
+
compile: function(element, attr) {
|
1976
|
+
if(attr.name) element.children().eq(0).attr('name', attr.name);
|
1977
|
+
if(attr.icon) element.children().eq(2).removeClass('ion-checkmark').addClass(attr.icon);
|
1437
1978
|
}
|
1438
1979
|
};
|
1439
1980
|
})
|
1440
1981
|
|
1441
1982
|
// The radio button is a radio powered element with only
|
1442
1983
|
// one possible selection in a set of options.
|
1443
|
-
.directive('
|
1984
|
+
.directive('ionRadioButtons', function() {
|
1444
1985
|
return {
|
1445
1986
|
restrict: 'E',
|
1446
1987
|
replace: true,
|
@@ -1483,17 +2024,17 @@ angular.module('ionic.ui.radio', [])
|
|
1483
2024
|
};
|
1484
2025
|
})
|
1485
2026
|
|
1486
|
-
.directive('
|
2027
|
+
.directive('ionButtonRadio', function() {
|
1487
2028
|
return {
|
1488
2029
|
restrict: 'CA',
|
1489
|
-
require: ['?^ngModel', '?^
|
2030
|
+
require: ['?^ngModel', '?^ionRadioButtons'],
|
1490
2031
|
link: function($scope, $element, $attr, ctrls) {
|
1491
2032
|
var ngModel = ctrls[0];
|
1492
2033
|
var radioButtons = ctrls[1];
|
1493
2034
|
if(!ngModel || !radioButtons) { return; }
|
1494
2035
|
|
1495
2036
|
var setIt = function() {
|
1496
|
-
|
2037
|
+
|
1497
2038
|
$element.addClass('active');
|
1498
2039
|
ngModel.$setViewValue($scope.$eval($attr.ngValue));
|
1499
2040
|
|
@@ -1501,7 +2042,7 @@ angular.module('ionic.ui.radio', [])
|
|
1501
2042
|
};
|
1502
2043
|
|
1503
2044
|
var clickHandler = function(e) {
|
1504
|
-
|
2045
|
+
|
1505
2046
|
setIt();
|
1506
2047
|
};
|
1507
2048
|
|
@@ -1527,11 +2068,11 @@ angular.module('ionic.ui.radio', [])
|
|
1527
2068
|
|
1528
2069
|
angular.module('ionic.ui.scroll', [])
|
1529
2070
|
|
1530
|
-
.directive('
|
2071
|
+
.directive('ionScroll', ['$parse', '$timeout', '$controller', function($parse, $timeout, $controller) {
|
1531
2072
|
return {
|
1532
2073
|
restrict: 'E',
|
1533
2074
|
replace: true,
|
1534
|
-
template: '<div class="scroll-view"></div>',
|
2075
|
+
template: '<div class="scroll-view"><div class="scroll" ng-transclude></div></div>',
|
1535
2076
|
transclude: true,
|
1536
2077
|
scope: {
|
1537
2078
|
direction: '@',
|
@@ -1547,86 +2088,46 @@ angular.module('ionic.ui.scroll', [])
|
|
1547
2088
|
controller: function() {},
|
1548
2089
|
|
1549
2090
|
compile: function(element, attr, transclude) {
|
1550
|
-
return function($scope, $element, $attr) {
|
1551
|
-
var clone, sv, sc = document.createElement('div');
|
1552
2091
|
|
1553
|
-
|
1554
|
-
|
2092
|
+
return {
|
2093
|
+
//Prelink <ion-scroll> so it can compile before other directives compile.
|
2094
|
+
//Then other directives can require ionicScrollCtrl
|
2095
|
+
pre: prelink
|
2096
|
+
};
|
2097
|
+
|
2098
|
+
function prelink($scope, $element, $attr) {
|
2099
|
+
var scrollView, scrollCtrl,
|
2100
|
+
sc = $element[0].children[0];
|
2101
|
+
|
1555
2102
|
if(attr.padding == "true") {
|
1556
2103
|
sc.classList.add('padding');
|
1557
|
-
addedPadding = true;
|
1558
2104
|
}
|
1559
2105
|
if($scope.$eval($scope.paging) === true) {
|
1560
2106
|
sc.classList.add('scroll-paging');
|
1561
2107
|
}
|
1562
|
-
$element.append(sc);
|
1563
|
-
|
1564
|
-
// Pass the parent scope down to the child
|
1565
|
-
clone = transclude($scope.$parent);
|
1566
|
-
angular.element($element[0].firstElementChild).append(clone);
|
1567
|
-
|
1568
|
-
// Get refresher size
|
1569
|
-
var refresher = $element[0].querySelector('.scroll-refresher');
|
1570
|
-
var refresherHeight = refresher && refresher.clientHeight || 0;
|
1571
2108
|
|
1572
2109
|
if(!$scope.direction) { $scope.direction = 'y'; }
|
1573
|
-
var
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
options.speedMultiplier = 0.8;
|
1588
|
-
options.bouncing = false;
|
1589
|
-
}
|
1590
|
-
|
1591
|
-
sv = new ionic.views.Scroll(options);
|
1592
|
-
|
1593
|
-
// Activate pull-to-refresh
|
1594
|
-
if(refresher) {
|
1595
|
-
sv.activatePullToRefresh(refresherHeight, function() {
|
1596
|
-
refresher.classList.add('active');
|
1597
|
-
}, function() {
|
1598
|
-
refresher.classList.remove('refreshing');
|
1599
|
-
refresher.classList.remove('active');
|
1600
|
-
}, function() {
|
1601
|
-
refresher.classList.add('refreshing');
|
1602
|
-
$scope.onRefresh();
|
1603
|
-
$scope.$parent.$broadcast('scroll.onRefresh');
|
1604
|
-
});
|
1605
|
-
}
|
1606
|
-
|
1607
|
-
$element.bind('scroll', function(e) {
|
1608
|
-
$scope.onScroll({
|
1609
|
-
event: e,
|
1610
|
-
scrollTop: e.detail ? e.detail.scrollTop : e.originalEvent ? e.originalEvent.detail.scrollTop : 0,
|
1611
|
-
scrollLeft: e.detail ? e.detail.scrollLeft: e.originalEvent ? e.originalEvent.detail.scrollLeft : 0
|
1612
|
-
});
|
1613
|
-
});
|
1614
|
-
|
1615
|
-
$scope.$parent.$on('scroll.resize', function(e) {
|
1616
|
-
// Run the resize after this digest
|
1617
|
-
$timeout(function() {
|
1618
|
-
sv && sv.resize();
|
1619
|
-
});
|
1620
|
-
});
|
2110
|
+
var isPaging = $scope.$eval($scope.paging) === true;
|
2111
|
+
|
2112
|
+
var scrollViewOptions= {
|
2113
|
+
el: $element[0],
|
2114
|
+
paging: isPaging,
|
2115
|
+
scrollbarX: $scope.$eval($scope.scrollbarX) !== false,
|
2116
|
+
scrollbarY: $scope.$eval($scope.scrollbarY) !== false,
|
2117
|
+
scrollingX: $scope.direction.indexOf('x') >= 0,
|
2118
|
+
scrollingY: $scope.direction.indexOf('y') >= 0
|
2119
|
+
};
|
2120
|
+
if (isPaging) {
|
2121
|
+
scrollViewOptions.speedMultiplier = 0.8;
|
2122
|
+
scrollViewOptions.bouncing = false;
|
2123
|
+
}
|
1621
2124
|
|
1622
|
-
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
1626
|
-
// Let child scopes access this
|
1627
|
-
$scope.$parent.scrollView = sv;
|
2125
|
+
scrollCtrl = $controller('$ionicScroll', {
|
2126
|
+
$scope: $scope,
|
2127
|
+
scrollViewOptions: scrollViewOptions
|
1628
2128
|
});
|
1629
|
-
|
2129
|
+
scrollView = $scope.$parent.scrollView = scrollCtrl.scrollView;
|
2130
|
+
}
|
1630
2131
|
}
|
1631
2132
|
};
|
1632
2133
|
}]);
|
@@ -1642,7 +2143,7 @@ angular.module('ionic.ui.scroll', [])
|
|
1642
2143
|
* left and/or right menu, which a center content area.
|
1643
2144
|
*/
|
1644
2145
|
|
1645
|
-
angular.module('ionic.ui.sideMenu', ['ionic.service.gesture'])
|
2146
|
+
angular.module('ionic.ui.sideMenu', ['ionic.service.gesture', 'ionic.service.view'])
|
1646
2147
|
|
1647
2148
|
/**
|
1648
2149
|
* The internal controller for the side menu controller. This
|
@@ -1650,24 +2151,22 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture'])
|
|
1650
2151
|
* some side menu stuff on the current scope.
|
1651
2152
|
*/
|
1652
2153
|
|
1653
|
-
.
|
2154
|
+
.run(['$ionicViewService', function($ionicViewService) {
|
2155
|
+
// set that the side-menus directive should not animate when transitioning to it
|
2156
|
+
$ionicViewService.disableRegisterByTagName('ion-side-menus');
|
2157
|
+
}])
|
2158
|
+
|
2159
|
+
.directive('ionSideMenus', function() {
|
1654
2160
|
return {
|
1655
2161
|
restrict: 'ECA',
|
1656
|
-
controller: ['$scope', function($scope) {
|
2162
|
+
controller: ['$scope', '$attrs', function($scope, $attrs) {
|
1657
2163
|
var _this = this;
|
1658
2164
|
|
1659
2165
|
angular.extend(this, ionic.controllers.SideMenuController.prototype);
|
1660
2166
|
|
1661
2167
|
ionic.controllers.SideMenuController.call(this, {
|
1662
|
-
|
1663
|
-
|
1664
|
-
width: 275,
|
1665
|
-
},
|
1666
|
-
|
1667
|
-
// Our quick implementation of the right side menu
|
1668
|
-
right: {
|
1669
|
-
width: 275,
|
1670
|
-
}
|
2168
|
+
left: { width: 275 },
|
2169
|
+
right: { width: 275 }
|
1671
2170
|
});
|
1672
2171
|
|
1673
2172
|
$scope.sideMenuContentTranslateX = 0;
|
@@ -1676,30 +2175,31 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture'])
|
|
1676
2175
|
}],
|
1677
2176
|
replace: true,
|
1678
2177
|
transclude: true,
|
1679
|
-
template: '<div class="
|
2178
|
+
template: '<div class="view" ng-transclude></div>'
|
1680
2179
|
};
|
1681
2180
|
})
|
1682
2181
|
|
1683
|
-
.directive('
|
2182
|
+
.directive('ionSideMenuContent', ['$timeout', '$ionicGesture', function($timeout, $ionicGesture) {
|
1684
2183
|
return {
|
1685
2184
|
restrict: 'AC',
|
1686
|
-
require: '^
|
2185
|
+
require: '^ionSideMenus',
|
1687
2186
|
scope: true,
|
1688
2187
|
compile: function(element, attr, transclude) {
|
1689
2188
|
return function($scope, $element, $attr, sideMenuCtrl) {
|
1690
2189
|
|
1691
2190
|
$element.addClass('menu-content');
|
1692
2191
|
|
1693
|
-
|
2192
|
+
if (angular.isDefined(attr.dragContent)) {
|
2193
|
+
$scope.$watch(attr.dragContent, function(value) {
|
2194
|
+
$scope.dragContent = value;
|
2195
|
+
});
|
2196
|
+
} else {
|
2197
|
+
$scope.dragContent = true;
|
2198
|
+
}
|
1694
2199
|
|
1695
2200
|
var defaultPrevented = false;
|
1696
2201
|
var isDragging = false;
|
1697
2202
|
|
1698
|
-
ionic.on('mousedown', function(e) {
|
1699
|
-
// If the child element prevented the drag, don't drag
|
1700
|
-
defaultPrevented = e.defaultPrevented;
|
1701
|
-
});
|
1702
|
-
|
1703
2203
|
// Listen for taps on the content to close the menu
|
1704
2204
|
/*
|
1705
2205
|
ionic.on('tap', function(e) {
|
@@ -1709,7 +2209,7 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture'])
|
|
1709
2209
|
|
1710
2210
|
var dragFn = function(e) {
|
1711
2211
|
if($scope.dragContent) {
|
1712
|
-
if(defaultPrevented) {
|
2212
|
+
if(defaultPrevented || e.gesture.srcEvent.defaultPrevented) {
|
1713
2213
|
return;
|
1714
2214
|
}
|
1715
2215
|
isDragging = true;
|
@@ -1725,10 +2225,10 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture'])
|
|
1725
2225
|
};
|
1726
2226
|
|
1727
2227
|
//var dragGesture = Gesture.on('drag', dragFn, $element);
|
1728
|
-
var dragRightGesture =
|
1729
|
-
var dragLeftGesture =
|
1730
|
-
var dragUpGesture =
|
1731
|
-
var dragDownGesture =
|
2228
|
+
var dragRightGesture = $ionicGesture.on('dragright', dragFn, $element);
|
2229
|
+
var dragLeftGesture = $ionicGesture.on('dragleft', dragFn, $element);
|
2230
|
+
var dragUpGesture = $ionicGesture.on('dragup', dragVertFn, $element);
|
2231
|
+
var dragDownGesture = $ionicGesture.on('dragdown', dragVertFn, $element);
|
1732
2232
|
|
1733
2233
|
var dragReleaseFn = function(e) {
|
1734
2234
|
isDragging = false;
|
@@ -1738,7 +2238,7 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture'])
|
|
1738
2238
|
defaultPrevented = false;
|
1739
2239
|
};
|
1740
2240
|
|
1741
|
-
var releaseGesture =
|
2241
|
+
var releaseGesture = $ionicGesture.on('release', dragReleaseFn, $element);
|
1742
2242
|
|
1743
2243
|
sideMenuCtrl.setContent({
|
1744
2244
|
onDrag: function(e) {},
|
@@ -1746,12 +2246,16 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture'])
|
|
1746
2246
|
getTranslateX: function() {
|
1747
2247
|
return $scope.sideMenuContentTranslateX || 0;
|
1748
2248
|
},
|
1749
|
-
setTranslateX: function(amount) {
|
1750
|
-
|
2249
|
+
setTranslateX: ionic.animationFrameThrottle(function(amount) {
|
2250
|
+
if(amount === 0) {
|
2251
|
+
$element[0].style[ionic.CSS.TRANSFORM] = 'none';
|
2252
|
+
} else {
|
2253
|
+
$element[0].style[ionic.CSS.TRANSFORM] = 'translate3d(' + amount + 'px, 0, 0)';
|
2254
|
+
}
|
1751
2255
|
$timeout(function() {
|
1752
2256
|
$scope.sideMenuContentTranslateX = amount;
|
1753
2257
|
});
|
1754
|
-
},
|
2258
|
+
}),
|
1755
2259
|
enableAnimation: function() {
|
1756
2260
|
//this.el.classList.add(this.animateClass);
|
1757
2261
|
$scope.animationEnabled = true;
|
@@ -1766,11 +2270,11 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture'])
|
|
1766
2270
|
|
1767
2271
|
// Cleanup
|
1768
2272
|
$scope.$on('$destroy', function() {
|
1769
|
-
|
1770
|
-
|
1771
|
-
|
1772
|
-
|
1773
|
-
|
2273
|
+
$ionicGesture.off(dragLeftGesture, 'dragleft', dragFn);
|
2274
|
+
$ionicGesture.off(dragRightGesture, 'dragright', dragFn);
|
2275
|
+
$ionicGesture.off(dragUpGesture, 'dragup', dragFn);
|
2276
|
+
$ionicGesture.off(dragDownGesture, 'dragdown', dragFn);
|
2277
|
+
$ionicGesture.off(releaseGesture, 'release', dragReleaseFn);
|
1774
2278
|
});
|
1775
2279
|
};
|
1776
2280
|
}
|
@@ -1778,37 +2282,40 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture'])
|
|
1778
2282
|
}])
|
1779
2283
|
|
1780
2284
|
|
1781
|
-
.directive('
|
2285
|
+
.directive('ionSideMenu', function() {
|
1782
2286
|
return {
|
1783
2287
|
restrict: 'E',
|
1784
|
-
require: '^
|
2288
|
+
require: '^ionSideMenus',
|
1785
2289
|
replace: true,
|
1786
2290
|
transclude: true,
|
1787
2291
|
scope: true,
|
1788
2292
|
template: '<div class="menu menu-{{side}}"></div>',
|
1789
2293
|
compile: function(element, attr, transclude) {
|
2294
|
+
angular.isUndefined(attr.isEnabled) && attr.$set('isEnabled', 'true');
|
2295
|
+
angular.isUndefined(attr.width) && attr.$set('width', '275');
|
2296
|
+
|
1790
2297
|
return function($scope, $element, $attr, sideMenuCtrl) {
|
1791
2298
|
$scope.side = $attr.side;
|
1792
2299
|
|
1793
|
-
|
1794
|
-
|
1795
|
-
|
1796
|
-
|
1797
|
-
|
1798
|
-
|
1799
|
-
|
1800
|
-
|
1801
|
-
|
1802
|
-
|
1803
|
-
|
1804
|
-
|
1805
|
-
|
1806
|
-
|
1807
|
-
|
1808
|
-
};
|
1809
|
-
}
|
2300
|
+
var sideMenu = sideMenuCtrl[$scope.side] = new ionic.views.SideMenu({
|
2301
|
+
width: 275,
|
2302
|
+
el: $element[0],
|
2303
|
+
isEnabled: true
|
2304
|
+
});
|
2305
|
+
|
2306
|
+
$scope.$watch($attr.width, function(val) {
|
2307
|
+
var numberVal = +val;
|
2308
|
+
if (numberVal && numberVal == val) {
|
2309
|
+
sideMenu.setWidth(+val);
|
2310
|
+
}
|
2311
|
+
});
|
2312
|
+
$scope.$watch($attr.isEnabled, function(val) {
|
2313
|
+
sideMenu.setIsEnabled(!!val);
|
2314
|
+
});
|
1810
2315
|
|
1811
|
-
|
2316
|
+
transclude($scope, function(clone) {
|
2317
|
+
$element.append(clone);
|
2318
|
+
});
|
1812
2319
|
};
|
1813
2320
|
}
|
1814
2321
|
};
|
@@ -1820,34 +2327,41 @@ angular.module('ionic.ui.sideMenu', ['ionic.service.gesture'])
|
|
1820
2327
|
|
1821
2328
|
/**
|
1822
2329
|
* @description
|
1823
|
-
* The
|
1824
|
-
*
|
2330
|
+
* The slideBoxCtrol lets you quickly create a multi-page
|
2331
|
+
* container where each page can be swiped or dragged between
|
1825
2332
|
*/
|
1826
2333
|
|
1827
2334
|
angular.module('ionic.ui.slideBox', [])
|
1828
2335
|
|
1829
2336
|
/**
|
1830
|
-
* The internal controller for the
|
1831
|
-
* extends our core Ionic side menu controller and exposes
|
1832
|
-
* some side menu stuff on the current scope.
|
2337
|
+
* The internal controller for the slide box controller.
|
1833
2338
|
*/
|
1834
2339
|
|
1835
|
-
.directive('
|
2340
|
+
.directive('ionSlideBox', ['$timeout', '$compile', '$ionicSlideBoxDelegate', function($timeout, $compile, $ionicSlideBoxDelegate) {
|
1836
2341
|
return {
|
1837
2342
|
restrict: 'E',
|
1838
2343
|
replace: true,
|
1839
2344
|
transclude: true,
|
1840
2345
|
scope: {
|
1841
2346
|
doesContinue: '@',
|
2347
|
+
slideInterval: '@',
|
1842
2348
|
showPager: '@',
|
1843
|
-
|
2349
|
+
disableScroll: '@',
|
2350
|
+
onSlideChanged: '&',
|
2351
|
+
activeSlide: '=?'
|
1844
2352
|
},
|
1845
2353
|
controller: ['$scope', '$element', function($scope, $element) {
|
1846
2354
|
var _this = this;
|
1847
2355
|
|
2356
|
+
var continuous = $scope.$eval($scope.doesContinue) === true;
|
2357
|
+
var slideInterval = continuous ? $scope.$eval($scope.slideInterval) || 4000 : 0;
|
2358
|
+
|
1848
2359
|
var slider = new ionic.views.Slider({
|
1849
2360
|
el: $element[0],
|
1850
|
-
|
2361
|
+
auto: slideInterval,
|
2362
|
+
disableScroll: ($scope.$eval($scope.disableScroll) === true) || false,
|
2363
|
+
continuous: continuous,
|
2364
|
+
startSlide: $scope.activeSlide,
|
1851
2365
|
slidesChanged: function() {
|
1852
2366
|
$scope.currentSlide = slider.getPos();
|
1853
2367
|
|
@@ -1858,12 +2372,18 @@ angular.module('ionic.ui.slideBox', [])
|
|
1858
2372
|
$scope.currentSlide = slideIndex;
|
1859
2373
|
$scope.onSlideChanged({index:$scope.currentSlide});
|
1860
2374
|
$scope.$parent.$broadcast('slideBox.slideChanged', slideIndex);
|
1861
|
-
|
2375
|
+
$scope.activeSlide = slideIndex;
|
1862
2376
|
// Try to trigger a digest
|
1863
2377
|
$timeout(function() {});
|
1864
2378
|
}
|
1865
2379
|
});
|
1866
2380
|
|
2381
|
+
$scope.$watch('activeSlide', function(nv) {
|
2382
|
+
if(angular.isDefined(nv)){
|
2383
|
+
slider.slide(nv);
|
2384
|
+
}
|
2385
|
+
});
|
2386
|
+
|
1867
2387
|
$scope.$on('slideBox.nextSlide', function() {
|
1868
2388
|
slider.next();
|
1869
2389
|
});
|
@@ -1876,7 +2396,13 @@ angular.module('ionic.ui.slideBox', [])
|
|
1876
2396
|
slider.slide(index);
|
1877
2397
|
});
|
1878
2398
|
|
1879
|
-
$scope.slideBox = slider;
|
2399
|
+
$scope.$parent.slideBox = slider;
|
2400
|
+
|
2401
|
+
$ionicSlideBoxDelegate.register($scope, $element);
|
2402
|
+
|
2403
|
+
this.getNumSlides = function() {
|
2404
|
+
return slider.getNumSlides();
|
2405
|
+
};
|
1880
2406
|
|
1881
2407
|
$timeout(function() {
|
1882
2408
|
slider.load();
|
@@ -1891,7 +2417,7 @@ angular.module('ionic.ui.slideBox', [])
|
|
1891
2417
|
// If the pager should show, append it to the slide box
|
1892
2418
|
if($scope.$eval($scope.showPager) !== false) {
|
1893
2419
|
var childScope = $scope.$new();
|
1894
|
-
var pager = angular.element('<pager></pager>');
|
2420
|
+
var pager = angular.element('<ion-pager></ion-pager>');
|
1895
2421
|
$element.append(pager);
|
1896
2422
|
$compile(pager)(childScope);
|
1897
2423
|
}
|
@@ -1899,343 +2425,877 @@ angular.module('ionic.ui.slideBox', [])
|
|
1899
2425
|
};
|
1900
2426
|
}])
|
1901
2427
|
|
1902
|
-
.directive('
|
2428
|
+
.directive('ionSlide', function() {
|
2429
|
+
return {
|
2430
|
+
restrict: 'E',
|
2431
|
+
require: '^ionSlideBox',
|
2432
|
+
compile: function(element, attr) {
|
2433
|
+
element.addClass('slider-slide');
|
2434
|
+
return function($scope, $element, $attr) {};
|
2435
|
+
},
|
2436
|
+
};
|
2437
|
+
})
|
2438
|
+
|
2439
|
+
.directive('ionPager', function() {
|
2440
|
+
return {
|
2441
|
+
restrict: 'E',
|
2442
|
+
replace: true,
|
2443
|
+
require: '^ionSlideBox',
|
2444
|
+
template: '<div class="slider-pager"><span class="slider-pager-page" ng-repeat="slide in numSlides() track by $index" ng-class="{active: $index == currentSlide}"><i class="icon ion-record"></i></span></div>',
|
2445
|
+
link: function($scope, $element, $attr, slideBox) {
|
2446
|
+
var selectPage = function(index) {
|
2447
|
+
var children = $element[0].children;
|
2448
|
+
var length = children.length;
|
2449
|
+
for(var i = 0; i < length; i++) {
|
2450
|
+
if(i == index) {
|
2451
|
+
children[i].classList.add('active');
|
2452
|
+
} else {
|
2453
|
+
children[i].classList.remove('active');
|
2454
|
+
}
|
2455
|
+
}
|
2456
|
+
};
|
2457
|
+
|
2458
|
+
$scope.numSlides = function() {
|
2459
|
+
return new Array(slideBox.getNumSlides());
|
2460
|
+
};
|
2461
|
+
|
2462
|
+
$scope.$watch('currentSlide', function(v) {
|
2463
|
+
selectPage(v);
|
2464
|
+
});
|
2465
|
+
}
|
2466
|
+
};
|
2467
|
+
|
2468
|
+
});
|
2469
|
+
|
2470
|
+
})();
|
2471
|
+
;
|
2472
|
+
angular.module('ionic.ui.tabs', ['ionic.service.view'])
|
2473
|
+
|
2474
|
+
/**
|
2475
|
+
* @description
|
2476
|
+
*
|
2477
|
+
* The Tab Controller renders a set of pages that switch based on taps
|
2478
|
+
* on a tab bar. Modelled off of UITabBarController.
|
2479
|
+
*/
|
2480
|
+
|
2481
|
+
.run(['$ionicViewService', function($ionicViewService) {
|
2482
|
+
// set that the tabs directive should not animate when transitioning
|
2483
|
+
// to it. Instead, the children <tab> directives would animate
|
2484
|
+
$ionicViewService.disableRegisterByTagName('ion-tabs');
|
2485
|
+
}])
|
2486
|
+
|
2487
|
+
.controller('$ionicTabs', ['$scope', '$ionicViewService', '$element', function($scope, $ionicViewService, $element) {
|
2488
|
+
var self = $scope.tabsController = this;
|
2489
|
+
self.tabs = [];
|
2490
|
+
|
2491
|
+
self.selectedTab = null;
|
2492
|
+
|
2493
|
+
self.add = function(tab) {
|
2494
|
+
$ionicViewService.registerHistory(tab);
|
2495
|
+
self.tabs.push(tab);
|
2496
|
+
if(self.tabs.length === 1) {
|
2497
|
+
self.select(tab);
|
2498
|
+
}
|
2499
|
+
};
|
2500
|
+
|
2501
|
+
self.remove = function(tab) {
|
2502
|
+
var tabIndex = self.tabs.indexOf(tab);
|
2503
|
+
if (tabIndex === -1) {
|
2504
|
+
return;
|
2505
|
+
}
|
2506
|
+
//Use a field like '$tabSelected' so developers won't accidentally set it in controllers etc
|
2507
|
+
if (tab.$tabSelected) {
|
2508
|
+
self.deselect(tab);
|
2509
|
+
//Try to select a new tab if we're removing a tab
|
2510
|
+
if (self.tabs.length === 1) {
|
2511
|
+
//do nothing if there are no other tabs to select
|
2512
|
+
} else {
|
2513
|
+
//Select previous tab if it's the last tab, else select next tab
|
2514
|
+
var newTabIndex = tabIndex === self.tabs.length - 1 ? tabIndex - 1 : tabIndex + 1;
|
2515
|
+
self.select(self.tabs[newTabIndex]);
|
2516
|
+
}
|
2517
|
+
}
|
2518
|
+
self.tabs.splice(tabIndex, 1);
|
2519
|
+
};
|
2520
|
+
|
2521
|
+
self.getTabIndex = function(tab) {
|
2522
|
+
return self.tabs.indexOf(tab);
|
2523
|
+
};
|
2524
|
+
|
2525
|
+
self.deselect = function(tab) {
|
2526
|
+
if (tab.$tabSelected) {
|
2527
|
+
self.selectedTab = null;
|
2528
|
+
tab.$tabSelected = false;
|
2529
|
+
(tab.onDeselect || angular.noop)();
|
2530
|
+
}
|
2531
|
+
};
|
2532
|
+
|
2533
|
+
self.select = function(tab, shouldEmitEvent) {
|
2534
|
+
var tabIndex;
|
2535
|
+
if (angular.isNumber(tab)) {
|
2536
|
+
tabIndex = tab;
|
2537
|
+
tab = self.tabs[tabIndex];
|
2538
|
+
} else {
|
2539
|
+
tabIndex = self.tabs.indexOf(tab);
|
2540
|
+
}
|
2541
|
+
if (!tab || tabIndex == -1) {
|
2542
|
+
throw new Error('Cannot select tab "' + tabIndex + '"!');
|
2543
|
+
}
|
2544
|
+
|
2545
|
+
if (self.selectedTab && self.selectedTab.$historyId == tab.$historyId) {
|
2546
|
+
if (shouldEmitEvent) {
|
2547
|
+
$ionicViewService.goToHistoryRoot(tab.$historyId);
|
2548
|
+
}
|
2549
|
+
} else {
|
2550
|
+
angular.forEach(self.tabs, function(tab) {
|
2551
|
+
self.deselect(tab);
|
2552
|
+
});
|
2553
|
+
|
2554
|
+
self.selectedTab = tab;
|
2555
|
+
//Use a funny name like $tabSelected so the developer doesn't overwrite the var in a child scope
|
2556
|
+
tab.$tabSelected = true;
|
2557
|
+
(tab.onSelect || angular.noop)();
|
2558
|
+
|
2559
|
+
if (shouldEmitEvent) {
|
2560
|
+
var viewData = {
|
2561
|
+
type: 'tab',
|
2562
|
+
tabIndex: tabIndex,
|
2563
|
+
historyId: tab.$historyId,
|
2564
|
+
navViewName: tab.navViewName,
|
2565
|
+
hasNavView: !!tab.navViewName,
|
2566
|
+
title: tab.title,
|
2567
|
+
//Skip the first character of href if it's #
|
2568
|
+
url: tab.href,
|
2569
|
+
uiSref: tab.uiSref
|
2570
|
+
};
|
2571
|
+
$scope.$emit('viewState.changeHistory', viewData);
|
2572
|
+
}
|
2573
|
+
}
|
2574
|
+
};
|
2575
|
+
}])
|
2576
|
+
|
2577
|
+
.directive('ionTabs', ['$ionicViewService', '$ionicBind', function($ionicViewService, $ionicBind) {
|
2578
|
+
return {
|
2579
|
+
restrict: 'E',
|
2580
|
+
replace: true,
|
2581
|
+
scope: true,
|
2582
|
+
transclude: true,
|
2583
|
+
controller: '$ionicTabs',
|
2584
|
+
template:
|
2585
|
+
'<div class="view {{$animation}}">' +
|
2586
|
+
'<div class="tabs {{$tabsStyle}} {{$tabsType}}">' +
|
2587
|
+
'</div>' +
|
2588
|
+
'</div>',
|
2589
|
+
compile: function(element, attr, transclude) {
|
2590
|
+
if(angular.isUndefined(attr.tabsType)) attr.$set('tabsType', 'tabs-positive');
|
2591
|
+
|
2592
|
+
return function link($scope, $element, $attr, tabsCtrl) {
|
2593
|
+
|
2594
|
+
$ionicBind($scope, $attr, {
|
2595
|
+
$animation: '@animation',
|
2596
|
+
$tabsStyle: '@tabsStyle',
|
2597
|
+
$tabsType: '@tabsType'
|
2598
|
+
});
|
2599
|
+
|
2600
|
+
tabsCtrl.$scope = $scope;
|
2601
|
+
tabsCtrl.$element = $element;
|
2602
|
+
tabsCtrl.$tabsElement = angular.element($element[0].querySelector('.tabs'));
|
2603
|
+
|
2604
|
+
transclude($scope, function(clone) {
|
2605
|
+
$element.append(clone);
|
2606
|
+
});
|
2607
|
+
};
|
2608
|
+
}
|
2609
|
+
};
|
2610
|
+
}])
|
2611
|
+
|
2612
|
+
.controller('$ionicTab', ['$scope', '$ionicViewService', '$rootScope', '$element',
|
2613
|
+
function($scope, $ionicViewService, $rootScope, $element) {
|
2614
|
+
this.$scope = $scope;
|
2615
|
+
}])
|
2616
|
+
|
2617
|
+
// Generic controller directive
|
2618
|
+
.directive('ionTab', ['$rootScope', '$animate', '$ionicBind', '$compile', '$ionicViewService', function($rootScope, $animate, $ionicBind, $compile, $ionicViewService) {
|
2619
|
+
|
2620
|
+
//Returns ' key="value"' if value exists
|
2621
|
+
function attrStr(k,v) {
|
2622
|
+
return angular.isDefined(v) ? ' ' + k + '="' + v + '"' : '';
|
2623
|
+
}
|
2624
|
+
return {
|
2625
|
+
restrict: 'E',
|
2626
|
+
require: ['^ionTabs', 'ionTab'],
|
2627
|
+
replace: true,
|
2628
|
+
transclude: 'element',
|
2629
|
+
controller: '$ionicTab',
|
2630
|
+
scope: true,
|
2631
|
+
compile: function(element, attr, transclude) {
|
2632
|
+
return function link($scope, $element, $attr, ctrls) {
|
2633
|
+
var childScope, childElement, tabNavElement;
|
2634
|
+
tabsCtrl = ctrls[0],
|
2635
|
+
tabCtrl = ctrls[1];
|
2636
|
+
|
2637
|
+
$ionicBind($scope, $attr, {
|
2638
|
+
animate: '=',
|
2639
|
+
leftButtons: '=',
|
2640
|
+
rightButtons: '=',
|
2641
|
+
onSelect: '&',
|
2642
|
+
onDeselect: '&',
|
2643
|
+
title: '@',
|
2644
|
+
uiSref: '@',
|
2645
|
+
href: '@',
|
2646
|
+
});
|
2647
|
+
|
2648
|
+
tabNavElement = angular.element(
|
2649
|
+
'<ion-tab-nav' +
|
2650
|
+
attrStr('title', attr.title) +
|
2651
|
+
attrStr('icon', attr.icon) +
|
2652
|
+
attrStr('icon-on', attr.iconOn) +
|
2653
|
+
attrStr('icon-off', attr.iconOff) +
|
2654
|
+
attrStr('badge', attr.badge) +
|
2655
|
+
attrStr('badge-style', attr.badgeStyle) +
|
2656
|
+
'></ion-tab-nav>'
|
2657
|
+
);
|
2658
|
+
tabNavElement.data('$ionTabsController', tabsCtrl);
|
2659
|
+
tabNavElement.data('$ionTabController', tabCtrl);
|
2660
|
+
tabsCtrl.$tabsElement.append($compile(tabNavElement)($scope));
|
2661
|
+
|
2662
|
+
tabsCtrl.add($scope);
|
2663
|
+
$scope.$on('$destroy', function() {
|
2664
|
+
tabsCtrl.remove($scope);
|
2665
|
+
tabNavElement.isolateScope().$destroy();
|
2666
|
+
tabNavElement.remove();
|
2667
|
+
});
|
2668
|
+
|
2669
|
+
$scope.$watch('$tabSelected', function(value) {
|
2670
|
+
if (!value) {
|
2671
|
+
$scope.$broadcast('tab.hidden', $scope);
|
2672
|
+
}
|
2673
|
+
childScope && childScope.$destroy();
|
2674
|
+
childScope = null;
|
2675
|
+
childElement && $animate.leave(childElement);
|
2676
|
+
childElement = null;
|
2677
|
+
if (value) {
|
2678
|
+
childScope = $scope.$new();
|
2679
|
+
transclude(childScope, function(clone) {
|
2680
|
+
//remove title attr to stop hover annoyance!
|
2681
|
+
clone[0].removeAttribute('title');
|
2682
|
+
$animate.enter(clone, tabsCtrl.$element);
|
2683
|
+
clone.addClass('pane');
|
2684
|
+
childElement = clone;
|
2685
|
+
});
|
2686
|
+
$scope.$broadcast('tab.shown', $scope);
|
2687
|
+
}
|
2688
|
+
});
|
2689
|
+
|
2690
|
+
transclude($scope, function(clone) {
|
2691
|
+
var navView = clone[0].querySelector('ion-nav-view');
|
2692
|
+
if (navView) {
|
2693
|
+
$scope.navViewName = navView.getAttribute('name');
|
2694
|
+
selectTabIfMatchesState();
|
2695
|
+
$scope.$on('$stateChangeSuccess', selectTabIfMatchesState);
|
2696
|
+
}
|
2697
|
+
});
|
2698
|
+
|
2699
|
+
function selectTabIfMatchesState() {
|
2700
|
+
// this tab's ui-view is the current one, go to it!
|
2701
|
+
if ($ionicViewService.isCurrentStateNavView($scope.navViewName)) {
|
2702
|
+
tabsCtrl.select($scope);
|
2703
|
+
}
|
2704
|
+
}
|
2705
|
+
};
|
2706
|
+
}
|
2707
|
+
};
|
2708
|
+
}])
|
2709
|
+
|
2710
|
+
.directive('ionTabNav', function() {
|
2711
|
+
return {
|
2712
|
+
restrict: 'E',
|
2713
|
+
replace: true,
|
2714
|
+
require: ['^ionTabs', '^ionTab'],
|
2715
|
+
template:
|
2716
|
+
'<a ng-class="{active: isTabActive(), \'has-badge\':badge}" ' +
|
2717
|
+
'ng-click="selectTab($event)" class="tab-item">' +
|
2718
|
+
'<span class="badge {{badgeStyle}}" ng-if="badge">{{badge}}</span>' +
|
2719
|
+
'<i class="icon {{getIconOn()}}" ng-if="getIconOn() && isTabActive()"></i>' +
|
2720
|
+
'<i class="icon {{getIconOff()}}" ng-if="getIconOff() && !isTabActive()"></i>' +
|
2721
|
+
'<span class="tab-title" ng-bind-html="title"></span>' +
|
2722
|
+
'</a>',
|
2723
|
+
scope: {
|
2724
|
+
title: '@',
|
2725
|
+
icon: '@',
|
2726
|
+
iconOn: '@',
|
2727
|
+
iconOff: '@',
|
2728
|
+
badge: '=',
|
2729
|
+
badgeStyle: '@'
|
2730
|
+
},
|
2731
|
+
compile: function(element, attr, transclude) {
|
2732
|
+
return function link($scope, $element, $attrs, ctrls) {
|
2733
|
+
var tabsCtrl = ctrls[0],
|
2734
|
+
tabCtrl = ctrls[1];
|
2735
|
+
|
2736
|
+
$scope.getIconOn = function() {
|
2737
|
+
return $scope.iconOn || $scope.icon;
|
2738
|
+
};
|
2739
|
+
$scope.getIconOff = function() {
|
2740
|
+
return $scope.iconOff || $scope.icon;
|
2741
|
+
};
|
2742
|
+
|
2743
|
+
$scope.isTabActive = function() {
|
2744
|
+
return tabsCtrl.selectedTab === tabCtrl.$scope;
|
2745
|
+
};
|
2746
|
+
$scope.selectTab = function(e) {
|
2747
|
+
e.preventDefault();
|
2748
|
+
tabsCtrl.select(tabCtrl.$scope, true);
|
2749
|
+
};
|
2750
|
+
};
|
2751
|
+
}
|
2752
|
+
};
|
2753
|
+
});
|
2754
|
+
;
|
2755
|
+
(function(ionic) {
|
2756
|
+
'use strict';
|
2757
|
+
|
2758
|
+
angular.module('ionic.ui.toggle', [])
|
2759
|
+
|
2760
|
+
// The Toggle directive is a toggle switch that can be tapped to change
|
2761
|
+
// its value
|
2762
|
+
.directive('ionToggle', function() {
|
2763
|
+
|
1903
2764
|
return {
|
1904
2765
|
restrict: 'E',
|
1905
2766
|
replace: true,
|
1906
|
-
require: '
|
2767
|
+
require: '?ngModel',
|
2768
|
+
scope: {
|
2769
|
+
ngModel: '=?',
|
2770
|
+
ngValue: '=?',
|
2771
|
+
ngChecked: '=?',
|
2772
|
+
ngChange: '&',
|
2773
|
+
ngDisabled: '=?'
|
2774
|
+
},
|
1907
2775
|
transclude: true,
|
1908
|
-
template: '<div class="
|
1909
|
-
|
1910
|
-
|
1911
|
-
|
2776
|
+
template: '<div class="item item-toggle disable-pointer-events">' +
|
2777
|
+
'<div ng-transclude></div>' +
|
2778
|
+
'<label class="toggle enable-pointer-events">' +
|
2779
|
+
'<input type="checkbox" ng-model="ngModel" ng-value="ngValue" ng-change="ngChange()" ng-disabled="ngDisabled">' +
|
2780
|
+
'<div class="track disable-pointer-events">' +
|
2781
|
+
'<div class="handle"></div>' +
|
2782
|
+
'</div>' +
|
2783
|
+
'</label>' +
|
2784
|
+
'</div>',
|
2785
|
+
|
2786
|
+
compile: function(element, attr) {
|
2787
|
+
var input = element.find('input');
|
2788
|
+
if(attr.name) input.attr('name', attr.name);
|
2789
|
+
if(attr.ngChecked) input.attr('ng-checked', 'ngChecked');
|
2790
|
+
if(attr.ngTrueValue) input.attr('ng-true-value', attr.ngTrueValue);
|
2791
|
+
if(attr.ngFalseValue) input.attr('ng-false-value', attr.ngFalseValue);
|
2792
|
+
|
2793
|
+
// return function link($scope, $element, $attr, ngModel) {
|
2794
|
+
// var el, checkbox, track, handle;
|
2795
|
+
|
2796
|
+
// el = $element[0].getElementsByTagName('label')[0];
|
2797
|
+
// checkbox = el.children[0];
|
2798
|
+
// track = el.children[1];
|
2799
|
+
// handle = track.children[0];
|
2800
|
+
|
2801
|
+
// $scope.toggle = new ionic.views.Toggle({
|
2802
|
+
// el: el,
|
2803
|
+
// track: track,
|
2804
|
+
// checkbox: checkbox,
|
2805
|
+
// handle: handle
|
2806
|
+
// });
|
2807
|
+
|
2808
|
+
// ionic.on('drag', function(e) {
|
2809
|
+
//
|
2810
|
+
// $scope.toggle.drag(e);
|
2811
|
+
// }, handle);
|
2812
|
+
|
2813
|
+
// }
|
1912
2814
|
}
|
2815
|
+
|
1913
2816
|
};
|
1914
|
-
})
|
2817
|
+
});
|
1915
2818
|
|
1916
|
-
.
|
1917
|
-
|
1918
|
-
restrict: 'E',
|
1919
|
-
replace: true,
|
1920
|
-
require: '^slideBox',
|
1921
|
-
template: '<div class="slider-pager"><span class="slider-pager-page" ng-repeat="slide in numSlides() track by $index" ng-class="{active: $index == currentSlide}"><i class="icon ion-record"></i></span></div>',
|
1922
|
-
link: function($scope, $element, $attr, slideBox) {
|
1923
|
-
var selectPage = function(index) {
|
1924
|
-
var children = $element[0].children;
|
1925
|
-
var length = children.length;
|
1926
|
-
for(var i = 0; i < length; i++) {
|
1927
|
-
if(i == index) {
|
1928
|
-
children[i].classList.add('active');
|
1929
|
-
} else {
|
1930
|
-
children[i].classList.remove('active');
|
1931
|
-
}
|
1932
|
-
}
|
1933
|
-
};
|
2819
|
+
})(window.ionic);
|
2820
|
+
;
|
1934
2821
|
|
1935
|
-
|
1936
|
-
|
1937
|
-
};
|
2822
|
+
// Similar to Angular's ngTouch, however it uses Ionic's tap detection
|
2823
|
+
// and click simulation. ngClick
|
1938
2824
|
|
1939
|
-
|
1940
|
-
|
1941
|
-
|
2825
|
+
(function(angular, ionic) {'use strict';
|
2826
|
+
|
2827
|
+
|
2828
|
+
angular.module('ionic.ui.touch', [])
|
2829
|
+
|
2830
|
+
.config(['$provide', function($provide) {
|
2831
|
+
$provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
|
2832
|
+
// drop the default ngClick directive
|
2833
|
+
$delegate.shift();
|
2834
|
+
return $delegate;
|
2835
|
+
}]);
|
2836
|
+
}])
|
2837
|
+
|
2838
|
+
.directive('ngClick', ['$parse', function($parse) {
|
2839
|
+
|
2840
|
+
function onTap(e) {
|
2841
|
+
// wire this up to Ionic's tap/click simulation
|
2842
|
+
ionic.tapElement(e.target, e);
|
2843
|
+
}
|
2844
|
+
|
2845
|
+
// Actual linking function.
|
2846
|
+
return function(scope, element, attr) {
|
2847
|
+
|
2848
|
+
var clickHandler = $parse(attr.ngClick);
|
2849
|
+
|
2850
|
+
element.on('click', function(event) {
|
2851
|
+
scope.$apply(function() {
|
2852
|
+
clickHandler(scope, {$event: (event)});
|
2853
|
+
});
|
2854
|
+
});
|
2855
|
+
|
2856
|
+
ionic.on('tap', onTap, element[0]);
|
2857
|
+
|
2858
|
+
// Hack for iOS Safari's benefit. It goes searching for onclick handlers and is liable to click
|
2859
|
+
// something else nearby.
|
2860
|
+
element.onclick = function(event) { };
|
2861
|
+
|
2862
|
+
scope.$on('$destroy', function () {
|
2863
|
+
ionic.off('tap', onTap, element[0]);
|
1942
2864
|
});
|
2865
|
+
|
2866
|
+
};
|
2867
|
+
|
2868
|
+
}])
|
2869
|
+
|
2870
|
+
.directive('ionStopEvent', function () {
|
2871
|
+
function stopEvent(e) {
|
2872
|
+
e.stopPropagation();
|
1943
2873
|
}
|
1944
|
-
|
2874
|
+
return {
|
2875
|
+
restrict: 'A',
|
2876
|
+
link: function (scope, element, attr) {
|
2877
|
+
element.bind(attr.ionStopEvent, stopEvent);
|
2878
|
+
}
|
2879
|
+
};
|
2880
|
+
});
|
1945
2881
|
|
1946
|
-
});
|
1947
2882
|
|
1948
|
-
})();
|
2883
|
+
})(window.angular, window.ionic);
|
1949
2884
|
;
|
1950
|
-
|
2885
|
+
(function() {
|
2886
|
+
'use strict';
|
1951
2887
|
|
1952
2888
|
/**
|
1953
2889
|
* @description
|
2890
|
+
* The NavController is a navigation stack View Controller modelled off of
|
2891
|
+
* UINavigationController from Cocoa Touch. With the Nav Controller, you can
|
2892
|
+
* "push" new "pages" on to the navigation stack, and then pop them off to go
|
2893
|
+
* back. The NavController controls a navigation bar with a back button and title
|
2894
|
+
* which updates as the pages switch.
|
1954
2895
|
*
|
1955
|
-
* The
|
1956
|
-
*
|
2896
|
+
* The NavController makes sure to not recycle scopes of old pages
|
2897
|
+
* so that a pop will still show the same state that the user left.
|
2898
|
+
*
|
2899
|
+
* However, once a page is popped, its scope is destroyed and will have to be
|
2900
|
+
* recreated then next time it is pushed.
|
2901
|
+
*
|
2902
|
+
*/
|
2903
|
+
|
2904
|
+
angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gesture', 'ngSanitize'])
|
2905
|
+
|
2906
|
+
/**
|
2907
|
+
* Our Nav Bar directive which updates as the controller state changes.
|
1957
2908
|
*/
|
2909
|
+
.directive('ionNavBar', ['$ionicViewService', '$rootScope', '$animate', '$compile',
|
2910
|
+
function( $ionicViewService, $rootScope, $animate, $compile) {
|
1958
2911
|
|
1959
|
-
.directive('tabs', function() {
|
1960
2912
|
return {
|
1961
2913
|
restrict: 'E',
|
1962
2914
|
replace: true,
|
1963
|
-
scope:
|
1964
|
-
|
1965
|
-
|
1966
|
-
|
1967
|
-
|
1968
|
-
|
1969
|
-
|
1970
|
-
|
1971
|
-
|
1972
|
-
|
1973
|
-
|
1974
|
-
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
1991
|
-
|
1992
|
-
|
1993
|
-
|
1994
|
-
|
1995
|
-
|
1996
|
-
|
1997
|
-
|
1998
|
-
|
1999
|
-
|
2000
|
-
|
2001
|
-
|
2002
|
-
|
2003
|
-
|
2004
|
-
|
2005
|
-
|
2006
|
-
|
2007
|
-
$scope.tabsStyle = $attr.tabsStyle;
|
2008
|
-
$scope.animation = $attr.animation;
|
2009
|
-
|
2010
|
-
$scope.animateNav = $scope.$eval($attr.animateNav);
|
2011
|
-
if($scope.animateNav !== false) {
|
2012
|
-
$scope.animateNav = true;
|
2013
|
-
}
|
2915
|
+
scope: {
|
2916
|
+
animation: '@',
|
2917
|
+
type: '@',
|
2918
|
+
backType: '@backButtonType',
|
2919
|
+
backLabel: '@backButtonLabel',
|
2920
|
+
backIcon: '@backButtonIcon',
|
2921
|
+
alignTitle: '@'
|
2922
|
+
},
|
2923
|
+
controller: function() {},
|
2924
|
+
template:
|
2925
|
+
'<header class="bar bar-header nav-bar{{navBarClass()}}">' +
|
2926
|
+
'<ion-nav-back-button ng-if="(backType || backLabel || backIcon)" ' +
|
2927
|
+
'type="backType" label="backLabel" icon="backIcon" class="hide" ' +
|
2928
|
+
'ng-class="{\'hide\': !backButtonEnabled}">' +
|
2929
|
+
'</ion-nav-back-button>' +
|
2930
|
+
'<div class="buttons left-buttons"> ' +
|
2931
|
+
'<button ng-click="button.tap($event)" ng-repeat="button in leftButtons" ' +
|
2932
|
+
'class="button no-animation {{button.type}}" ng-bind-html="button.content">' +
|
2933
|
+
'</button>' +
|
2934
|
+
'</div>' +
|
2935
|
+
|
2936
|
+
'<h1 ng-bind-html="title" class="title"></h1>' +
|
2937
|
+
|
2938
|
+
'<div class="buttons right-buttons"> ' +
|
2939
|
+
'<button ng-click="button.tap($event)" ng-repeat="button in rightButtons" '+
|
2940
|
+
'class="button no-animation {{button.type}}" ng-bind-html="button.content">' +
|
2941
|
+
'</button>' +
|
2942
|
+
'</div>' +
|
2943
|
+
'</header>',
|
2944
|
+
compile: function(tElement, tAttrs) {
|
2945
|
+
|
2946
|
+
return function link($scope, $element, $attr) {
|
2947
|
+
//defaults
|
2948
|
+
$scope.backButtonEnabled = false;
|
2949
|
+
$scope.animateEnabled = true;
|
2950
|
+
$scope.isReverse = false;
|
2951
|
+
$scope.isInvisible = true;
|
2952
|
+
|
2953
|
+
$scope.navBarClass = function() {
|
2954
|
+
return ($scope.type ? ' ' + $scope.type : '') +
|
2955
|
+
($scope.isReverse ? ' reverse' : '') +
|
2956
|
+
($scope.isInvisible ? ' invisible' : '') +
|
2957
|
+
(!$scope.animationDisabled && $scope.animation ? ' ' + $scope.animation : '');
|
2958
|
+
};
|
2014
2959
|
|
2015
|
-
|
2016
|
-
|
2017
|
-
|
2018
|
-
|
2960
|
+
// Initialize our header bar view which will handle
|
2961
|
+
// resizing and aligning our title labels
|
2962
|
+
var hb = new ionic.views.HeaderBar({
|
2963
|
+
el: $element[0],
|
2964
|
+
alignTitle: $scope.alignTitle || 'center'
|
2019
2965
|
});
|
2966
|
+
$scope.headerBarView = hb;
|
2020
2967
|
|
2021
|
-
|
2022
|
-
|
2023
|
-
|
2024
|
-
}
|
2968
|
+
//Navbar events
|
2969
|
+
$scope.$on('viewState.viewEnter', function(e, data) {
|
2970
|
+
updateHeaderData(data);
|
2025
2971
|
});
|
2026
|
-
|
2027
|
-
|
2028
|
-
//$element.removeClass($scope.animation + ' ' + $scope.animation + '-reverse');
|
2029
|
-
$element.addClass($scope.activeAnimation);
|
2972
|
+
$scope.$on('viewState.showNavBar', function(e, showNavBar) {
|
2973
|
+
$scope.isInvisible = !showNavBar;
|
2030
2974
|
});
|
2031
|
-
|
2032
|
-
|
2975
|
+
|
2976
|
+
// All of these these are emitted from children of a sibling scope,
|
2977
|
+
// so we listen on parent so we can catch them as they bubble up
|
2978
|
+
var unregisterEventListeners = [
|
2979
|
+
$scope.$parent.$on('$viewHistory.historyChange', function(e, data) {
|
2980
|
+
$scope.backButtonEnabled = !!data.showBack;
|
2981
|
+
}),
|
2982
|
+
$scope.$parent.$on('viewState.leftButtonsChanged', function(e, data) {
|
2983
|
+
$scope.leftButtons = data;
|
2984
|
+
}),
|
2985
|
+
$scope.$parent.$on('viewState.rightButtonsChanged', function(e, data) {
|
2986
|
+
$scope.rightButtons = data;
|
2987
|
+
}),
|
2988
|
+
$scope.$parent.$on('viewState.showBackButton', function(e, data) {
|
2989
|
+
$scope.backButtonEnabled = !!data;
|
2990
|
+
}),
|
2991
|
+
$scope.$parent.$on('viewState.titleUpdated', function(e, data) {
|
2992
|
+
$scope.title = data && data.title || '';
|
2993
|
+
})
|
2994
|
+
];
|
2995
|
+
$scope.$on('$destroy', function() {
|
2996
|
+
for (var i=0; i<unregisterEventListeners.length; i++)
|
2997
|
+
unregisterEventListeners[i]();
|
2033
2998
|
});
|
2034
|
-
};
|
2035
|
-
}
|
2036
|
-
};
|
2037
|
-
})
|
2038
2999
|
|
2039
|
-
|
2040
|
-
.directive('tab', ['$animate', '$parse', function($animate, $parse) {
|
2041
|
-
return {
|
2042
|
-
restrict: 'E',
|
2043
|
-
require: '^tabs',
|
2044
|
-
scope: true,
|
2045
|
-
transclude: 'element',
|
2046
|
-
compile: function(element, attr, transclude) {
|
2047
|
-
return function($scope, $element, $attr, tabsCtrl) {
|
2048
|
-
var childScope, childElement;
|
3000
|
+
function updateHeaderData(data) {
|
2049
3001
|
|
2050
|
-
|
2051
|
-
|
2052
|
-
|
2053
|
-
|
3002
|
+
if (angular.isDefined(data.hideBackButton)) {
|
3003
|
+
$scope.backButtonEnabled = !!data.hideBackButton;
|
3004
|
+
}
|
3005
|
+
$scope.isReverse = data.navDirection == 'back';
|
3006
|
+
$scope.animateEnabled = !!(data.navDirection && data.animate !== false);
|
2054
3007
|
|
2055
|
-
|
2056
|
-
|
3008
|
+
$scope.leftButtons = data.leftButtons;
|
3009
|
+
$scope.rightButtons = data.rightButtons;
|
3010
|
+
$scope.oldTitle = $scope.title;
|
3011
|
+
$scope.title = data && data.title || '';
|
2057
3012
|
|
2058
|
-
|
2059
|
-
|
3013
|
+
//If no animation, we're done!
|
3014
|
+
if (!$scope.animateEnabled) {
|
3015
|
+
hb.align();
|
3016
|
+
return;
|
3017
|
+
} else {
|
3018
|
+
animateTitles();
|
3019
|
+
}
|
2060
3020
|
}
|
2061
3021
|
|
2062
|
-
|
2063
|
-
|
2064
|
-
$scope.animate = $scope.$eval($attr.animate);
|
3022
|
+
function animateTitles() {
|
3023
|
+
var oldTitleEl, newTitleEl, currentTitles;
|
2065
3024
|
|
2066
|
-
|
2067
|
-
|
2068
|
-
|
2069
|
-
|
2070
|
-
|
2071
|
-
|
2072
|
-
var leftButtonsGet = $parse($attr.leftButtons);
|
2073
|
-
$scope.$watch(leftButtonsGet, function(value) {
|
2074
|
-
$scope.leftButtons = value;
|
2075
|
-
if($scope.doesUpdateNavRouter) {
|
2076
|
-
$scope.$emit('navRouter.leftButtonsChanged', $scope.rightButtons);
|
3025
|
+
//If we have any title right now (or more than one, they could be transitioning on switch),
|
3026
|
+
//replace the first one with an oldTitle element
|
3027
|
+
currentTitles = $element[0].querySelectorAll('.title');
|
3028
|
+
if (currentTitles.length) {
|
3029
|
+
oldTitleEl = $compile('<h1 ng-bind-html="oldTitle" class="title"></h1>')($scope);
|
3030
|
+
angular.element(currentTitles[0]).replaceWith(oldTitleEl);
|
2077
3031
|
}
|
2078
|
-
|
3032
|
+
//Compile new title
|
3033
|
+
newTitleEl = $compile('<h1 class="title invisible" ng-bind-html="title"></h1>')($scope);
|
2079
3034
|
|
2080
|
-
|
2081
|
-
|
2082
|
-
$scope.rightButtons = value;
|
2083
|
-
});
|
3035
|
+
//Animate in one frame
|
3036
|
+
ionic.requestAnimationFrame(function() {
|
2084
3037
|
|
2085
|
-
|
2086
|
-
|
2087
|
-
$scope.$watch('isVisible', function(value) {
|
2088
|
-
if(childElement) {
|
2089
|
-
$animate.leave(childElement);
|
2090
|
-
$scope.$broadcast('tab.hidden');
|
2091
|
-
childElement = undefined;
|
2092
|
-
}
|
2093
|
-
if(childScope) {
|
2094
|
-
childScope.$destroy();
|
2095
|
-
childScope = undefined;
|
2096
|
-
}
|
2097
|
-
if(value) {
|
2098
|
-
childScope = $scope.$new();
|
2099
|
-
transclude(childScope, function(clone) {
|
2100
|
-
childElement = clone;
|
3038
|
+
oldTitleEl && $animate.leave(angular.element(oldTitleEl));
|
2101
3039
|
|
2102
|
-
|
3040
|
+
var insert = oldTitleEl && angular.element(oldTitleEl) || null;
|
3041
|
+
$animate.enter(newTitleEl, $element, insert, function() {
|
3042
|
+
hb.align();
|
3043
|
+
});
|
2103
3044
|
|
2104
|
-
|
2105
|
-
|
2106
|
-
if(
|
2107
|
-
//
|
2108
|
-
|
2109
|
-
$scope.$emit('navRouter.pageShown', {
|
2110
|
-
title: $scope.title,
|
2111
|
-
rightButtons: $scope.rightButtons,
|
2112
|
-
leftButtons: $scope.leftButtons,
|
2113
|
-
hideBackButton: $scope.hideBackButton,
|
2114
|
-
animate: $scope.animateNav
|
2115
|
-
});
|
2116
|
-
}
|
2117
|
-
//$scope.$emit('navRouter.titleChanged', $scope.title);
|
3045
|
+
//Cleanup any old titles leftover (besides the one we already did replaceWith on)
|
3046
|
+
angular.forEach(currentTitles, function(el) {
|
3047
|
+
if (el && el.parentNode) {
|
3048
|
+
//Use .remove() to cleanup things like .data()
|
3049
|
+
angular.element(el).remove();
|
2118
3050
|
}
|
2119
|
-
$scope.$broadcast('tab.shown');
|
2120
3051
|
});
|
2121
|
-
|
2122
|
-
|
3052
|
+
|
3053
|
+
//$apply so bindings fire
|
3054
|
+
$scope.$digest();
|
3055
|
+
|
3056
|
+
//Stop flicker of new title on ios7
|
3057
|
+
ionic.requestAnimationFrame(function() {
|
3058
|
+
newTitleEl[0].classList.remove('invisible');
|
3059
|
+
});
|
3060
|
+
});
|
3061
|
+
}
|
2123
3062
|
};
|
2124
3063
|
}
|
2125
3064
|
};
|
2126
3065
|
}])
|
2127
3066
|
|
2128
|
-
|
2129
|
-
.directive('tabControllerBar', function() {
|
3067
|
+
.directive('ionNavBarTitle', function() {
|
2130
3068
|
return {
|
2131
|
-
restrict: '
|
2132
|
-
require: '^
|
2133
|
-
|
2134
|
-
|
2135
|
-
|
2136
|
-
|
2137
|
-
|
2138
|
-
'</div>',
|
2139
|
-
link: function($scope, $element, $attr, tabsCtrl) {
|
2140
|
-
$element.addClass($scope.tabsType);
|
2141
|
-
$element.addClass($scope.tabsStyle);
|
3069
|
+
restrict: 'A',
|
3070
|
+
require: '^ionNavBar',
|
3071
|
+
link: function($scope, $element, $attr, navBarCtrl) {
|
3072
|
+
$scope.headerBarView && $scope.headerBarView.align();
|
3073
|
+
$element.on('$animate:close', function() {
|
3074
|
+
$scope.headerBarView && $scope.headerBarView.align();
|
3075
|
+
});
|
2142
3076
|
}
|
2143
3077
|
};
|
2144
3078
|
})
|
2145
3079
|
|
2146
|
-
|
3080
|
+
/*
|
3081
|
+
* Directive to put on an element that has 'invisible' class when rendered.
|
3082
|
+
* This removes the visible class one frame later.
|
3083
|
+
* Fixes flickering in iOS7 and old android.
|
3084
|
+
* Used in title and back button
|
3085
|
+
*/
|
3086
|
+
.directive('ionAsyncVisible', function() {
|
3087
|
+
return function($scope, $element) {
|
3088
|
+
ionic.requestAnimationFrame(function() {
|
3089
|
+
$element[0].classList.remove('invisible');
|
3090
|
+
});
|
3091
|
+
};
|
3092
|
+
})
|
3093
|
+
|
3094
|
+
.directive('ionView', ['$ionicViewService', '$rootScope', '$animate',
|
3095
|
+
function( $ionicViewService, $rootScope, $animate) {
|
2147
3096
|
return {
|
2148
|
-
restrict: '
|
2149
|
-
|
2150
|
-
require: '^tabs',
|
3097
|
+
restrict: 'EA',
|
3098
|
+
priority: 1000,
|
2151
3099
|
scope: {
|
2152
|
-
|
3100
|
+
leftButtons: '=',
|
3101
|
+
rightButtons: '=',
|
3102
|
+
title: '=',
|
2153
3103
|
icon: '@',
|
2154
3104
|
iconOn: '@',
|
2155
3105
|
iconOff: '@',
|
2156
|
-
|
2157
|
-
|
2158
|
-
|
3106
|
+
type: '@',
|
3107
|
+
alignTitle: '@',
|
3108
|
+
hideBackButton: '@',
|
3109
|
+
hideNavBar: '@',
|
3110
|
+
animation: '@'
|
2159
3111
|
},
|
2160
|
-
|
2161
|
-
|
2162
|
-
|
2163
|
-
|
2164
|
-
|
2165
|
-
|
3112
|
+
|
3113
|
+
compile: function(tElement, tAttrs, transclude) {
|
3114
|
+
tElement.addClass('pane');
|
3115
|
+
tElement[0].removeAttribute('title');
|
3116
|
+
|
3117
|
+
return function link($scope, $element, $attr) {
|
3118
|
+
|
3119
|
+
$rootScope.$broadcast('viewState.viewEnter', {
|
3120
|
+
title: $scope.title,
|
3121
|
+
navDirection: $scope.$navDirection || $scope.$parent.$navDirection
|
3122
|
+
});
|
3123
|
+
|
3124
|
+
// Should we hide a back button when this tab is shown
|
3125
|
+
$scope.hideBackButton = $scope.$eval($scope.hideBackButton);
|
3126
|
+
if($scope.hideBackButton) {
|
3127
|
+
$rootScope.$broadcast('viewState.showBackButton', false);
|
3128
|
+
}
|
3129
|
+
|
3130
|
+
// Should the nav bar be hidden for this view or not?
|
3131
|
+
$rootScope.$broadcast('viewState.showNavBar', ($scope.hideNavBar !== 'true') );
|
3132
|
+
|
3133
|
+
// watch for changes in the left buttons
|
3134
|
+
$scope.$watch('leftButtons', function(value) {
|
3135
|
+
$scope.$emit('viewState.leftButtonsChanged', $scope.leftButtons);
|
3136
|
+
});
|
3137
|
+
|
3138
|
+
$scope.$watch('rightButtons', function(val) {
|
3139
|
+
$scope.$emit('viewState.rightButtonsChanged', $scope.rightButtons);
|
3140
|
+
});
|
3141
|
+
|
3142
|
+
// watch for changes in the title
|
3143
|
+
$scope.$watch('title', function(val) {
|
3144
|
+
$scope.$emit('viewState.titleUpdated', $scope);
|
3145
|
+
});
|
2166
3146
|
};
|
2167
|
-
}
|
2168
|
-
template:
|
2169
|
-
'<a ng-class="{active:active}" ng-click="selectTab()" class="tab-item">' +
|
2170
|
-
'<i class="{{icon}}" ng-if="icon"></i>' +
|
2171
|
-
'<i class="{{iconOn}}" ng-if="active"></i>' +
|
2172
|
-
'<i class="{{iconOff}}" ng-if="!active"></i> {{title}}' +
|
2173
|
-
'</a>'
|
3147
|
+
}
|
2174
3148
|
};
|
2175
|
-
})
|
3149
|
+
}])
|
3150
|
+
|
3151
|
+
|
3152
|
+
.directive('ionNavBackButton', ['$ionicViewService', '$rootScope',
|
3153
|
+
function($ionicViewService, $rootScope) {
|
3154
|
+
|
3155
|
+
function goBack(e) {
|
3156
|
+
var backView = $ionicViewService.getBackView();
|
3157
|
+
backView && backView.go();
|
3158
|
+
e.alreadyHandled = true;
|
3159
|
+
return false;
|
3160
|
+
}
|
2176
3161
|
|
2177
|
-
.directive('tabBar', function() {
|
2178
3162
|
return {
|
2179
3163
|
restrict: 'E',
|
3164
|
+
scope: {
|
3165
|
+
type: '=',
|
3166
|
+
label: '=',
|
3167
|
+
icon: '='
|
3168
|
+
},
|
2180
3169
|
replace: true,
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
3170
|
+
template:
|
3171
|
+
'<button ng-click="goBack($event)" class="button back-button {{type}} ' +
|
3172
|
+
'{{(icon && !label) ? \'icon \' + icon : \'\'}}">' +
|
3173
|
+
'<i ng-if="icon && label" class="icon {{icon}}"></i> ' +
|
3174
|
+
'{{label}}' +
|
3175
|
+
'</button>',
|
3176
|
+
link: function($scope) {
|
3177
|
+
$scope.goBack = goBack;
|
3178
|
+
}
|
2184
3179
|
};
|
2185
|
-
})
|
2186
|
-
|
2187
|
-
;
|
2188
|
-
(function(ionic) {
|
2189
|
-
'use strict';
|
3180
|
+
}])
|
2190
3181
|
|
2191
|
-
|
3182
|
+
.directive('ionNavView', ['$ionicViewService', '$state', '$compile', '$controller', '$animate',
|
3183
|
+
function( $ionicViewService, $state, $compile, $controller, $animate) {
|
3184
|
+
// IONIC's fork of Angular UI Router, v0.2.7
|
3185
|
+
// the navView handles registering views in the history, which animation to use, and which
|
3186
|
+
var viewIsUpdating = false;
|
2192
3187
|
|
2193
|
-
|
2194
|
-
// its value
|
2195
|
-
.directive('toggle', function() {
|
2196
|
-
return {
|
3188
|
+
var directive = {
|
2197
3189
|
restrict: 'E',
|
2198
|
-
|
2199
|
-
|
2200
|
-
|
2201
|
-
|
3190
|
+
terminal: true,
|
3191
|
+
priority: 2000,
|
3192
|
+
transclude: true,
|
3193
|
+
controller: ['$scope', function($scope) {
|
3194
|
+
this.setNextAnimation = function(anim) {
|
3195
|
+
$scope.$nextAnimation = anim;
|
3196
|
+
};
|
3197
|
+
}],
|
3198
|
+
compile: function (element, attr, transclude) {
|
3199
|
+
return function(scope, element, attr, navViewCtrl) {
|
3200
|
+
var viewScope, viewLocals,
|
3201
|
+
name = attr[directive.name] || attr.name || '',
|
3202
|
+
onloadExp = attr.onload || '',
|
3203
|
+
initialView = transclude(scope);
|
3204
|
+
|
3205
|
+
// Put back the compiled initial view
|
3206
|
+
element.append(initialView);
|
3207
|
+
|
3208
|
+
// Find the details of the parent view directive (if any) and use it
|
3209
|
+
// to derive our own qualified view name, then hang our own details
|
3210
|
+
// off the DOM so child directives can find it.
|
3211
|
+
var parent = element.parent().inheritedData('$uiView');
|
3212
|
+
if (name.indexOf('@') < 0) name = name + '@' + (parent ? parent.state.name : '');
|
3213
|
+
var view = { name: name, state: null };
|
3214
|
+
element.data('$uiView', view);
|
3215
|
+
|
3216
|
+
var eventHook = function() {
|
3217
|
+
if (viewIsUpdating) return;
|
3218
|
+
viewIsUpdating = true;
|
3219
|
+
|
3220
|
+
try { updateView(true); } catch (e) {
|
3221
|
+
viewIsUpdating = false;
|
3222
|
+
throw e;
|
3223
|
+
}
|
3224
|
+
viewIsUpdating = false;
|
3225
|
+
};
|
2202
3226
|
|
2203
|
-
|
2204
|
-
|
3227
|
+
scope.$on('$stateChangeSuccess', eventHook);
|
3228
|
+
scope.$on('$viewContentLoading', eventHook);
|
3229
|
+
updateView(false);
|
2205
3230
|
|
2206
|
-
|
3231
|
+
function updateView(doAnimate) {
|
3232
|
+
//===false because $animate.enabled() is a noop without angular-animate included
|
3233
|
+
if ($animate.enabled() === false) {
|
3234
|
+
doAnimate = false;
|
3235
|
+
}
|
2207
3236
|
|
2208
|
-
|
2209
|
-
|
3237
|
+
var locals = $state.$current && $state.$current.locals[name];
|
3238
|
+
if (locals === viewLocals) return; // nothing to do
|
3239
|
+
var renderer = $ionicViewService.getRenderer(element, attr, scope);
|
2210
3240
|
|
2211
|
-
|
3241
|
+
// Destroy previous view scope
|
3242
|
+
if (viewScope) {
|
3243
|
+
viewScope.$destroy();
|
3244
|
+
viewScope = null;
|
3245
|
+
}
|
2212
3246
|
|
2213
|
-
|
2214
|
-
|
2215
|
-
|
2216
|
-
handle: handle[0]
|
2217
|
-
});
|
3247
|
+
if (!locals) {
|
3248
|
+
viewLocals = null;
|
3249
|
+
view.state = null;
|
2218
3250
|
|
2219
|
-
|
2220
|
-
|
2221
|
-
|
2222
|
-
|
3251
|
+
// Restore the initial view
|
3252
|
+
return element.append(initialView);
|
3253
|
+
}
|
3254
|
+
|
3255
|
+
var newElement = angular.element('<div></div>').html(locals.$template).contents();
|
3256
|
+
var viewRegisterData = renderer().register(newElement);
|
3257
|
+
|
3258
|
+
// Remove existing content
|
3259
|
+
renderer(doAnimate).leave();
|
3260
|
+
|
3261
|
+
viewLocals = locals;
|
3262
|
+
view.state = locals.$$state;
|
3263
|
+
|
3264
|
+
renderer(doAnimate).enter(newElement);
|
3265
|
+
|
3266
|
+
var link = $compile(newElement);
|
3267
|
+
viewScope = scope.$new();
|
3268
|
+
|
3269
|
+
viewScope.$navDirection = viewRegisterData.navDirection;
|
3270
|
+
|
3271
|
+
if (locals.$$controller) {
|
3272
|
+
locals.$scope = viewScope;
|
3273
|
+
var controller = $controller(locals.$$controller, locals);
|
3274
|
+
element.children().data('$ngControllerController', controller);
|
3275
|
+
}
|
3276
|
+
link(viewScope);
|
3277
|
+
|
3278
|
+
var viewHistoryData = $ionicViewService._getView(viewRegisterData.viewId) || {};
|
3279
|
+
viewScope.$broadcast('$viewContentLoaded', viewHistoryData);
|
2223
3280
|
|
2224
|
-
|
2225
|
-
|
3281
|
+
if (onloadExp) viewScope.$eval(onloadExp);
|
3282
|
+
|
3283
|
+
newElement = null;
|
3284
|
+
}
|
2226
3285
|
};
|
2227
3286
|
}
|
2228
3287
|
};
|
2229
|
-
|
3288
|
+
return directive;
|
3289
|
+
}]);
|
2230
3290
|
|
2231
|
-
})(
|
3291
|
+
})();
|
2232
3292
|
;
|
2233
3293
|
(function() {
|
2234
3294
|
'use strict';
|
2235
3295
|
|
2236
3296
|
angular.module('ionic.ui.virtRepeat', [])
|
2237
3297
|
|
2238
|
-
.directive('
|
3298
|
+
.directive('ionVirtRepeat', function() {
|
2239
3299
|
return {
|
2240
3300
|
require: ['?ngModel', '^virtualList'],
|
2241
3301
|
transclude: 'element',
|
@@ -2385,7 +3445,7 @@ angular.module('ionic.ui.virtualRepeat', [])
|
|
2385
3445
|
* scrolling to only render items that are showing or will be showing
|
2386
3446
|
* if a scroll is made.
|
2387
3447
|
*/
|
2388
|
-
.directive('
|
3448
|
+
.directive('ionVirtualRepeat', ['$log', function($log) {
|
2389
3449
|
return {
|
2390
3450
|
require: ['?ngModel, ^virtualList'],
|
2391
3451
|
transclude: 'element',
|
@@ -2581,3 +3641,64 @@ angular.module('ionic.ui.virtualRepeat', [])
|
|
2581
3641
|
}]);
|
2582
3642
|
|
2583
3643
|
})(ionic);
|
3644
|
+
;
|
3645
|
+
(function() {
|
3646
|
+
'use strict';
|
3647
|
+
|
3648
|
+
angular.module('ionic.ui.scroll')
|
3649
|
+
|
3650
|
+
.controller('$ionicScroll', ['$scope', 'scrollViewOptions', '$timeout', '$ionicScrollDelegate', '$window', function($scope, scrollViewOptions, $timeout, $ionicScrollDelegate, $window) {
|
3651
|
+
|
3652
|
+
var self = this;
|
3653
|
+
|
3654
|
+
var element = this.element = scrollViewOptions.el;
|
3655
|
+
var scrollView = this.scrollView = new ionic.views.Scroll(scrollViewOptions);
|
3656
|
+
|
3657
|
+
if (!angular.isDefined(scrollViewOptions.bouncing)) {
|
3658
|
+
ionic.Platform.ready(function() {
|
3659
|
+
scrollView.options.bouncing = !ionic.Platform.isAndroid();
|
3660
|
+
});
|
3661
|
+
}
|
3662
|
+
|
3663
|
+
var $element = this.$element = angular.element(element);
|
3664
|
+
|
3665
|
+
//Attach self to element as a controller so other directives can require this controller
|
3666
|
+
//through `require: '$ionicScroll'
|
3667
|
+
$element.data('$$ionicScrollController', this);
|
3668
|
+
|
3669
|
+
//Register delegate for event handling
|
3670
|
+
$ionicScrollDelegate.register($scope, $element, scrollView);
|
3671
|
+
|
3672
|
+
$window.addEventListener('resize', resize);
|
3673
|
+
$scope.$on('$destroy', function() {
|
3674
|
+
$window.removeEventListener('resize', resize);
|
3675
|
+
});
|
3676
|
+
function resize() {
|
3677
|
+
scrollView.resize();
|
3678
|
+
}
|
3679
|
+
|
3680
|
+
$timeout(function() {
|
3681
|
+
scrollView.run();
|
3682
|
+
|
3683
|
+
self.refresher = element.querySelector('.scroll-refresher');
|
3684
|
+
|
3685
|
+
// Activate pull-to-refresh
|
3686
|
+
if(self.refresher) {
|
3687
|
+
var refresherHeight = self.refresher.clientHeight || 0;
|
3688
|
+
scrollView.activatePullToRefresh(refresherHeight, function() {
|
3689
|
+
self.refresher.classList.add('active');
|
3690
|
+
$scope.$onRefreshOpening && $scope.$onRefreshOpening();
|
3691
|
+
}, function() {
|
3692
|
+
self.refresher.classList.remove('refreshing');
|
3693
|
+
self.refresher.classList.remove('active');
|
3694
|
+
}, function() {
|
3695
|
+
self.refresher.classList.add('refreshing');
|
3696
|
+
$scope.$onRefresh && $scope.$onRefresh();
|
3697
|
+
$scope.$parent.$broadcast('scroll.onRefresh');
|
3698
|
+
});
|
3699
|
+
}
|
3700
|
+
});
|
3701
|
+
|
3702
|
+
}]);
|
3703
|
+
|
3704
|
+
})();
|