├── .cordova └── config.json ├── .gitignore ├── LICENSE ├── README.md ├── platforms └── .gitignore ├── plugins └── .gitignore └── www ├── config.xml ├── css ├── app.css ├── ionic.css ├── ionic.min.css └── themes │ ├── ionic-ios7.css │ └── ionic-ios7.min.css ├── fonts ├── ionicons.eot ├── ionicons.svg ├── ionicons.ttf └── ionicons.woff ├── img └── ionic.png ├── index.html ├── js ├── angular │ ├── angular-animate.js │ ├── angular-animate.min.js │ ├── angular-animate.min.js.map │ ├── angular-cookies.js │ ├── angular-cookies.min.js │ ├── angular-cookies.min.js.map │ ├── angular-csp.css │ ├── angular-loader.js │ ├── angular-loader.min.js │ ├── angular-loader.min.js.map │ ├── angular-mocks.js │ ├── angular-resource.js │ ├── angular-resource.min.js │ ├── angular-resource.min.js.map │ ├── angular-route.js │ ├── angular-route.min.js │ ├── angular-route.min.js.map │ ├── angular-sanitize.js │ ├── angular-sanitize.min.js │ ├── angular-sanitize.min.js.map │ ├── angular-scenario.js │ ├── angular-touch.js │ ├── angular-touch.min.js │ ├── angular-touch.min.js.map │ ├── angular.js │ ├── angular.min.js │ ├── angular.min.js.map │ ├── errors.json │ ├── version.json │ └── version.txt ├── app.js ├── controllers.js ├── ionic-angular.js ├── ionic-angular.min.js ├── ionic.js ├── ionic.min.js └── services.js ├── res ├── icon │ ├── android │ │ ├── icon-36-ldpi.png │ │ ├── icon-48-mdpi.png │ │ ├── icon-72-hdpi.png │ │ └── icon-96-xhdpi.png │ ├── bada-wac │ │ ├── icon-48-type5.png │ │ ├── icon-50-type3.png │ │ └── icon-80-type4.png │ ├── bada │ │ └── icon-128.png │ ├── blackberry │ │ └── icon-80.png │ ├── ios │ │ ├── icon-57-2x.png │ │ ├── icon-57.png │ │ ├── icon-72-2x.png │ │ └── icon-72.png │ ├── tizen │ │ └── icon-128.png │ ├── webos │ │ └── icon-64.png │ └── windows-phone │ │ ├── icon-173-tile.png │ │ ├── icon-48.png │ │ └── icon-62-tile.png └── screen │ ├── android │ ├── screen-hdpi-landscape.png │ ├── screen-hdpi-portrait.png │ ├── screen-ldpi-landscape.png │ ├── screen-ldpi-portrait.png │ ├── screen-mdpi-landscape.png │ ├── screen-mdpi-portrait.png │ ├── screen-xhdpi-landscape.png │ └── screen-xhdpi-portrait.png │ ├── bada-wac │ ├── screen-type3.png │ ├── screen-type4.png │ └── screen-type5.png │ ├── bada │ └── screen-portrait.png │ ├── blackberry │ └── screen-225.png │ ├── ios │ ├── screen-ipad-landscape-2x.png │ ├── screen-ipad-landscape.png │ ├── screen-ipad-portrait-2x.png │ ├── screen-ipad-portrait.png │ ├── screen-iphone-landscape-2x.png │ ├── screen-iphone-landscape.png │ ├── screen-iphone-portrait-2x.png │ ├── screen-iphone-portrait-568h-2x.png │ └── screen-iphone-portrait.png │ ├── tizen │ └── README.md │ ├── webos │ └── screen-64.png │ └── windows-phone │ └── screen-portrait.jpg └── templates ├── app.html └── pet.html /.cordova/config.json: -------------------------------------------------------------------------------- 1 | {"id":"com.ionicframework.starter","name":"StarterApp"} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.keystore 2 | *.sw* 3 | platforms/^.* 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Drifty 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ionic-intro 2 | =========== 3 | 4 | A demo app for showing an intro tutorial for your apps 5 | -------------------------------------------------------------------------------- /platforms/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /plugins/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /www/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | StarterApp 4 | 5 | A sample Ionic Framework app using Cordova and AngularJS 6 | 7 | 8 | Apache Cordova Team 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /www/css/app.css: -------------------------------------------------------------------------------- 1 | #splash-page { 2 | background-color: white; 3 | } 4 | #logo { 5 | background: url('../img/ionic.png') no-repeat transparent; 6 | width: 128px; 7 | height: 128px; 8 | position: absolute; 9 | top: 50%; 10 | left: 50%; 11 | margin: -64px 0px 0px -64px; 12 | } 13 | -------------------------------------------------------------------------------- /www/css/themes/ionic-ios7.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /*! 3 | * Copyright 2013 Drifty Co. 4 | * http://drifty.com/ 5 | 6 | * Ionic - a powerful HTML5 mobile app framework. 7 | * http://ionicframework.com/ 8 | * 9 | * 10 | * By @maxlynch, @helloimben, @adamdbradley <3 11 | * 12 | * Licensed under the MIT license. Please see LICENSE for more information. 13 | * 14 | */ 15 | /** 16 | * Nav controllers and header bar animations 17 | */ 18 | /* 19 | .content-slide-in { 20 | &.ng-enter, > .ng-enter { 21 | -webkit-transition: 0.5s ease-in-out all; 22 | -webkit-transform:translate3d(100%,0,0) ; 23 | box-shadow: -1px 0px 10px rgba(0,0,0,0.6); 24 | } 25 | &.ng-enter-active, > .ng-enter-active { 26 | -webkit-transform:translate3d(0,0,0) ; 27 | } 28 | &.ng-leave, > .ng-leave { 29 | -webkit-transition: 0.5s ease-in-out all; 30 | -webkit-transform:translate3d(0%,0,0); 31 | } 32 | &.ng-leave-active, > .ng-leave-active { 33 | -webkit-transform:translate3d(-10%,0,0); 34 | opacity: 0.8; 35 | } 36 | } 37 | */ 38 | .content-slide-out.ng-enter, .content-slide-out > .ng-enter { 39 | z-index: 1; 40 | -webkit-transition: 0.5s ease-in-out all; 41 | -webkit-transform: translate3d(-100%, 0, 0); 42 | box-shadow: -1px 0px 10px rgba(0, 0, 0, 0.6); } 43 | .content-slide-out.ng-enter-active, .content-slide-out > .ng-enter-active { 44 | -webkit-transform: translate3d(0, 0, 0); } 45 | .content-slide-out.ng-leave, .content-slide-out > .ng-leave { 46 | z-index: 0; 47 | -webkit-transition: 0.5s ease-in-out all; 48 | -webkit-transform: translate3d(0%, 0, 0); } 49 | .content-slide-out.ng-leave-active, .content-slide-out > .ng-leave-active { 50 | -webkit-transform: translate3d(10%, 0, 0); 51 | opacity: 0.8; } 52 | 53 | .bar-title-in-add { 54 | -webkit-transition: -webkit-transform 0.5s ease-in-out, opacity 0.5s ease-in-out; 55 | -webkit-transform: translate3d(100%, 0, 0); 56 | opacity: 0; } 57 | 58 | .bar-title-in-add-active { 59 | -webkit-transform: translate3d(0px, 0, 0); 60 | opacity: 1; } 61 | 62 | .bar-title-out-add { 63 | -webkit-transition: -webkit-transform 0.5s ease-in-out, opacity 0.5s ease-in-out; } 64 | 65 | .bar-title-out-add-active { 66 | -webkit-transform: translate3d(-100%, 0, 0); 67 | opacity: 0; } 68 | 69 | .bar-button-in { 70 | opacity: 0; } 71 | 72 | .bar-button-in-add { 73 | -webkit-transition: -webkit-transform 0.5s ease-in-out, opacity 0.5s ease-in-out; 74 | -webkit-transform: translate3d(50%, 0, 0); 75 | opacity: 0; } 76 | 77 | .bar-button-in-active { 78 | -webkit-transform: translate3d(0px, 0, 0); 79 | opacity: 1; } 80 | 81 | /** 82 | * Tab controller animations 83 | */ 84 | .fade-in-out.ng-enter, .fade-in-out > .ng-enter { 85 | opacity: 0; 86 | -webkit-transition: opacity 0.3s ease-in-out; } 87 | .fade-in-out.ng-enter-active, .fade-in-out > .ng-enter-active { 88 | opacity: 1; } 89 | .fade-in-out.ng-leave, .fade-in-out > .ng-leave { 90 | opacity: 1; 91 | -webkit-transition: opacity 0.3s ease-in-out; } 92 | .fade-in-out.ng-leave-active, .fade-in-out > .ng-leave-active { 93 | opacity: 0; } 94 | 95 | /* the overall container of the toggle */ 96 | .toggle { 97 | display: inline-block; } 98 | 99 | /* hide the actual checkbox */ 100 | .toggle input { 101 | display: none; } 102 | 103 | .toggle .track { 104 | /* the background of the toggle's track area */ 105 | /* also the track appearance when the toggle is "off" */ 106 | position: relative; 107 | display: inline-block; 108 | box-sizing: border-box; 109 | width: 54px; 110 | height: 32px; 111 | border: solid 2px #dddddd; 112 | border-radius: 20px; 113 | background-color: white; 114 | cursor: pointer; 115 | transition: 0.4s ease; } 116 | 117 | .toggle .handle { 118 | /* the handle (circle) thats inside the toggle's track area */ 119 | /* also the appearance when the handle is "off" */ 120 | position: absolute; 121 | display: block; 122 | width: auto; 123 | /* override defaults */ 124 | height: auto; 125 | /* override defaults */ 126 | box-shadow: 0 0 2px rgba(0, 0, 0, 0.5), 0 4px 5px rgba(0, 0, 0, 0.25); 127 | border-radius: 20px; 128 | background-color: white; 129 | left: 0; 130 | top: 0; 131 | bottom: 0; 132 | right: 20px; 133 | transition: 0.2s ease; 134 | transition-property: left, right; 135 | transition-delay: 0s, .05s; } 136 | 137 | .toggle :checked + .track { 138 | /* When the toggle is "on" */ 139 | /* the track when the toggle is "on" */ 140 | border-color: #4bd863; 141 | background-color: #ccc; 142 | box-shadow: inset 0 0 0 20px #4bd863; 143 | transition: 0.2s ease; 144 | /* the handle when the toggle is "on" */ } 145 | .toggle :checked + .track .handle { 146 | background-color: white; 147 | right: 0; 148 | left: 20px; 149 | -webkit-transform: none; 150 | transition-delay: .05s, 0s; } 151 | -------------------------------------------------------------------------------- /www/css/themes/ionic-ios7.min.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";/*! 2 | * Copyright 2013 Drifty Co. 3 | * http://drifty.com/ 4 | 5 | * Ionic - a powerful HTML5 mobile app framework. 6 | * http://ionicframework.com/ 7 | * 8 | * 9 | * By @maxlynch, @helloimben, @adamdbradley <3 10 | * 11 | * Licensed under the MIT license. Please see LICENSE for more information. 12 | * 13 | */.content-slide-out.ng-enter,.content-slide-out>.ng-enter{z-index:1;-webkit-transition:.5s ease-in-out all;-webkit-transform:translate3d(-100%,0,0);box-shadow:-1px 0 10px rgba(0,0,0,.6)}.content-slide-out.ng-enter-active,.content-slide-out>.ng-enter-active{-webkit-transform:translate3d(0,0,0)}.content-slide-out.ng-leave,.content-slide-out>.ng-leave{z-index:0;-webkit-transition:.5s ease-in-out all;-webkit-transform:translate3d(0%,0,0)}.content-slide-out.ng-leave-active,.content-slide-out>.ng-leave-active{-webkit-transform:translate3d(10%,0,0);opacity:.8}.bar-title-in-add{-webkit-transition:-webkit-transform .5s ease-in-out,opacity .5s ease-in-out;-webkit-transform:translate3d(100%,0,0);opacity:0}.bar-title-in-add-active{-webkit-transform:translate3d(0px,0,0);opacity:1}.bar-title-out-add{-webkit-transition:-webkit-transform .5s ease-in-out,opacity .5s ease-in-out}.bar-title-out-add-active{-webkit-transform:translate3d(-100%,0,0);opacity:0}.bar-button-in{opacity:0}.bar-button-in-add{-webkit-transition:-webkit-transform .5s ease-in-out,opacity .5s ease-in-out;-webkit-transform:translate3d(50%,0,0);opacity:0}.bar-button-in-active{-webkit-transform:translate3d(0px,0,0);opacity:1}.fade-in-out.ng-enter,.fade-in-out>.ng-enter{opacity:0;-webkit-transition:opacity .3s ease-in-out}.fade-in-out.ng-enter-active,.fade-in-out>.ng-enter-active{opacity:1}.fade-in-out.ng-leave,.fade-in-out>.ng-leave{opacity:1;-webkit-transition:opacity .3s ease-in-out}.fade-in-out.ng-leave-active,.fade-in-out>.ng-leave-active{opacity:0}.toggle{display:inline-block}.toggle input{display:none}.toggle .track{position:relative;display:inline-block;box-sizing:border-box;width:54px;height:32px;border:solid 2px #ddd;border-radius:20px;background-color:#fff;cursor:pointer;transition:.4s ease}.toggle .handle{position:absolute;display:block;width:auto;height:auto;box-shadow:0 0 2px rgba(0,0,0,.5),0 4px 5px rgba(0,0,0,.25);border-radius:20px;background-color:#fff;left:0;top:0;bottom:0;right:20px;transition:.2s ease;transition-property:left,right;transition-delay:0s,.05s}.toggle :checked+.track{border-color:#4bd863;background-color:#ccc;box-shadow:inset 0 0 0 20px #4bd863;transition:.2s ease}.toggle :checked+.track .handle{background-color:#fff;right:0;left:20px;-webkit-transform:none;transition-delay:.05s,0s} -------------------------------------------------------------------------------- /www/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/fonts/ionicons.eot -------------------------------------------------------------------------------- /www/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/fonts/ionicons.ttf -------------------------------------------------------------------------------- /www/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/fonts/ionicons.woff -------------------------------------------------------------------------------- /www/img/ionic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/img/ionic.png -------------------------------------------------------------------------------- /www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ionic Seed 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /www/js/angular/angular-animate.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.4 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(C,k,F){'use strict';k.module("ngAnimate",["ng"]).config(["$provide","$animateProvider",function(M,G){function l(l){for(var h=0;h=v&&d>=p&&f()}var r=a.data(z),m=l(a);if(-1!=m.className.indexOf(c)&&r){var k=r.timings,n=r.stagger,p=r.maxDuration,q=r.activeClassName,v=1E3*Math.max(k.transitionDelay,k.animationDelay),x=Date.now(),w=Q+" "+P,u=r.ii,y,r="",s=[];if(0 20 | * 21 | * See {@link ngCookies.$cookies `$cookies`} and 22 | * {@link ngCookies.$cookieStore `$cookieStore`} for usage. 23 | */ 24 | 25 | 26 | angular.module('ngCookies', ['ng']). 27 | /** 28 | * @ngdoc object 29 | * @name ngCookies.$cookies 30 | * @requires $browser 31 | * 32 | * @description 33 | * Provides read/write access to browser's cookies. 34 | * 35 | * Only a simple Object is exposed and by adding or removing properties to/from 36 | * this object, new cookies are created/deleted at the end of current $eval. 37 | * 38 | * Requires the {@link ngCookies `ngCookies`} module to be installed. 39 | * 40 | * @example 41 | 42 | 43 | 51 | 52 | 53 | */ 54 | factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) { 55 | var cookies = {}, 56 | lastCookies = {}, 57 | lastBrowserCookies, 58 | runEval = false, 59 | copy = angular.copy, 60 | isUndefined = angular.isUndefined; 61 | 62 | //creates a poller fn that copies all cookies from the $browser to service & inits the service 63 | $browser.addPollFn(function() { 64 | var currentCookies = $browser.cookies(); 65 | if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl 66 | lastBrowserCookies = currentCookies; 67 | copy(currentCookies, lastCookies); 68 | copy(currentCookies, cookies); 69 | if (runEval) $rootScope.$apply(); 70 | } 71 | })(); 72 | 73 | runEval = true; 74 | 75 | //at the end of each eval, push cookies 76 | //TODO: this should happen before the "delayed" watches fire, because if some cookies are not 77 | // strings or browser refuses to store some cookies, we update the model in the push fn. 78 | $rootScope.$watch(push); 79 | 80 | return cookies; 81 | 82 | 83 | /** 84 | * Pushes all the cookies from the service to the browser and verifies if all cookies were 85 | * stored. 86 | */ 87 | function push() { 88 | var name, 89 | value, 90 | browserCookies, 91 | updated; 92 | 93 | //delete any cookies deleted in $cookies 94 | for (name in lastCookies) { 95 | if (isUndefined(cookies[name])) { 96 | $browser.cookies(name, undefined); 97 | } 98 | } 99 | 100 | //update all cookies updated in $cookies 101 | for(name in cookies) { 102 | value = cookies[name]; 103 | if (!angular.isString(value)) { 104 | if (angular.isDefined(lastCookies[name])) { 105 | cookies[name] = lastCookies[name]; 106 | } else { 107 | delete cookies[name]; 108 | } 109 | } else if (value !== lastCookies[name]) { 110 | $browser.cookies(name, value); 111 | updated = true; 112 | } 113 | } 114 | 115 | //verify what was actually stored 116 | if (updated){ 117 | updated = false; 118 | browserCookies = $browser.cookies(); 119 | 120 | for (name in cookies) { 121 | if (cookies[name] !== browserCookies[name]) { 122 | //delete or reset all cookies that the browser dropped from $cookies 123 | if (isUndefined(browserCookies[name])) { 124 | delete cookies[name]; 125 | } else { 126 | cookies[name] = browserCookies[name]; 127 | } 128 | updated = true; 129 | } 130 | } 131 | } 132 | } 133 | }]). 134 | 135 | 136 | /** 137 | * @ngdoc object 138 | * @name ngCookies.$cookieStore 139 | * @requires $cookies 140 | * 141 | * @description 142 | * Provides a key-value (string-object) storage, that is backed by session cookies. 143 | * Objects put or retrieved from this storage are automatically serialized or 144 | * deserialized by angular's toJson/fromJson. 145 | * 146 | * Requires the {@link ngCookies `ngCookies`} module to be installed. 147 | * 148 | * @example 149 | */ 150 | factory('$cookieStore', ['$cookies', function($cookies) { 151 | 152 | return { 153 | /** 154 | * @ngdoc method 155 | * @name ngCookies.$cookieStore#get 156 | * @methodOf ngCookies.$cookieStore 157 | * 158 | * @description 159 | * Returns the value of given cookie key 160 | * 161 | * @param {string} key Id to use for lookup. 162 | * @returns {Object} Deserialized cookie value. 163 | */ 164 | get: function(key) { 165 | var value = $cookies[key]; 166 | return value ? angular.fromJson(value) : value; 167 | }, 168 | 169 | /** 170 | * @ngdoc method 171 | * @name ngCookies.$cookieStore#put 172 | * @methodOf ngCookies.$cookieStore 173 | * 174 | * @description 175 | * Sets a value for given cookie key 176 | * 177 | * @param {string} key Id for the `value`. 178 | * @param {Object} value Value to be stored. 179 | */ 180 | put: function(key, value) { 181 | $cookies[key] = angular.toJson(value); 182 | }, 183 | 184 | /** 185 | * @ngdoc method 186 | * @name ngCookies.$cookieStore#remove 187 | * @methodOf ngCookies.$cookieStore 188 | * 189 | * @description 190 | * Remove given cookie 191 | * 192 | * @param {string} key Id of the key-value pair to delete. 193 | */ 194 | remove: function(key) { 195 | delete $cookies[key]; 196 | } 197 | }; 198 | 199 | }]); 200 | 201 | 202 | })(window, window.angular); 203 | -------------------------------------------------------------------------------- /www/js/angular/angular-cookies.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.4 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(p,f,n){'use strict';f.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(d,b){var c={},g={},h,k=!1,l=f.copy,m=f.isUndefined;b.addPollFn(function(){var a=b.cookies();h!=a&&(h=a,l(a,g),l(a,c),k&&d.$apply())})();k=!0;d.$watch(function(){var a,e,d;for(a in g)m(c[a])&&b.cookies(a,n);for(a in c)(e=c[a],f.isString(e))?e!==g[a]&&(b.cookies(a,e),d=!0):f.isDefined(g[a])?c[a]=g[a]:delete c[a];if(d)for(a in e=b.cookies(),c)c[a]!==e[a]&&(m(e[a])?delete c[a]:c[a]=e[a])}); 7 | return c}]).factory("$cookieStore",["$cookies",function(d){return{get:function(b){return(b=d[b])?f.fromJson(b):b},put:function(b,c){d[b]=f.toJson(c)},remove:function(b){delete d[b]}}}])})(window,window.angular); 8 | //# sourceMappingURL=angular-cookies.min.js.map 9 | -------------------------------------------------------------------------------- /www/js/angular/angular-cookies.min.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version":3, 3 | "file":"angular-cookies.min.js", 4 | "lineCount":7, 5 | "mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CAoBtCD,CAAAE,OAAA,CAAe,WAAf,CAA4B,CAAC,IAAD,CAA5B,CAAAC,QAAA,CA4BW,UA5BX,CA4BuB,CAAC,YAAD,CAAe,UAAf,CAA2B,QAAS,CAACC,CAAD,CAAaC,CAAb,CAAuB,CAAA,IACxEC,EAAU,EAD8D,CAExEC,EAAc,EAF0D,CAGxEC,CAHwE,CAIxEC,EAAU,CAAA,CAJ8D,CAKxEC,EAAOV,CAAAU,KALiE,CAMxEC,EAAcX,CAAAW,YAGlBN,EAAAO,UAAA,CAAmB,QAAQ,EAAG,CAC5B,IAAIC,EAAiBR,CAAAC,QAAA,EACjBE,EAAJ,EAA0BK,CAA1B,GACEL,CAGA,CAHqBK,CAGrB,CAFAH,CAAA,CAAKG,CAAL,CAAqBN,CAArB,CAEA,CADAG,CAAA,CAAKG,CAAL,CAAqBP,CAArB,CACA,CAAIG,CAAJ,EAAaL,CAAAU,OAAA,EAJf,CAF4B,CAA9B,CAAA,EAUAL,EAAA,CAAU,CAAA,CAKVL,EAAAW,OAAA,CASAC,QAAa,EAAG,CAAA,IACVC,CADU,CAEVC,CAFU,CAIVC,CAGJ,KAAKF,CAAL,GAAaV,EAAb,CACMI,CAAA,CAAYL,CAAA,CAAQW,CAAR,CAAZ,CAAJ,EACEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBhB,CAAvB,CAKJ,KAAIgB,CAAJ,GAAYX,EAAZ,CAEE,CADAY,CACK,CADGZ,CAAA,CAAQW,CAAR,CACH,CAAAjB,CAAAoB,SAAA,CAAiBF,CAAjB,CAAL,EAMWA,CANX,GAMqBX,CAAA,CAAYU,CAAZ,CANrB,GAOEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBC,CAAvB,CACA,CAAAC,CAAA,CAAU,CAAA,CARZ,EACMnB,CAAAqB,UAAA,CAAkBd,CAAA,CAAYU,CAAZ,CAAlB,CAAJ,CACEX,CAAA,CAAQW,CAAR,CADF,CACkBV,CAAA,CAAYU,CAAZ,CADlB,CAGE,OAAOX,CAAA,CAAQW,CAAR,CASb,IAAIE,CAAJ,CAIE,IAAKF,CAAL,GAFAK,EAEahB,CAFID,CAAAC,QAAA,EAEJA,CAAAA,CAAb,CACMA,CAAA,CAAQW,CAAR,CAAJ,GAAsBK,CAAA,CAAeL,CAAf,CAAtB,GAEMN,CAAA,CAAYW,CAAA,CAAeL,CAAf,CAAZ,CAAJ,CACE,OAAOX,CAAA,CAAQW,CAAR,CADT,CAGEX,CAAA,CAAQW,CAAR,CAHF,CAGkBK,CAAA,CAAeL,CAAf,CALpB,CAlCU,CAThB,CAEA;MAAOX,EA1BqE,CAA3D,CA5BvB,CAAAH,QAAA,CA4HW,cA5HX,CA4H2B,CAAC,UAAD,CAAa,QAAQ,CAACoB,CAAD,CAAW,CAErD,MAAO,KAYAC,QAAQ,CAACC,CAAD,CAAM,CAEjB,MAAO,CADHP,CACG,CADKK,CAAA,CAASE,CAAT,CACL,EAAQzB,CAAA0B,SAAA,CAAiBR,CAAjB,CAAR,CAAkCA,CAFxB,CAZd,KA4BAS,QAAQ,CAACF,CAAD,CAAMP,CAAN,CAAa,CACxBK,CAAA,CAASE,CAAT,CAAA,CAAgBzB,CAAA4B,OAAA,CAAeV,CAAf,CADQ,CA5BrB,QA0CGW,QAAQ,CAACJ,CAAD,CAAM,CACpB,OAAOF,CAAA,CAASE,CAAT,CADa,CA1CjB,CAF8C,CAAhC,CA5H3B,CApBsC,CAArC,CAAA,CAoME1B,MApMF,CAoMUA,MAAAC,QApMV;", 6 | "sources":["angular-cookies.js"], 7 | "names":["window","angular","undefined","module","factory","$rootScope","$browser","cookies","lastCookies","lastBrowserCookies","runEval","copy","isUndefined","addPollFn","currentCookies","$apply","$watch","push","name","value","updated","isString","isDefined","browserCookies","$cookies","get","key","fromJson","put","toJson","remove"] 8 | } 9 | -------------------------------------------------------------------------------- /www/js/angular/angular-csp.css: -------------------------------------------------------------------------------- 1 | /* Include this file in your html if you are using the CSP mode. */ 2 | 3 | @charset "UTF-8"; 4 | 5 | [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], 6 | .ng-cloak, .x-ng-cloak, 7 | .ng-hide { 8 | display: none !important; 9 | } 10 | 11 | ng\:form { 12 | display: block; 13 | } 14 | 15 | /* The styles below ensure that the CSS transition will ALWAYS 16 | * animate and close. A nasty bug occurs with CSS transitions where 17 | * when the active class isn't set, or if the active class doesn't 18 | * contain any styles to transition to, then, if ngAnimate is used, 19 | * it will appear as if the webpage is broken due to the forever hanging 20 | * animations. The border-spacing (!ie) and zoom (ie) CSS properties are 21 | * used below since they trigger a transition without making the browser 22 | * animate anything and they're both highly underused CSS properties */ 23 | .ng-animate-start { border-spacing:1px 1px; -ms-zoom:1.0001; } 24 | .ng-animate-active { border-spacing:0px 0px; -ms-zoom:1; } 25 | -------------------------------------------------------------------------------- /www/js/angular/angular-loader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license AngularJS v1.2.4 3 | * (c) 2010-2014 Google, Inc. http://angularjs.org 4 | * License: MIT 5 | */ 6 | 7 | (function() {'use strict'; 8 | 9 | /** 10 | * @description 11 | * 12 | * This object provides a utility for producing rich Error messages within 13 | * Angular. It can be called as follows: 14 | * 15 | * var exampleMinErr = minErr('example'); 16 | * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); 17 | * 18 | * The above creates an instance of minErr in the example namespace. The 19 | * resulting error will have a namespaced error code of example.one. The 20 | * resulting error will replace {0} with the value of foo, and {1} with the 21 | * value of bar. The object is not restricted in the number of arguments it can 22 | * take. 23 | * 24 | * If fewer arguments are specified than necessary for interpolation, the extra 25 | * interpolation markers will be preserved in the final string. 26 | * 27 | * Since data will be parsed statically during a build step, some restrictions 28 | * are applied with respect to how minErr instances are created and called. 29 | * Instances should have names of the form namespaceMinErr for a minErr created 30 | * using minErr('namespace') . Error codes, namespaces and template strings 31 | * should all be static strings, not variables or general expressions. 32 | * 33 | * @param {string} module The namespace to use for the new minErr instance. 34 | * @returns {function(string, string, ...): Error} instance 35 | */ 36 | 37 | function minErr(module) { 38 | return function () { 39 | var code = arguments[0], 40 | prefix = '[' + (module ? module + ':' : '') + code + '] ', 41 | template = arguments[1], 42 | templateArgs = arguments, 43 | stringify = function (obj) { 44 | if (typeof obj === 'function') { 45 | return obj.toString().replace(/ \{[\s\S]*$/, ''); 46 | } else if (typeof obj === 'undefined') { 47 | return 'undefined'; 48 | } else if (typeof obj !== 'string') { 49 | return JSON.stringify(obj); 50 | } 51 | return obj; 52 | }, 53 | message, i; 54 | 55 | message = prefix + template.replace(/\{\d+\}/g, function (match) { 56 | var index = +match.slice(1, -1), arg; 57 | 58 | if (index + 2 < templateArgs.length) { 59 | arg = templateArgs[index + 2]; 60 | if (typeof arg === 'function') { 61 | return arg.toString().replace(/ ?\{[\s\S]*$/, ''); 62 | } else if (typeof arg === 'undefined') { 63 | return 'undefined'; 64 | } else if (typeof arg !== 'string') { 65 | return toJson(arg); 66 | } 67 | return arg; 68 | } 69 | return match; 70 | }); 71 | 72 | message = message + '\nhttp://errors.angularjs.org/1.2.4/' + 73 | (module ? module + '/' : '') + code; 74 | for (i = 2; i < arguments.length; i++) { 75 | message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' + 76 | encodeURIComponent(stringify(arguments[i])); 77 | } 78 | 79 | return new Error(message); 80 | }; 81 | } 82 | 83 | /** 84 | * @ngdoc interface 85 | * @name angular.Module 86 | * @description 87 | * 88 | * Interface for configuring angular {@link angular.module modules}. 89 | */ 90 | 91 | function setupModuleLoader(window) { 92 | 93 | var $injectorMinErr = minErr('$injector'); 94 | var ngMinErr = minErr('ng'); 95 | 96 | function ensure(obj, name, factory) { 97 | return obj[name] || (obj[name] = factory()); 98 | } 99 | 100 | var angular = ensure(window, 'angular', Object); 101 | 102 | // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap 103 | angular.$$minErr = angular.$$minErr || minErr; 104 | 105 | return ensure(angular, 'module', function() { 106 | /** @type {Object.} */ 107 | var modules = {}; 108 | 109 | /** 110 | * @ngdoc function 111 | * @name angular.module 112 | * @description 113 | * 114 | * The `angular.module` is a global place for creating, registering and retrieving Angular 115 | * modules. 116 | * All modules (angular core or 3rd party) that should be available to an application must be 117 | * registered using this mechanism. 118 | * 119 | * When passed two or more arguments, a new module is created. If passed only one argument, an 120 | * existing module (the name passed as the first argument to `module`) is retrieved. 121 | * 122 | * 123 | * # Module 124 | * 125 | * A module is a collection of services, directives, filters, and configuration information. 126 | * `angular.module` is used to configure the {@link AUTO.$injector $injector}. 127 | * 128 | *
129 |      * // Create a new module
130 |      * var myModule = angular.module('myModule', []);
131 |      *
132 |      * // register a new service
133 |      * myModule.value('appName', 'MyCoolApp');
134 |      *
135 |      * // configure existing services inside initialization blocks.
136 |      * myModule.config(function($locationProvider) {
137 |      *   // Configure existing providers
138 |      *   $locationProvider.hashPrefix('!');
139 |      * });
140 |      * 
141 | * 142 | * Then you can create an injector and load your modules like this: 143 | * 144 | *
145 |      * var injector = angular.injector(['ng', 'MyModule'])
146 |      * 
147 | * 148 | * However it's more likely that you'll just use 149 | * {@link ng.directive:ngApp ngApp} or 150 | * {@link angular.bootstrap} to simplify this process for you. 151 | * 152 | * @param {!string} name The name of the module to create or retrieve. 153 | * @param {Array.=} requires If specified then new module is being created. If 154 | * unspecified then the the module is being retrieved for further configuration. 155 | * @param {Function} configFn Optional configuration function for the module. Same as 156 | * {@link angular.Module#methods_config Module#config()}. 157 | * @returns {module} new module with the {@link angular.Module} api. 158 | */ 159 | return function module(name, requires, configFn) { 160 | var assertNotHasOwnProperty = function(name, context) { 161 | if (name === 'hasOwnProperty') { 162 | throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); 163 | } 164 | }; 165 | 166 | assertNotHasOwnProperty(name, 'module'); 167 | if (requires && modules.hasOwnProperty(name)) { 168 | modules[name] = null; 169 | } 170 | return ensure(modules, name, function() { 171 | if (!requires) { 172 | throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " + 173 | "the module name or forgot to load it. If registering a module ensure that you " + 174 | "specify the dependencies as the second argument.", name); 175 | } 176 | 177 | /** @type {!Array.>} */ 178 | var invokeQueue = []; 179 | 180 | /** @type {!Array.} */ 181 | var runBlocks = []; 182 | 183 | var config = invokeLater('$injector', 'invoke'); 184 | 185 | /** @type {angular.Module} */ 186 | var moduleInstance = { 187 | // Private state 188 | _invokeQueue: invokeQueue, 189 | _runBlocks: runBlocks, 190 | 191 | /** 192 | * @ngdoc property 193 | * @name angular.Module#requires 194 | * @propertyOf angular.Module 195 | * @returns {Array.} List of module names which must be loaded before this module. 196 | * @description 197 | * Holds the list of modules which the injector will load before the current module is 198 | * loaded. 199 | */ 200 | requires: requires, 201 | 202 | /** 203 | * @ngdoc property 204 | * @name angular.Module#name 205 | * @propertyOf angular.Module 206 | * @returns {string} Name of the module. 207 | * @description 208 | */ 209 | name: name, 210 | 211 | 212 | /** 213 | * @ngdoc method 214 | * @name angular.Module#provider 215 | * @methodOf angular.Module 216 | * @param {string} name service name 217 | * @param {Function} providerType Construction function for creating new instance of the 218 | * service. 219 | * @description 220 | * See {@link AUTO.$provide#provider $provide.provider()}. 221 | */ 222 | provider: invokeLater('$provide', 'provider'), 223 | 224 | /** 225 | * @ngdoc method 226 | * @name angular.Module#factory 227 | * @methodOf angular.Module 228 | * @param {string} name service name 229 | * @param {Function} providerFunction Function for creating new instance of the service. 230 | * @description 231 | * See {@link AUTO.$provide#factory $provide.factory()}. 232 | */ 233 | factory: invokeLater('$provide', 'factory'), 234 | 235 | /** 236 | * @ngdoc method 237 | * @name angular.Module#service 238 | * @methodOf angular.Module 239 | * @param {string} name service name 240 | * @param {Function} constructor A constructor function that will be instantiated. 241 | * @description 242 | * See {@link AUTO.$provide#service $provide.service()}. 243 | */ 244 | service: invokeLater('$provide', 'service'), 245 | 246 | /** 247 | * @ngdoc method 248 | * @name angular.Module#value 249 | * @methodOf angular.Module 250 | * @param {string} name service name 251 | * @param {*} object Service instance object. 252 | * @description 253 | * See {@link AUTO.$provide#value $provide.value()}. 254 | */ 255 | value: invokeLater('$provide', 'value'), 256 | 257 | /** 258 | * @ngdoc method 259 | * @name angular.Module#constant 260 | * @methodOf angular.Module 261 | * @param {string} name constant name 262 | * @param {*} object Constant value. 263 | * @description 264 | * Because the constant are fixed, they get applied before other provide methods. 265 | * See {@link AUTO.$provide#constant $provide.constant()}. 266 | */ 267 | constant: invokeLater('$provide', 'constant', 'unshift'), 268 | 269 | /** 270 | * @ngdoc method 271 | * @name angular.Module#animation 272 | * @methodOf angular.Module 273 | * @param {string} name animation name 274 | * @param {Function} animationFactory Factory function for creating new instance of an 275 | * animation. 276 | * @description 277 | * 278 | * **NOTE**: animations take effect only if the **ngAnimate** module is loaded. 279 | * 280 | * 281 | * Defines an animation hook that can be later used with 282 | * {@link ngAnimate.$animate $animate} service and directives that use this service. 283 | * 284 | *
285 |            * module.animation('.animation-name', function($inject1, $inject2) {
286 |            *   return {
287 |            *     eventName : function(element, done) {
288 |            *       //code to run the animation
289 |            *       //once complete, then run done()
290 |            *       return function cancellationFunction(element) {
291 |            *         //code to cancel the animation
292 |            *       }
293 |            *     }
294 |            *   }
295 |            * })
296 |            * 
297 | * 298 | * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and 299 | * {@link ngAnimate ngAnimate module} for more information. 300 | */ 301 | animation: invokeLater('$animateProvider', 'register'), 302 | 303 | /** 304 | * @ngdoc method 305 | * @name angular.Module#filter 306 | * @methodOf angular.Module 307 | * @param {string} name Filter name. 308 | * @param {Function} filterFactory Factory function for creating new instance of filter. 309 | * @description 310 | * See {@link ng.$filterProvider#register $filterProvider.register()}. 311 | */ 312 | filter: invokeLater('$filterProvider', 'register'), 313 | 314 | /** 315 | * @ngdoc method 316 | * @name angular.Module#controller 317 | * @methodOf angular.Module 318 | * @param {string|Object} name Controller name, or an object map of controllers where the 319 | * keys are the names and the values are the constructors. 320 | * @param {Function} constructor Controller constructor function. 321 | * @description 322 | * See {@link ng.$controllerProvider#register $controllerProvider.register()}. 323 | */ 324 | controller: invokeLater('$controllerProvider', 'register'), 325 | 326 | /** 327 | * @ngdoc method 328 | * @name angular.Module#directive 329 | * @methodOf angular.Module 330 | * @param {string|Object} name Directive name, or an object map of directives where the 331 | * keys are the names and the values are the factories. 332 | * @param {Function} directiveFactory Factory function for creating new instance of 333 | * directives. 334 | * @description 335 | * See {@link ng.$compileProvider#methods_directive $compileProvider.directive()}. 336 | */ 337 | directive: invokeLater('$compileProvider', 'directive'), 338 | 339 | /** 340 | * @ngdoc method 341 | * @name angular.Module#config 342 | * @methodOf angular.Module 343 | * @param {Function} configFn Execute this function on module load. Useful for service 344 | * configuration. 345 | * @description 346 | * Use this method to register work which needs to be performed on module loading. 347 | */ 348 | config: config, 349 | 350 | /** 351 | * @ngdoc method 352 | * @name angular.Module#run 353 | * @methodOf angular.Module 354 | * @param {Function} initializationFn Execute this function after injector creation. 355 | * Useful for application initialization. 356 | * @description 357 | * Use this method to register work which should be performed when the injector is done 358 | * loading all modules. 359 | */ 360 | run: function(block) { 361 | runBlocks.push(block); 362 | return this; 363 | } 364 | }; 365 | 366 | if (configFn) { 367 | config(configFn); 368 | } 369 | 370 | return moduleInstance; 371 | 372 | /** 373 | * @param {string} provider 374 | * @param {string} method 375 | * @param {String=} insertMethod 376 | * @returns {angular.Module} 377 | */ 378 | function invokeLater(provider, method, insertMethod) { 379 | return function() { 380 | invokeQueue[insertMethod || 'push']([provider, method, arguments]); 381 | return moduleInstance; 382 | }; 383 | } 384 | }); 385 | }; 386 | }); 387 | 388 | } 389 | 390 | setupModuleLoader(window); 391 | })(window); 392 | 393 | /** 394 | * Closure compiler type information 395 | * 396 | * @typedef { { 397 | * requires: !Array., 398 | * invokeQueue: !Array.>, 399 | * 400 | * service: function(string, Function):angular.Module, 401 | * factory: function(string, Function):angular.Module, 402 | * value: function(string, *):angular.Module, 403 | * 404 | * filter: function(string, Function):angular.Module, 405 | * 406 | * init: function(Function):angular.Module 407 | * } } 408 | */ 409 | angular.Module; 410 | 411 | -------------------------------------------------------------------------------- /www/js/angular/angular-loader.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.4 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(){'use strict';function d(a){return function(){var c=arguments[0],b,c="["+(a?a+":":"")+c+"] http://errors.angularjs.org/1.2.4/"+(a?a+"/":"")+c;for(b=1;b 45 | * 46 | * See {@link ngResource.$resource `$resource`} for usage. 47 | */ 48 | 49 | /** 50 | * @ngdoc object 51 | * @name ngResource.$resource 52 | * @requires $http 53 | * 54 | * @description 55 | * A factory which creates a resource object that lets you interact with 56 | * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources. 57 | * 58 | * The returned resource object has action methods which provide high-level behaviors without 59 | * the need to interact with the low level {@link ng.$http $http} service. 60 | * 61 | * Requires the {@link ngResource `ngResource`} module to be installed. 62 | * 63 | * @param {string} url A parametrized URL template with parameters prefixed by `:` as in 64 | * `/user/:username`. If you are using a URL with a port number (e.g. 65 | * `http://example.com:8080/api`), it will be respected. 66 | * 67 | * If you are using a url with a suffix, just add the suffix, like this: 68 | * `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')` 69 | * or even `$resource('http://example.com/resource/:resource_id.:format')` 70 | * If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be 71 | * collapsed down to a single `.`. If you need this sequence to appear and not collapse then you 72 | * can escape it with `/\.`. 73 | * 74 | * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in 75 | * `actions` methods. If any of the parameter value is a function, it will be executed every time 76 | * when a param value needs to be obtained for a request (unless the param was overridden). 77 | * 78 | * Each key value in the parameter object is first bound to url template if present and then any 79 | * excess keys are appended to the url search query after the `?`. 80 | * 81 | * Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in 82 | * URL `/path/greet?salutation=Hello`. 83 | * 84 | * If the parameter value is prefixed with `@` then the value of that parameter is extracted from 85 | * the data object (useful for non-GET operations). 86 | * 87 | * @param {Object.=} actions Hash with declaration of custom action that should extend the 88 | * default set of resource actions. The declaration should be created in the format of {@link 89 | * ng.$http#usage_parameters $http.config}: 90 | * 91 | * {action1: {method:?, params:?, isArray:?, headers:?, ...}, 92 | * action2: {method:?, params:?, isArray:?, headers:?, ...}, 93 | * ...} 94 | * 95 | * Where: 96 | * 97 | * - **`action`** – {string} – The name of action. This name becomes the name of the method on 98 | * your resource object. 99 | * - **`method`** – {string} – HTTP request method. Valid methods are: `GET`, `POST`, `PUT`, 100 | * `DELETE`, and `JSONP`. 101 | * - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of 102 | * the parameter value is a function, it will be executed every time when a param value needs to 103 | * be obtained for a request (unless the param was overridden). 104 | * - **`url`** – {string} – action specific `url` override. The url templating is supported just 105 | * like for the resource-level urls. 106 | * - **`isArray`** – {boolean=} – If true then the returned object for this action is an array, 107 | * see `returns` section. 108 | * - **`transformRequest`** – 109 | * `{function(data, headersGetter)|Array.}` – 110 | * transform function or an array of such functions. The transform function takes the http 111 | * request body and headers and returns its transformed (typically serialized) version. 112 | * - **`transformResponse`** – 113 | * `{function(data, headersGetter)|Array.}` – 114 | * transform function or an array of such functions. The transform function takes the http 115 | * response body and headers and returns its transformed (typically deserialized) version. 116 | * - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the 117 | * GET request, otherwise if a cache instance built with 118 | * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for 119 | * caching. 120 | * - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that 121 | * should abort the request when resolved. 122 | * - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the 123 | * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5 124 | * requests with credentials} for more information. 125 | * - **`responseType`** - `{string}` - see {@link 126 | * https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}. 127 | * - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods - 128 | * `response` and `responseError`. Both `response` and `responseError` interceptors get called 129 | * with `http response` object. See {@link ng.$http $http interceptors}. 130 | * 131 | * @returns {Object} A resource "class" object with methods for the default set of resource actions 132 | * optionally extended with custom `actions`. The default set contains these actions: 133 | * 134 | * { 'get': {method:'GET'}, 135 | * 'save': {method:'POST'}, 136 | * 'query': {method:'GET', isArray:true}, 137 | * 'remove': {method:'DELETE'}, 138 | * 'delete': {method:'DELETE'} }; 139 | * 140 | * Calling these methods invoke an {@link ng.$http} with the specified http method, 141 | * destination and parameters. When the data is returned from the server then the object is an 142 | * instance of the resource class. The actions `save`, `remove` and `delete` are available on it 143 | * as methods with the `$` prefix. This allows you to easily perform CRUD operations (create, 144 | * read, update, delete) on server-side data like this: 145 | *
146 |         var User = $resource('/user/:userId', {userId:'@id'});
147 |         var user = User.get({userId:123}, function() {
148 |           user.abc = true;
149 |           user.$save();
150 |         });
151 |      
152 | * 153 | * It is important to realize that invoking a $resource object method immediately returns an 154 | * empty reference (object or array depending on `isArray`). Once the data is returned from the 155 | * server the existing reference is populated with the actual data. This is a useful trick since 156 | * usually the resource is assigned to a model which is then rendered by the view. Having an empty 157 | * object results in no rendering, once the data arrives from the server then the object is 158 | * populated with the data and the view automatically re-renders itself showing the new data. This 159 | * means that in most cases one never has to write a callback function for the action methods. 160 | * 161 | * The action methods on the class object or instance object can be invoked with the following 162 | * parameters: 163 | * 164 | * - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])` 165 | * - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])` 166 | * - non-GET instance actions: `instance.$action([parameters], [success], [error])` 167 | * 168 | * Success callback is called with (value, responseHeaders) arguments. Error callback is called 169 | * with (httpResponse) argument. 170 | * 171 | * Class actions return empty instance (with additional properties below). 172 | * Instance actions return promise of the action. 173 | * 174 | * The Resource instances and collection have these additional properties: 175 | * 176 | * - `$promise`: the {@link ng.$q promise} of the original server interaction that created this 177 | * instance or collection. 178 | * 179 | * On success, the promise is resolved with the same resource instance or collection object, 180 | * updated with data from server. This makes it easy to use in 181 | * {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view 182 | * rendering until the resource(s) are loaded. 183 | * 184 | * On failure, the promise is resolved with the {@link ng.$http http response} object, without 185 | * the `resource` property. 186 | * 187 | * - `$resolved`: `true` after first server interaction is completed (either with success or 188 | * rejection), `false` before that. Knowing if the Resource has been resolved is useful in 189 | * data-binding. 190 | * 191 | * @example 192 | * 193 | * # Credit card resource 194 | * 195 | *
196 |      // Define CreditCard class
197 |      var CreditCard = $resource('/user/:userId/card/:cardId',
198 |       {userId:123, cardId:'@id'}, {
199 |        charge: {method:'POST', params:{charge:true}}
200 |       });
201 | 
202 |      // We can retrieve a collection from the server
203 |      var cards = CreditCard.query(function() {
204 |        // GET: /user/123/card
205 |        // server returns: [ {id:456, number:'1234', name:'Smith'} ];
206 | 
207 |        var card = cards[0];
208 |        // each item is an instance of CreditCard
209 |        expect(card instanceof CreditCard).toEqual(true);
210 |        card.name = "J. Smith";
211 |        // non GET methods are mapped onto the instances
212 |        card.$save();
213 |        // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
214 |        // server returns: {id:456, number:'1234', name: 'J. Smith'};
215 | 
216 |        // our custom method is mapped as well.
217 |        card.$charge({amount:9.99});
218 |        // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
219 |      });
220 | 
221 |      // we can create an instance as well
222 |      var newCard = new CreditCard({number:'0123'});
223 |      newCard.name = "Mike Smith";
224 |      newCard.$save();
225 |      // POST: /user/123/card {number:'0123', name:'Mike Smith'}
226 |      // server returns: {id:789, number:'01234', name: 'Mike Smith'};
227 |      expect(newCard.id).toEqual(789);
228 |  * 
229 | * 230 | * The object returned from this function execution is a resource "class" which has "static" method 231 | * for each action in the definition. 232 | * 233 | * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and 234 | * `headers`. 235 | * When the data is returned from the server then the object is an instance of the resource type and 236 | * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD 237 | * operations (create, read, update, delete) on server-side data. 238 | 239 |
240 |      var User = $resource('/user/:userId', {userId:'@id'});
241 |      var user = User.get({userId:123}, function() {
242 |        user.abc = true;
243 |        user.$save();
244 |      });
245 |    
246 | * 247 | * It's worth noting that the success callback for `get`, `query` and other methods gets passed 248 | * in the response that came from the server as well as $http header getter function, so one 249 | * could rewrite the above example and get access to http headers as: 250 | * 251 |
252 |      var User = $resource('/user/:userId', {userId:'@id'});
253 |      User.get({userId:123}, function(u, getResponseHeaders){
254 |        u.abc = true;
255 |        u.$save(function(u, putResponseHeaders) {
256 |          //u => saved user object
257 |          //putResponseHeaders => $http header getter
258 |        });
259 |      });
260 |    
261 | */ 262 | angular.module('ngResource', ['ng']). 263 | factory('$resource', ['$http', '$q', function($http, $q) { 264 | 265 | var DEFAULT_ACTIONS = { 266 | 'get': {method:'GET'}, 267 | 'save': {method:'POST'}, 268 | 'query': {method:'GET', isArray:true}, 269 | 'remove': {method:'DELETE'}, 270 | 'delete': {method:'DELETE'} 271 | }; 272 | var noop = angular.noop, 273 | forEach = angular.forEach, 274 | extend = angular.extend, 275 | copy = angular.copy, 276 | isFunction = angular.isFunction; 277 | 278 | /** 279 | * We need our custom method because encodeURIComponent is too aggressive and doesn't follow 280 | * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path 281 | * segments: 282 | * segment = *pchar 283 | * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" 284 | * pct-encoded = "%" HEXDIG HEXDIG 285 | * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" 286 | * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" 287 | * / "*" / "+" / "," / ";" / "=" 288 | */ 289 | function encodeUriSegment(val) { 290 | return encodeUriQuery(val, true). 291 | replace(/%26/gi, '&'). 292 | replace(/%3D/gi, '='). 293 | replace(/%2B/gi, '+'); 294 | } 295 | 296 | 297 | /** 298 | * This method is intended for encoding *key* or *value* parts of query component. We need a 299 | * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't 300 | * have to be encoded per http://tools.ietf.org/html/rfc3986: 301 | * query = *( pchar / "/" / "?" ) 302 | * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" 303 | * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" 304 | * pct-encoded = "%" HEXDIG HEXDIG 305 | * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" 306 | * / "*" / "+" / "," / ";" / "=" 307 | */ 308 | function encodeUriQuery(val, pctEncodeSpaces) { 309 | return encodeURIComponent(val). 310 | replace(/%40/gi, '@'). 311 | replace(/%3A/gi, ':'). 312 | replace(/%24/g, '$'). 313 | replace(/%2C/gi, ','). 314 | replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); 315 | } 316 | 317 | function Route(template, defaults) { 318 | this.template = template; 319 | this.defaults = defaults || {}; 320 | this.urlParams = {}; 321 | } 322 | 323 | Route.prototype = { 324 | setUrlParams: function(config, params, actionUrl) { 325 | var self = this, 326 | url = actionUrl || self.template, 327 | val, 328 | encodedVal; 329 | 330 | var urlParams = self.urlParams = {}; 331 | forEach(url.split(/\W/), function(param){ 332 | if (param === 'hasOwnProperty') { 333 | throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name."); 334 | } 335 | if (!(new RegExp("^\\d+$").test(param)) && param && 336 | (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) { 337 | urlParams[param] = true; 338 | } 339 | }); 340 | url = url.replace(/\\:/g, ':'); 341 | 342 | params = params || {}; 343 | forEach(self.urlParams, function(_, urlParam){ 344 | val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam]; 345 | if (angular.isDefined(val) && val !== null) { 346 | encodedVal = encodeUriSegment(val); 347 | url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), encodedVal + "$1"); 348 | } else { 349 | url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match, 350 | leadingSlashes, tail) { 351 | if (tail.charAt(0) == '/') { 352 | return tail; 353 | } else { 354 | return leadingSlashes + tail; 355 | } 356 | }); 357 | } 358 | }); 359 | 360 | // strip trailing slashes and set the url 361 | url = url.replace(/\/+$/, ''); 362 | // then replace collapse `/.` if found in the last URL path segment before the query 363 | // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x` 364 | url = url.replace(/\/\.(?=\w+($|\?))/, '.'); 365 | // replace escaped `/\.` with `/.` 366 | config.url = url.replace(/\/\\\./, '/.'); 367 | 368 | 369 | // set params - delegate param encoding to $http 370 | forEach(params, function(value, key){ 371 | if (!self.urlParams[key]) { 372 | config.params = config.params || {}; 373 | config.params[key] = value; 374 | } 375 | }); 376 | } 377 | }; 378 | 379 | 380 | function resourceFactory(url, paramDefaults, actions) { 381 | var route = new Route(url); 382 | 383 | actions = extend({}, DEFAULT_ACTIONS, actions); 384 | 385 | function extractParams(data, actionParams){ 386 | var ids = {}; 387 | actionParams = extend({}, paramDefaults, actionParams); 388 | forEach(actionParams, function(value, key){ 389 | if (isFunction(value)) { value = value(); } 390 | ids[key] = value && value.charAt && value.charAt(0) == '@' ? 391 | lookupDottedPath(data, value.substr(1)) : value; 392 | }); 393 | return ids; 394 | } 395 | 396 | function defaultResponseInterceptor(response) { 397 | return response.resource; 398 | } 399 | 400 | function Resource(value){ 401 | copy(value || {}, this); 402 | } 403 | 404 | forEach(actions, function(action, name) { 405 | var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method); 406 | 407 | Resource[name] = function(a1, a2, a3, a4) { 408 | var params = {}, data, success, error; 409 | 410 | /* jshint -W086 */ /* (purposefully fall through case statements) */ 411 | switch(arguments.length) { 412 | case 4: 413 | error = a4; 414 | success = a3; 415 | //fallthrough 416 | case 3: 417 | case 2: 418 | if (isFunction(a2)) { 419 | if (isFunction(a1)) { 420 | success = a1; 421 | error = a2; 422 | break; 423 | } 424 | 425 | success = a2; 426 | error = a3; 427 | //fallthrough 428 | } else { 429 | params = a1; 430 | data = a2; 431 | success = a3; 432 | break; 433 | } 434 | case 1: 435 | if (isFunction(a1)) success = a1; 436 | else if (hasBody) data = a1; 437 | else params = a1; 438 | break; 439 | case 0: break; 440 | default: 441 | throw $resourceMinErr('badargs', 442 | "Expected up to 4 arguments [params, data, success, error], got {0} arguments", 443 | arguments.length); 444 | } 445 | /* jshint +W086 */ /* (purposefully fall through case statements) */ 446 | 447 | var isInstanceCall = this instanceof Resource; 448 | var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data)); 449 | var httpConfig = {}; 450 | var responseInterceptor = action.interceptor && action.interceptor.response || 451 | defaultResponseInterceptor; 452 | var responseErrorInterceptor = action.interceptor && action.interceptor.responseError || 453 | undefined; 454 | 455 | forEach(action, function(value, key) { 456 | if (key != 'params' && key != 'isArray' && key != 'interceptor') { 457 | httpConfig[key] = copy(value); 458 | } 459 | }); 460 | 461 | if (hasBody) httpConfig.data = data; 462 | route.setUrlParams(httpConfig, 463 | extend({}, extractParams(data, action.params || {}), params), 464 | action.url); 465 | 466 | var promise = $http(httpConfig).then(function(response) { 467 | var data = response.data, 468 | promise = value.$promise; 469 | 470 | if (data) { 471 | // Need to convert action.isArray to boolean in case it is undefined 472 | // jshint -W018 473 | if ( angular.isArray(data) !== (!!action.isArray) ) { 474 | throw $resourceMinErr('badcfg', 'Error in resource configuration. Expected ' + 475 | 'response to contain an {0} but got an {1}', 476 | action.isArray?'array':'object', angular.isArray(data)?'array':'object'); 477 | } 478 | // jshint +W018 479 | if (action.isArray) { 480 | value.length = 0; 481 | forEach(data, function(item) { 482 | value.push(new Resource(item)); 483 | }); 484 | } else { 485 | copy(data, value); 486 | value.$promise = promise; 487 | } 488 | } 489 | 490 | value.$resolved = true; 491 | 492 | response.resource = value; 493 | 494 | return response; 495 | }, function(response) { 496 | value.$resolved = true; 497 | 498 | (error||noop)(response); 499 | 500 | return $q.reject(response); 501 | }); 502 | 503 | promise = promise.then( 504 | function(response) { 505 | var value = responseInterceptor(response); 506 | (success||noop)(value, response.headers); 507 | return value; 508 | }, 509 | responseErrorInterceptor); 510 | 511 | if (!isInstanceCall) { 512 | // we are creating instance / collection 513 | // - set the initial promise 514 | // - return the instance / collection 515 | value.$promise = promise; 516 | value.$resolved = false; 517 | 518 | return value; 519 | } 520 | 521 | // instance call 522 | return promise; 523 | }; 524 | 525 | 526 | Resource.prototype['$' + name] = function(params, success, error) { 527 | if (isFunction(params)) { 528 | error = success; success = params; params = {}; 529 | } 530 | var result = Resource[name].call(this, params, this, success, error); 531 | return result.$promise || result; 532 | }; 533 | }); 534 | 535 | Resource.bind = function(additionalParamDefaults){ 536 | return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions); 537 | }; 538 | 539 | return Resource; 540 | } 541 | 542 | return resourceFactory; 543 | }]); 544 | 545 | 546 | })(window, window.angular); 547 | -------------------------------------------------------------------------------- /www/js/angular/angular-resource.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.4 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(H,f,z){'use strict';var u=f.$$minErr("$resource"),A=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;f.module("ngResource",["ng"]).factory("$resource",["$http","$q",function(D,E){function n(f,h){this.template=f;this.defaults=h||{};this.urlParams={}}function v(m,h,k){function r(d,c){var e={};c=w({},h,c);s(c,function(a,c){t(a)&&(a=a());var g;if(a&&a.charAt&&"@"==a.charAt(0)){g=d;var b=a.substr(1);if(null==b||""===b||"hasOwnProperty"===b||!A.test("."+b))throw u("badmember",b);for(var b=b.split("."),f=0,h= 7 | b.length;f 22 | * 23 | * See {@link ngSanitize.$sanitize `$sanitize`} for usage. 24 | */ 25 | 26 | /* 27 | * HTML Parser By Misko Hevery (misko@hevery.com) 28 | * based on: HTML Parser By John Resig (ejohn.org) 29 | * Original code by Erik Arvidsson, Mozilla Public License 30 | * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js 31 | * 32 | * // Use like so: 33 | * htmlParser(htmlString, { 34 | * start: function(tag, attrs, unary) {}, 35 | * end: function(tag) {}, 36 | * chars: function(text) {}, 37 | * comment: function(text) {} 38 | * }); 39 | * 40 | */ 41 | 42 | 43 | /** 44 | * @ngdoc service 45 | * @name ngSanitize.$sanitize 46 | * @function 47 | * 48 | * @description 49 | * The input is sanitized by parsing the html into tokens. All safe tokens (from a whitelist) are 50 | * then serialized back to properly escaped html string. This means that no unsafe input can make 51 | * it into the returned string, however, since our parser is more strict than a typical browser 52 | * parser, it's possible that some obscure input, which would be recognized as valid HTML by a 53 | * browser, won't make it through the sanitizer. 54 | * The whitelist is configured using the functions `aHrefSanitizationWhitelist` and 55 | * `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}. 56 | * 57 | * @param {string} html Html input. 58 | * @returns {string} Sanitized html. 59 | * 60 | * @example 61 | 62 | 63 | 74 |
75 | Snippet: 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 |
DirectiveHowSourceRendered
ng-bind-htmlAutomatically uses $sanitize
<div ng-bind-html="snippet">
</div>
ng-bind-htmlBypass $sanitize by explicitly trusting the dangerous value 93 |
<div ng-bind-html="deliberatelyTrustDangerousSnippet()">
 94 | </div>
95 |
ng-bindAutomatically escapes
<div ng-bind="snippet">
</div>
105 |
106 |
107 | 108 | it('should sanitize the html snippet by default', function() { 109 | expect(using('#bind-html-with-sanitize').element('div').html()). 110 | toBe('

an html\nclick here\nsnippet

'); 111 | }); 112 | 113 | it('should inline raw snippet if bound to a trusted value', function() { 114 | expect(using('#bind-html-with-trust').element("div").html()). 115 | toBe("

an html\n" + 116 | "click here\n" + 117 | "snippet

"); 118 | }); 119 | 120 | it('should escape snippet without any filter', function() { 121 | expect(using('#bind-default').element('div').html()). 122 | toBe("<p style=\"color:blue\">an html\n" + 123 | "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + 124 | "snippet</p>"); 125 | }); 126 | 127 | it('should update', function() { 128 | input('snippet').enter('new text'); 129 | expect(using('#bind-html-with-sanitize').element('div').html()).toBe('new text'); 130 | expect(using('#bind-html-with-trust').element('div').html()).toBe( 131 | 'new text'); 132 | expect(using('#bind-default').element('div').html()).toBe( 133 | "new <b onclick=\"alert(1)\">text</b>"); 134 | }); 135 |
136 |
137 | */ 138 | function $SanitizeProvider() { 139 | this.$get = ['$$sanitizeUri', function($$sanitizeUri) { 140 | return function(html) { 141 | var buf = []; 142 | htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) { 143 | return !/^unsafe/.test($$sanitizeUri(uri, isImage)); 144 | })); 145 | return buf.join(''); 146 | }; 147 | }]; 148 | } 149 | 150 | function sanitizeText(chars) { 151 | var buf = []; 152 | var writer = htmlSanitizeWriter(buf, angular.noop); 153 | writer.chars(chars); 154 | return buf.join(''); 155 | } 156 | 157 | 158 | // Regular Expressions for parsing tags and attributes 159 | var START_TAG_REGEXP = 160 | /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/, 161 | END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/, 162 | ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, 163 | BEGIN_TAG_REGEXP = /^/g, 166 | DOCTYPE_REGEXP = /]*?)>/i, 167 | CDATA_REGEXP = //g, 168 | // Match everything outside of normal chars and " (quote character) 169 | NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; 170 | 171 | 172 | // Good source of info about elements and attributes 173 | // http://dev.w3.org/html5/spec/Overview.html#semantics 174 | // http://simon.html5.org/html-elements 175 | 176 | // Safe Void Elements - HTML5 177 | // http://dev.w3.org/html5/spec/Overview.html#void-elements 178 | var voidElements = makeMap("area,br,col,hr,img,wbr"); 179 | 180 | // Elements that you can, intentionally, leave open (and which close themselves) 181 | // http://dev.w3.org/html5/spec/Overview.html#optional-tags 182 | var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"), 183 | optionalEndTagInlineElements = makeMap("rp,rt"), 184 | optionalEndTagElements = angular.extend({}, 185 | optionalEndTagInlineElements, 186 | optionalEndTagBlockElements); 187 | 188 | // Safe Block Elements - HTML5 189 | var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," + 190 | "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," + 191 | "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")); 192 | 193 | // Inline Elements - HTML5 194 | var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," + 195 | "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," + 196 | "samp,small,span,strike,strong,sub,sup,time,tt,u,var")); 197 | 198 | 199 | // Special Elements (can contain anything) 200 | var specialElements = makeMap("script,style"); 201 | 202 | var validElements = angular.extend({}, 203 | voidElements, 204 | blockElements, 205 | inlineElements, 206 | optionalEndTagElements); 207 | 208 | //Attributes that have href and hence need to be sanitized 209 | var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap"); 210 | var validAttrs = angular.extend({}, uriAttrs, makeMap( 211 | 'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+ 212 | 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+ 213 | 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+ 214 | 'scope,scrolling,shape,span,start,summary,target,title,type,'+ 215 | 'valign,value,vspace,width')); 216 | 217 | function makeMap(str) { 218 | var obj = {}, items = str.split(','), i; 219 | for (i = 0; i < items.length; i++) obj[items[i]] = true; 220 | return obj; 221 | } 222 | 223 | 224 | /** 225 | * @example 226 | * htmlParser(htmlString, { 227 | * start: function(tag, attrs, unary) {}, 228 | * end: function(tag) {}, 229 | * chars: function(text) {}, 230 | * comment: function(text) {} 231 | * }); 232 | * 233 | * @param {string} html string 234 | * @param {object} handler 235 | */ 236 | function htmlParser( html, handler ) { 237 | var index, chars, match, stack = [], last = html; 238 | stack.last = function() { return stack[ stack.length - 1 ]; }; 239 | 240 | while ( html ) { 241 | chars = true; 242 | 243 | // Make sure we're not in a script or style element 244 | if ( !stack.last() || !specialElements[ stack.last() ] ) { 245 | 246 | // Comment 247 | if ( html.indexOf("", index) === index) { 252 | if (handler.comment) handler.comment( html.substring( 4, index ) ); 253 | html = html.substring( index + 3 ); 254 | chars = false; 255 | } 256 | // DOCTYPE 257 | } else if ( DOCTYPE_REGEXP.test(html) ) { 258 | match = html.match( DOCTYPE_REGEXP ); 259 | 260 | if ( match ) { 261 | html = html.replace( match[0] , ''); 262 | chars = false; 263 | } 264 | // end tag 265 | } else if ( BEGING_END_TAGE_REGEXP.test(html) ) { 266 | match = html.match( END_TAG_REGEXP ); 267 | 268 | if ( match ) { 269 | html = html.substring( match[0].length ); 270 | match[0].replace( END_TAG_REGEXP, parseEndTag ); 271 | chars = false; 272 | } 273 | 274 | // start tag 275 | } else if ( BEGIN_TAG_REGEXP.test(html) ) { 276 | match = html.match( START_TAG_REGEXP ); 277 | 278 | if ( match ) { 279 | html = html.substring( match[0].length ); 280 | match[0].replace( START_TAG_REGEXP, parseStartTag ); 281 | chars = false; 282 | } 283 | } 284 | 285 | if ( chars ) { 286 | index = html.indexOf("<"); 287 | 288 | var text = index < 0 ? html : html.substring( 0, index ); 289 | html = index < 0 ? "" : html.substring( index ); 290 | 291 | if (handler.chars) handler.chars( decodeEntities(text) ); 292 | } 293 | 294 | } else { 295 | html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'), 296 | function(all, text){ 297 | text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1"); 298 | 299 | if (handler.chars) handler.chars( decodeEntities(text) ); 300 | 301 | return ""; 302 | }); 303 | 304 | parseEndTag( "", stack.last() ); 305 | } 306 | 307 | if ( html == last ) { 308 | throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " + 309 | "of html: {0}", html); 310 | } 311 | last = html; 312 | } 313 | 314 | // Clean up any remaining tags 315 | parseEndTag(); 316 | 317 | function parseStartTag( tag, tagName, rest, unary ) { 318 | tagName = angular.lowercase(tagName); 319 | if ( blockElements[ tagName ] ) { 320 | while ( stack.last() && inlineElements[ stack.last() ] ) { 321 | parseEndTag( "", stack.last() ); 322 | } 323 | } 324 | 325 | if ( optionalEndTagElements[ tagName ] && stack.last() == tagName ) { 326 | parseEndTag( "", tagName ); 327 | } 328 | 329 | unary = voidElements[ tagName ] || !!unary; 330 | 331 | if ( !unary ) 332 | stack.push( tagName ); 333 | 334 | var attrs = {}; 335 | 336 | rest.replace(ATTR_REGEXP, 337 | function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) { 338 | var value = doubleQuotedValue 339 | || singleQuotedValue 340 | || unquotedValue 341 | || ''; 342 | 343 | attrs[name] = decodeEntities(value); 344 | }); 345 | if (handler.start) handler.start( tagName, attrs, unary ); 346 | } 347 | 348 | function parseEndTag( tag, tagName ) { 349 | var pos = 0, i; 350 | tagName = angular.lowercase(tagName); 351 | if ( tagName ) 352 | // Find the closest opened tag of the same type 353 | for ( pos = stack.length - 1; pos >= 0; pos-- ) 354 | if ( stack[ pos ] == tagName ) 355 | break; 356 | 357 | if ( pos >= 0 ) { 358 | // Close all the open elements, up the stack 359 | for ( i = stack.length - 1; i >= pos; i-- ) 360 | if (handler.end) handler.end( stack[ i ] ); 361 | 362 | // Remove the open elements from the stack 363 | stack.length = pos; 364 | } 365 | } 366 | } 367 | 368 | var hiddenPre=document.createElement("pre"); 369 | var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/; 370 | /** 371 | * decodes all entities into regular string 372 | * @param value 373 | * @returns {string} A string with decoded entities. 374 | */ 375 | function decodeEntities(value) { 376 | if (!value) { return ''; } 377 | 378 | // Note: IE8 does not preserve spaces at the start/end of innerHTML 379 | // so we must capture them and reattach them afterward 380 | var parts = spaceRe.exec(value); 381 | var spaceBefore = parts[1]; 382 | var spaceAfter = parts[3]; 383 | var content = parts[2]; 384 | if (content) { 385 | hiddenPre.innerHTML=content.replace(//g, '>'); 411 | } 412 | 413 | /** 414 | * create an HTML/XML writer which writes to buffer 415 | * @param {Array} buf use buf.jain('') to get out sanitized html string 416 | * @returns {object} in the form of { 417 | * start: function(tag, attrs, unary) {}, 418 | * end: function(tag) {}, 419 | * chars: function(text) {}, 420 | * comment: function(text) {} 421 | * } 422 | */ 423 | function htmlSanitizeWriter(buf, uriValidator){ 424 | var ignore = false; 425 | var out = angular.bind(buf, buf.push); 426 | return { 427 | start: function(tag, attrs, unary){ 428 | tag = angular.lowercase(tag); 429 | if (!ignore && specialElements[tag]) { 430 | ignore = tag; 431 | } 432 | if (!ignore && validElements[tag] === true) { 433 | out('<'); 434 | out(tag); 435 | angular.forEach(attrs, function(value, key){ 436 | var lkey=angular.lowercase(key); 437 | var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background'); 438 | if (validAttrs[lkey] === true && 439 | (uriAttrs[lkey] !== true || uriValidator(value, isImage))) { 440 | out(' '); 441 | out(key); 442 | out('="'); 443 | out(encodeEntities(value)); 444 | out('"'); 445 | } 446 | }); 447 | out(unary ? '/>' : '>'); 448 | } 449 | }, 450 | end: function(tag){ 451 | tag = angular.lowercase(tag); 452 | if (!ignore && validElements[tag] === true) { 453 | out(''); 456 | } 457 | if (tag == ignore) { 458 | ignore = false; 459 | } 460 | }, 461 | chars: function(chars){ 462 | if (!ignore) { 463 | out(encodeEntities(chars)); 464 | } 465 | } 466 | }; 467 | } 468 | 469 | 470 | // define ngSanitize module and register $sanitize service 471 | angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider); 472 | 473 | /* global sanitizeText: false */ 474 | 475 | /** 476 | * @ngdoc filter 477 | * @name ngSanitize.filter:linky 478 | * @function 479 | * 480 | * @description 481 | * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and 482 | * plain email address links. 483 | * 484 | * Requires the {@link ngSanitize `ngSanitize`} module to be installed. 485 | * 486 | * @param {string} text Input text. 487 | * @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in. 488 | * @returns {string} Html-linkified text. 489 | * 490 | * @usage 491 | 492 | * 493 | * @example 494 | 495 | 496 | 507 |
508 | Snippet: 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 520 | 523 | 524 | 525 | 526 | 529 | 532 | 533 | 534 | 535 | 536 | 537 | 538 |
FilterSourceRendered
linky filter 518 |
<div ng-bind-html="snippet | linky">
</div>
519 |
521 |
522 |
linky target 527 |
<div ng-bind-html="snippetWithTarget | linky:'_blank'">
</div>
528 |
530 |
531 |
no filter
<div ng-bind="snippet">
</div>
539 | 540 | 541 | it('should linkify the snippet with urls', function() { 542 | expect(using('#linky-filter').binding('snippet | linky')). 543 | toBe('Pretty text with some links: ' + 544 | 'http://angularjs.org/, ' + 545 | 'us@somewhere.org, ' + 546 | 'another@somewhere.org, ' + 547 | 'and one more: ftp://127.0.0.1/.'); 548 | }); 549 | 550 | it ('should not linkify snippet without the linky filter', function() { 551 | expect(using('#escaped-html').binding('snippet')). 552 | toBe("Pretty text with some links:\n" + 553 | "http://angularjs.org/,\n" + 554 | "mailto:us@somewhere.org,\n" + 555 | "another@somewhere.org,\n" + 556 | "and one more: ftp://127.0.0.1/."); 557 | }); 558 | 559 | it('should update', function() { 560 | input('snippet').enter('new http://link.'); 561 | expect(using('#linky-filter').binding('snippet | linky')). 562 | toBe('new http://link.'); 563 | expect(using('#escaped-html').binding('snippet')).toBe('new http://link.'); 564 | }); 565 | 566 | it('should work with the target property', function() { 567 | expect(using('#linky-target').binding("snippetWithTarget | linky:'_blank'")). 568 | toBe('http://angularjs.org/'); 569 | }); 570 | 571 | 572 | */ 573 | angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { 574 | var LINKY_URL_REGEXP = 575 | /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/, 576 | MAILTO_REGEXP = /^mailto:/; 577 | 578 | return function(text, target) { 579 | if (!text) return text; 580 | var match; 581 | var raw = text; 582 | var html = []; 583 | var url; 584 | var i; 585 | while ((match = raw.match(LINKY_URL_REGEXP))) { 586 | // We can not end in these as they are sometimes found at the end of the sentence 587 | url = match[0]; 588 | // if we did not match ftp/http/mailto then assume mailto 589 | if (match[2] == match[3]) url = 'mailto:' + url; 590 | i = match.index; 591 | addText(raw.substr(0, i)); 592 | addLink(url, match[0].replace(MAILTO_REGEXP, '')); 593 | raw = raw.substring(i + match[0].length); 594 | } 595 | addText(raw); 596 | return $sanitize(html.join('')); 597 | 598 | function addText(text) { 599 | if (!text) { 600 | return; 601 | } 602 | html.push(sanitizeText(text)); 603 | } 604 | 605 | function addLink(url, text) { 606 | html.push(''); 615 | addText(text); 616 | html.push(''); 617 | } 618 | }; 619 | }]); 620 | 621 | 622 | })(window, window.angular); 623 | -------------------------------------------------------------------------------- /www/js/angular/angular-sanitize.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.4 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(p,h,q){'use strict';function E(a){var e=[];s(e,h.noop).chars(a);return e.join("")}function k(a){var e={};a=a.split(",");var d;for(d=0;d=c;d--)e.end&&e.end(f[d]);f.length=c}}var b,g,f=[],l=a;for(f.last=function(){return f[f.length-1]};a;){g=!0;if(f.last()&&x[f.last()])a=a.replace(RegExp("(.*)<\\s*\\/\\s*"+f.last()+"[^>]*>","i"),function(b,a){a=a.replace(H,"$1").replace(I,"$1");e.chars&&e.chars(r(a));return""}),c("",f.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",b)===b&&(e.comment&&e.comment(a.substring(4,b)),a=a.substring(b+3),g=!1);else if(y.test(a)){if(b=a.match(y))a= 8 | a.replace(b[0],""),g=!1}else if(J.test(a)){if(b=a.match(z))a=a.substring(b[0].length),b[0].replace(z,c),g=!1}else K.test(a)&&(b=a.match(A))&&(a=a.substring(b[0].length),b[0].replace(A,d),g=!1);g&&(b=a.indexOf("<"),g=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),e.chars&&e.chars(r(g)))}if(a==l)throw L("badparse",a);l=a}c()}function r(a){if(!a)return"";var e=M.exec(a);a=e[1];var d=e[3];if(e=e[2])n.innerHTML=e.replace(//g,">")}function s(a,e){var d=!1,c=h.bind(a,a.push);return{start:function(a,g,f){a=h.lowercase(a);!d&&x[a]&&(d=a);d||!0!==C[a]||(c("<"),c(a),h.forEach(g,function(d,f){var g=h.lowercase(f),k="img"===a&&"src"===g||"background"===g;!0!==O[g]||!0===D[g]&&!e(d,k)||(c(" "),c(f),c('="'),c(B(d)),c('"'))}),c(f?"/>":">"))},end:function(a){a=h.lowercase(a);d||!0!==C[a]||(c(""));a==d&&(d=!1)},chars:function(a){d|| 10 | c(B(a))}}}var L=h.$$minErr("$sanitize"),A=/^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,z=/^<\s*\/\s*([\w:-]+)[^>]*>/,G=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,K=/^]*?)>/i,I=/]/,d=/^mailto:/;return function(c,b){function g(a){a&&m.push(E(a))}function f(a,c){m.push("');g(c);m.push("")}if(!c)return c;for(var l,k=c,m=[],n,p;l=k.match(e);)n=l[0],l[2]==l[3]&&(n="mailto:"+n),p=l.index,g(k.substr(0,p)),f(n,l[0].replace(d,"")),k=k.substring(p+l[0].length);g(k);return a(m.join(""))}}])})(window,window.angular); 14 | //# sourceMappingURL=angular-sanitize.min.js.map 15 | -------------------------------------------------------------------------------- /www/js/angular/angular-sanitize.min.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version":3, 3 | "file":"angular-sanitize.min.js", 4 | "lineCount":13, 5 | "mappings":"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", 6 | "sources":["angular-sanitize.js"], 7 | "names":["window","angular","undefined","sanitizeText","chars","buf","htmlSanitizeWriter","writer","noop","join","makeMap","str","obj","items","split","i","length","htmlParser","html","handler","parseStartTag","tag","tagName","rest","unary","lowercase","blockElements","stack","last","inlineElements","parseEndTag","optionalEndTagElements","voidElements","push","attrs","replace","ATTR_REGEXP","match","name","doubleQuotedValue","singleQuotedValue","unquotedValue","decodeEntities","start","pos","end","index","stack.last","specialElements","RegExp","all","text","COMMENT_REGEXP","CDATA_REGEXP","indexOf","lastIndexOf","comment","substring","DOCTYPE_REGEXP","test","BEGING_END_TAGE_REGEXP","END_TAG_REGEXP","BEGIN_TAG_REGEXP","START_TAG_REGEXP","$sanitizeMinErr","value","parts","spaceRe","exec","spaceBefore","spaceAfter","content","hiddenPre","innerHTML","textContent","innerText","encodeEntities","NON_ALPHANUMERIC_REGEXP","charCodeAt","uriValidator","ignore","out","bind","validElements","forEach","key","lkey","isImage","validAttrs","uriAttrs","$$minErr","optionalEndTagBlockElements","optionalEndTagInlineElements","extend","document","createElement","module","provider","$SanitizeProvider","$get","$$sanitizeUri","uri","filter","$sanitize","LINKY_URL_REGEXP","MAILTO_REGEXP","target","addText","addLink","url","isDefined","raw","substr"] 8 | } 9 | -------------------------------------------------------------------------------- /www/js/angular/angular-touch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license AngularJS v1.2.4 3 | * (c) 2010-2014 Google, Inc. http://angularjs.org 4 | * License: MIT 5 | */ 6 | (function(window, angular, undefined) {'use strict'; 7 | 8 | /** 9 | * @ngdoc overview 10 | * @name ngTouch 11 | * @description 12 | * 13 | * # ngTouch 14 | * 15 | * The `ngTouch` module provides touch events and other helpers for touch-enabled devices. 16 | * The implementation is based on jQuery Mobile touch event handling 17 | * ([jquerymobile.com](http://jquerymobile.com/)). 18 | * 19 | * {@installModule touch} 20 | * 21 | * See {@link ngTouch.$swipe `$swipe`} for usage. 22 | * 23 | *
24 | * 25 | */ 26 | 27 | // define ngTouch module 28 | /* global -ngTouch */ 29 | var ngTouch = angular.module('ngTouch', []); 30 | 31 | /* global ngTouch: false */ 32 | 33 | /** 34 | * @ngdoc object 35 | * @name ngTouch.$swipe 36 | * 37 | * @description 38 | * The `$swipe` service is a service that abstracts the messier details of hold-and-drag swipe 39 | * behavior, to make implementing swipe-related directives more convenient. 40 | * 41 | * Requires the {@link ngTouch `ngTouch`} module to be installed. 42 | * 43 | * `$swipe` is used by the `ngSwipeLeft` and `ngSwipeRight` directives in `ngTouch`, and by 44 | * `ngCarousel` in a separate component. 45 | * 46 | * # Usage 47 | * The `$swipe` service is an object with a single method: `bind`. `bind` takes an element 48 | * which is to be watched for swipes, and an object with four handler functions. See the 49 | * documentation for `bind` below. 50 | */ 51 | 52 | ngTouch.factory('$swipe', [function() { 53 | // The total distance in any direction before we make the call on swipe vs. scroll. 54 | var MOVE_BUFFER_RADIUS = 10; 55 | 56 | function getCoordinates(event) { 57 | var touches = event.touches && event.touches.length ? event.touches : [event]; 58 | var e = (event.changedTouches && event.changedTouches[0]) || 59 | (event.originalEvent && event.originalEvent.changedTouches && 60 | event.originalEvent.changedTouches[0]) || 61 | touches[0].originalEvent || touches[0]; 62 | 63 | return { 64 | x: e.clientX, 65 | y: e.clientY 66 | }; 67 | } 68 | 69 | return { 70 | /** 71 | * @ngdoc method 72 | * @name ngTouch.$swipe#bind 73 | * @methodOf ngTouch.$swipe 74 | * 75 | * @description 76 | * The main method of `$swipe`. It takes an element to be watched for swipe motions, and an 77 | * object containing event handlers. 78 | * 79 | * The four events are `start`, `move`, `end`, and `cancel`. `start`, `move`, and `end` 80 | * receive as a parameter a coordinates object of the form `{ x: 150, y: 310 }`. 81 | * 82 | * `start` is called on either `mousedown` or `touchstart`. After this event, `$swipe` is 83 | * watching for `touchmove` or `mousemove` events. These events are ignored until the total 84 | * distance moved in either dimension exceeds a small threshold. 85 | * 86 | * Once this threshold is exceeded, either the horizontal or vertical delta is greater. 87 | * - If the horizontal distance is greater, this is a swipe and `move` and `end` events follow. 88 | * - If the vertical distance is greater, this is a scroll, and we let the browser take over. 89 | * A `cancel` event is sent. 90 | * 91 | * `move` is called on `mousemove` and `touchmove` after the above logic has determined that 92 | * a swipe is in progress. 93 | * 94 | * `end` is called when a swipe is successfully completed with a `touchend` or `mouseup`. 95 | * 96 | * `cancel` is called either on a `touchcancel` from the browser, or when we begin scrolling 97 | * as described above. 98 | * 99 | */ 100 | bind: function(element, eventHandlers) { 101 | // Absolute total movement, used to control swipe vs. scroll. 102 | var totalX, totalY; 103 | // Coordinates of the start position. 104 | var startCoords; 105 | // Last event's position. 106 | var lastPos; 107 | // Whether a swipe is active. 108 | var active = false; 109 | 110 | element.on('touchstart mousedown', function(event) { 111 | startCoords = getCoordinates(event); 112 | active = true; 113 | totalX = 0; 114 | totalY = 0; 115 | lastPos = startCoords; 116 | eventHandlers['start'] && eventHandlers['start'](startCoords, event); 117 | }); 118 | 119 | element.on('touchcancel', function(event) { 120 | active = false; 121 | eventHandlers['cancel'] && eventHandlers['cancel'](event); 122 | }); 123 | 124 | element.on('touchmove mousemove', function(event) { 125 | if (!active) return; 126 | 127 | // Android will send a touchcancel if it thinks we're starting to scroll. 128 | // So when the total distance (+ or - or both) exceeds 10px in either direction, 129 | // we either: 130 | // - On totalX > totalY, we send preventDefault() and treat this as a swipe. 131 | // - On totalY > totalX, we let the browser handle it as a scroll. 132 | 133 | if (!startCoords) return; 134 | var coords = getCoordinates(event); 135 | 136 | totalX += Math.abs(coords.x - lastPos.x); 137 | totalY += Math.abs(coords.y - lastPos.y); 138 | 139 | lastPos = coords; 140 | 141 | if (totalX < MOVE_BUFFER_RADIUS && totalY < MOVE_BUFFER_RADIUS) { 142 | return; 143 | } 144 | 145 | // One of totalX or totalY has exceeded the buffer, so decide on swipe vs. scroll. 146 | if (totalY > totalX) { 147 | // Allow native scrolling to take over. 148 | active = false; 149 | eventHandlers['cancel'] && eventHandlers['cancel'](event); 150 | return; 151 | } else { 152 | // Prevent the browser from scrolling. 153 | event.preventDefault(); 154 | eventHandlers['move'] && eventHandlers['move'](coords, event); 155 | } 156 | }); 157 | 158 | element.on('touchend mouseup', function(event) { 159 | if (!active) return; 160 | active = false; 161 | eventHandlers['end'] && eventHandlers['end'](getCoordinates(event), event); 162 | }); 163 | } 164 | }; 165 | }]); 166 | 167 | /* global ngTouch: false */ 168 | 169 | /** 170 | * @ngdoc directive 171 | * @name ngTouch.directive:ngClick 172 | * 173 | * @description 174 | * A more powerful replacement for the default ngClick designed to be used on touchscreen 175 | * devices. Most mobile browsers wait about 300ms after a tap-and-release before sending 176 | * the click event. This version handles them immediately, and then prevents the 177 | * following click event from propagating. 178 | * 179 | * Requires the {@link ngTouch `ngTouch`} module to be installed. 180 | * 181 | * This directive can fall back to using an ordinary click event, and so works on desktop 182 | * browsers as well as mobile. 183 | * 184 | * This directive also sets the CSS class `ng-click-active` while the element is being held 185 | * down (by a mouse click or touch) so you can restyle the depressed element if you wish. 186 | * 187 | * @element ANY 188 | * @param {expression} ngClick {@link guide/expression Expression} to evaluate 189 | * upon tap. (Event object is available as `$event`) 190 | * 191 | * @example 192 | 193 | 194 | 197 | count: {{ count }} 198 | 199 | 200 | */ 201 | 202 | ngTouch.config(['$provide', function($provide) { 203 | $provide.decorator('ngClickDirective', ['$delegate', function($delegate) { 204 | // drop the default ngClick directive 205 | $delegate.shift(); 206 | return $delegate; 207 | }]); 208 | }]); 209 | 210 | ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement', 211 | function($parse, $timeout, $rootElement) { 212 | var TAP_DURATION = 750; // Shorter than 750ms is a tap, longer is a taphold or drag. 213 | var MOVE_TOLERANCE = 12; // 12px seems to work in most mobile browsers. 214 | var PREVENT_DURATION = 2500; // 2.5 seconds maximum from preventGhostClick call to click 215 | var CLICKBUSTER_THRESHOLD = 25; // 25 pixels in any dimension is the limit for busting clicks. 216 | 217 | var ACTIVE_CLASS_NAME = 'ng-click-active'; 218 | var lastPreventedTime; 219 | var touchCoordinates; 220 | 221 | 222 | // TAP EVENTS AND GHOST CLICKS 223 | // 224 | // Why tap events? 225 | // Mobile browsers detect a tap, then wait a moment (usually ~300ms) to see if you're 226 | // double-tapping, and then fire a click event. 227 | // 228 | // This delay sucks and makes mobile apps feel unresponsive. 229 | // So we detect touchstart, touchmove, touchcancel and touchend ourselves and determine when 230 | // the user has tapped on something. 231 | // 232 | // What happens when the browser then generates a click event? 233 | // The browser, of course, also detects the tap and fires a click after a delay. This results in 234 | // tapping/clicking twice. So we do "clickbusting" to prevent it. 235 | // 236 | // How does it work? 237 | // We attach global touchstart and click handlers, that run during the capture (early) phase. 238 | // So the sequence for a tap is: 239 | // - global touchstart: Sets an "allowable region" at the point touched. 240 | // - element's touchstart: Starts a touch 241 | // (- touchmove or touchcancel ends the touch, no click follows) 242 | // - element's touchend: Determines if the tap is valid (didn't move too far away, didn't hold 243 | // too long) and fires the user's tap handler. The touchend also calls preventGhostClick(). 244 | // - preventGhostClick() removes the allowable region the global touchstart created. 245 | // - The browser generates a click event. 246 | // - The global click handler catches the click, and checks whether it was in an allowable region. 247 | // - If preventGhostClick was called, the region will have been removed, the click is busted. 248 | // - If the region is still there, the click proceeds normally. Therefore clicks on links and 249 | // other elements without ngTap on them work normally. 250 | // 251 | // This is an ugly, terrible hack! 252 | // Yeah, tell me about it. The alternatives are using the slow click events, or making our users 253 | // deal with the ghost clicks, so I consider this the least of evils. Fortunately Angular 254 | // encapsulates this ugly logic away from the user. 255 | // 256 | // Why not just put click handlers on the element? 257 | // We do that too, just to be sure. The problem is that the tap event might have caused the DOM 258 | // to change, so that the click fires in the same position but something else is there now. So 259 | // the handlers are global and care only about coordinates and not elements. 260 | 261 | // Checks if the coordinates are close enough to be within the region. 262 | function hit(x1, y1, x2, y2) { 263 | return Math.abs(x1 - x2) < CLICKBUSTER_THRESHOLD && Math.abs(y1 - y2) < CLICKBUSTER_THRESHOLD; 264 | } 265 | 266 | // Checks a list of allowable regions against a click location. 267 | // Returns true if the click should be allowed. 268 | // Splices out the allowable region from the list after it has been used. 269 | function checkAllowableRegions(touchCoordinates, x, y) { 270 | for (var i = 0; i < touchCoordinates.length; i += 2) { 271 | if (hit(touchCoordinates[i], touchCoordinates[i+1], x, y)) { 272 | touchCoordinates.splice(i, i + 2); 273 | return true; // allowable region 274 | } 275 | } 276 | return false; // No allowable region; bust it. 277 | } 278 | 279 | // Global click handler that prevents the click if it's in a bustable zone and preventGhostClick 280 | // was called recently. 281 | function onClick(event) { 282 | if (Date.now() - lastPreventedTime > PREVENT_DURATION) { 283 | return; // Too old. 284 | } 285 | 286 | var touches = event.touches && event.touches.length ? event.touches : [event]; 287 | var x = touches[0].clientX; 288 | var y = touches[0].clientY; 289 | // Work around desktop Webkit quirk where clicking a label will fire two clicks (on the label 290 | // and on the input element). Depending on the exact browser, this second click we don't want 291 | // to bust has either (0,0) or negative coordinates. 292 | if (x < 1 && y < 1) { 293 | return; // offscreen 294 | } 295 | 296 | // Look for an allowable region containing this click. 297 | // If we find one, that means it was created by touchstart and not removed by 298 | // preventGhostClick, so we don't bust it. 299 | if (checkAllowableRegions(touchCoordinates, x, y)) { 300 | return; 301 | } 302 | 303 | // If we didn't find an allowable region, bust the click. 304 | event.stopPropagation(); 305 | event.preventDefault(); 306 | 307 | // Blur focused form elements 308 | event.target && event.target.blur(); 309 | } 310 | 311 | 312 | // Global touchstart handler that creates an allowable region for a click event. 313 | // This allowable region can be removed by preventGhostClick if we want to bust it. 314 | function onTouchStart(event) { 315 | var touches = event.touches && event.touches.length ? event.touches : [event]; 316 | var x = touches[0].clientX; 317 | var y = touches[0].clientY; 318 | touchCoordinates.push(x, y); 319 | 320 | $timeout(function() { 321 | // Remove the allowable region. 322 | for (var i = 0; i < touchCoordinates.length; i += 2) { 323 | if (touchCoordinates[i] == x && touchCoordinates[i+1] == y) { 324 | touchCoordinates.splice(i, i + 2); 325 | return; 326 | } 327 | } 328 | }, PREVENT_DURATION, false); 329 | } 330 | 331 | // On the first call, attaches some event handlers. Then whenever it gets called, it creates a 332 | // zone around the touchstart where clicks will get busted. 333 | function preventGhostClick(x, y) { 334 | if (!touchCoordinates) { 335 | $rootElement[0].addEventListener('click', onClick, true); 336 | $rootElement[0].addEventListener('touchstart', onTouchStart, true); 337 | touchCoordinates = []; 338 | } 339 | 340 | lastPreventedTime = Date.now(); 341 | 342 | checkAllowableRegions(touchCoordinates, x, y); 343 | } 344 | 345 | // Actual linking function. 346 | return function(scope, element, attr) { 347 | var clickHandler = $parse(attr.ngClick), 348 | tapping = false, 349 | tapElement, // Used to blur the element after a tap. 350 | startTime, // Used to check if the tap was held too long. 351 | touchStartX, 352 | touchStartY; 353 | 354 | function resetState() { 355 | tapping = false; 356 | element.removeClass(ACTIVE_CLASS_NAME); 357 | } 358 | 359 | element.on('touchstart', function(event) { 360 | tapping = true; 361 | tapElement = event.target ? event.target : event.srcElement; // IE uses srcElement. 362 | // Hack for Safari, which can target text nodes instead of containers. 363 | if(tapElement.nodeType == 3) { 364 | tapElement = tapElement.parentNode; 365 | } 366 | 367 | element.addClass(ACTIVE_CLASS_NAME); 368 | 369 | startTime = Date.now(); 370 | 371 | var touches = event.touches && event.touches.length ? event.touches : [event]; 372 | var e = touches[0].originalEvent || touches[0]; 373 | touchStartX = e.clientX; 374 | touchStartY = e.clientY; 375 | }); 376 | 377 | element.on('touchmove', function(event) { 378 | resetState(); 379 | }); 380 | 381 | element.on('touchcancel', function(event) { 382 | resetState(); 383 | }); 384 | 385 | element.on('touchend', function(event) { 386 | var diff = Date.now() - startTime; 387 | 388 | var touches = (event.changedTouches && event.changedTouches.length) ? event.changedTouches : 389 | ((event.touches && event.touches.length) ? event.touches : [event]); 390 | var e = touches[0].originalEvent || touches[0]; 391 | var x = e.clientX; 392 | var y = e.clientY; 393 | var dist = Math.sqrt( Math.pow(x - touchStartX, 2) + Math.pow(y - touchStartY, 2) ); 394 | 395 | if (tapping && diff < TAP_DURATION && dist < MOVE_TOLERANCE) { 396 | // Call preventGhostClick so the clickbuster will catch the corresponding click. 397 | preventGhostClick(x, y); 398 | 399 | // Blur the focused element (the button, probably) before firing the callback. 400 | // This doesn't work perfectly on Android Chrome, but seems to work elsewhere. 401 | // I couldn't get anything to work reliably on Android Chrome. 402 | if (tapElement) { 403 | tapElement.blur(); 404 | } 405 | 406 | if (!angular.isDefined(attr.disabled) || attr.disabled === false) { 407 | element.triggerHandler('click', [event]); 408 | } 409 | } 410 | 411 | resetState(); 412 | }); 413 | 414 | // Hack for iOS Safari's benefit. It goes searching for onclick handlers and is liable to click 415 | // something else nearby. 416 | element.onclick = function(event) { }; 417 | 418 | // Actual click handler. 419 | // There are three different kinds of clicks, only two of which reach this point. 420 | // - On desktop browsers without touch events, their clicks will always come here. 421 | // - On mobile browsers, the simulated "fast" click will call this. 422 | // - But the browser's follow-up slow click will be "busted" before it reaches this handler. 423 | // Therefore it's safe to use this directive on both mobile and desktop. 424 | element.on('click', function(event, touchend) { 425 | scope.$apply(function() { 426 | clickHandler(scope, {$event: (touchend || event)}); 427 | }); 428 | }); 429 | 430 | element.on('mousedown', function(event) { 431 | element.addClass(ACTIVE_CLASS_NAME); 432 | }); 433 | 434 | element.on('mousemove mouseup', function(event) { 435 | element.removeClass(ACTIVE_CLASS_NAME); 436 | }); 437 | 438 | }; 439 | }]); 440 | 441 | /* global ngTouch: false */ 442 | 443 | /** 444 | * @ngdoc directive 445 | * @name ngTouch.directive:ngSwipeLeft 446 | * 447 | * @description 448 | * Specify custom behavior when an element is swiped to the left on a touchscreen device. 449 | * A leftward swipe is a quick, right-to-left slide of the finger. 450 | * Though ngSwipeLeft is designed for touch-based devices, it will work with a mouse click and drag 451 | * too. 452 | * 453 | * Requires the {@link ngTouch `ngTouch`} module to be installed. 454 | * 455 | * @element ANY 456 | * @param {expression} ngSwipeLeft {@link guide/expression Expression} to evaluate 457 | * upon left swipe. (Event object is available as `$event`) 458 | * 459 | * @example 460 | 461 | 462 |
463 | Some list content, like an email in the inbox 464 |
465 |
466 | 467 | 468 |
469 |
470 |
471 | */ 472 | 473 | /** 474 | * @ngdoc directive 475 | * @name ngTouch.directive:ngSwipeRight 476 | * 477 | * @description 478 | * Specify custom behavior when an element is swiped to the right on a touchscreen device. 479 | * A rightward swipe is a quick, left-to-right slide of the finger. 480 | * Though ngSwipeRight is designed for touch-based devices, it will work with a mouse click and drag 481 | * too. 482 | * 483 | * Requires the {@link ngTouch `ngTouch`} module to be installed. 484 | * 485 | * @element ANY 486 | * @param {expression} ngSwipeRight {@link guide/expression Expression} to evaluate 487 | * upon right swipe. (Event object is available as `$event`) 488 | * 489 | * @example 490 | 491 | 492 |
493 | Some list content, like an email in the inbox 494 |
495 |
496 | 497 | 498 |
499 |
500 |
501 | */ 502 | 503 | function makeSwipeDirective(directiveName, direction, eventName) { 504 | ngTouch.directive(directiveName, ['$parse', '$swipe', function($parse, $swipe) { 505 | // The maximum vertical delta for a swipe should be less than 75px. 506 | var MAX_VERTICAL_DISTANCE = 75; 507 | // Vertical distance should not be more than a fraction of the horizontal distance. 508 | var MAX_VERTICAL_RATIO = 0.3; 509 | // At least a 30px lateral motion is necessary for a swipe. 510 | var MIN_HORIZONTAL_DISTANCE = 30; 511 | 512 | return function(scope, element, attr) { 513 | var swipeHandler = $parse(attr[directiveName]); 514 | 515 | var startCoords, valid; 516 | 517 | function validSwipe(coords) { 518 | // Check that it's within the coordinates. 519 | // Absolute vertical distance must be within tolerances. 520 | // Horizontal distance, we take the current X - the starting X. 521 | // This is negative for leftward swipes and positive for rightward swipes. 522 | // After multiplying by the direction (-1 for left, +1 for right), legal swipes 523 | // (ie. same direction as the directive wants) will have a positive delta and 524 | // illegal ones a negative delta. 525 | // Therefore this delta must be positive, and larger than the minimum. 526 | if (!startCoords) return false; 527 | var deltaY = Math.abs(coords.y - startCoords.y); 528 | var deltaX = (coords.x - startCoords.x) * direction; 529 | return valid && // Short circuit for already-invalidated swipes. 530 | deltaY < MAX_VERTICAL_DISTANCE && 531 | deltaX > 0 && 532 | deltaX > MIN_HORIZONTAL_DISTANCE && 533 | deltaY / deltaX < MAX_VERTICAL_RATIO; 534 | } 535 | 536 | $swipe.bind(element, { 537 | 'start': function(coords, event) { 538 | startCoords = coords; 539 | valid = true; 540 | }, 541 | 'cancel': function(event) { 542 | valid = false; 543 | }, 544 | 'end': function(coords, event) { 545 | if (validSwipe(coords)) { 546 | scope.$apply(function() { 547 | element.triggerHandler(eventName); 548 | swipeHandler(scope, {$event: event}); 549 | }); 550 | } 551 | } 552 | }); 553 | }; 554 | }]); 555 | } 556 | 557 | // Left is negative X-coordinate, right is positive. 558 | makeSwipeDirective('ngSwipeLeft', -1, 'swipeleft'); 559 | makeSwipeDirective('ngSwipeRight', 1, 'swiperight'); 560 | 561 | 562 | 563 | })(window, window.angular); 564 | -------------------------------------------------------------------------------- /www/js/angular/angular-touch.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.4 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(y,v,z){'use strict';function t(g,a,b){q.directive(g,["$parse","$swipe",function(l,n){var r=75,h=0.3,d=30;return function(p,m,k){function e(e){if(!u)return!1;var c=Math.abs(e.y-u.y);e=(e.x-u.x)*a;return f&&cd&&c/el&&10>n|| 8 | (n>l?(d=!1,b.cancel&&b.cancel(a)):(a.preventDefault(),b.move&&b.move(m,a)))}});a.on("touchend mouseup",function(a){d&&(d=!1,b.end&&b.end(g(a),a))})}}}]);q.config(["$provide",function(g){g.decorator("ngClickDirective",["$delegate",function(a){a.shift();return a}])}]);q.directive("ngClick",["$parse","$timeout","$rootElement",function(g,a,b){function l(a,c,b){for(var f=0;fh)){var c= 9 | a.touches&&a.touches.length?a.touches:[a],b=c[0].clientX,c=c[0].clientY;1>b&&1>c||l(k,b,c)||(a.stopPropagation(),a.preventDefault(),a.target&&a.target.blur())}}function r(b){b=b.touches&&b.touches.length?b.touches:[b];var c=b[0].clientX,d=b[0].clientY;k.push(c,d);a(function(){for(var a=0;ah&&12>p)&&(k||(b[0].addEventListener("click",n,!0),b[0].addEventListener("touchstart",r,!0),k=[]),m=Date.now(),l(k,e,g),s&&s.blur(),v.isDefined(d.disabled)&&!1!==d.disabled||c.triggerHandler("click",[a]));f()});c.onclick=function(a){};c.on("click",function(b,c){a.$apply(function(){h(a,{$event:c||b})})});c.on("mousedown",function(a){c.addClass(p)});c.on("mousemove mouseup",function(a){c.removeClass(p)})}}]);t("ngSwipeLeft",-1,"swipeleft");t("ngSwipeRight",1,"swiperight")})(window, 12 | window.angular); 13 | //# sourceMappingURL=angular-touch.min.js.map 14 | -------------------------------------------------------------------------------- /www/js/angular/angular-touch.min.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version":3, 3 | "file":"angular-touch.min.js", 4 | "lineCount":12, 5 | "mappings":"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", 6 | "sources":["angular-touch.js"], 7 | "names":["window","angular","undefined","makeSwipeDirective","directiveName","direction","eventName","ngTouch","directive","$parse","$swipe","MAX_VERTICAL_DISTANCE","MAX_VERTICAL_RATIO","MIN_HORIZONTAL_DISTANCE","scope","element","attr","validSwipe","coords","startCoords","deltaY","Math","abs","y","deltaX","x","valid","swipeHandler","bind","start","event","cancel","end","$apply","triggerHandler","module","factory","getCoordinates","touches","length","e","changedTouches","originalEvent","clientX","clientY","eventHandlers","totalX","totalY","lastPos","active","on","MOVE_BUFFER_RADIUS","preventDefault","config","$provide","decorator","$delegate","shift","$timeout","$rootElement","checkAllowableRegions","touchCoordinates","i","x1","CLICKBUSTER_THRESHOLD","y1","splice","onClick","Date","now","lastPreventedTime","PREVENT_DURATION","stopPropagation","target","blur","onTouchStart","push","ACTIVE_CLASS_NAME","resetState","tapping","removeClass","clickHandler","ngClick","tapElement","startTime","touchStartX","touchStartY","srcElement","nodeType","parentNode","addClass","diff","dist","sqrt","pow","TAP_DURATION","MOVE_TOLERANCE","addEventListener","isDefined","disabled","onclick","element.onclick","touchend"] 8 | } 9 | -------------------------------------------------------------------------------- /www/js/angular/errors.json: -------------------------------------------------------------------------------- 1 | {"id":"ng","generated":"Fri Dec 06 2013 13:49:28 GMT-0500 (EST)","errors":{"$cacheFactory":{"iid":"CacheId '{0}' is already taken!"},"ngModel":{"nonassign":"Expression '{0}' is non-assignable. Element: {1}"},"$sce":{"iequirks":"Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks mode. You can fix this by adding the text to the top of your HTML document. See http://docs.angularjs.org/api/ng.$sce for more information.","insecurl":"Blocked loading resource from url not allowed by $sceDelegate policy. URL: {0}","icontext":"Attempted to trust a value in invalid context. Context: {0}; Value: {1}","imatcher":"Matchers may only be \"self\", string patterns or RegExp objects","iwcard":"Illegal sequence *** in string matcher. String: {0}","itype":"Attempted to trust a non-string value in a content requiring a string: Context: {0}","unsafe":"Attempting to use an unsafe value in a safe context."},"$controller":{"noscp":"Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`."},"$compile":{"nodomevents":"Interpolations for HTML DOM event attributes are disallowed. Please use the ng- versions (such as ng-click instead of onclick) instead.","multidir":"Multiple directives [{0}, {1}] asking for {2} on: {3}","nonassign":"Expression '{0}' used with directive '{1}' is non-assignable!","tplrt":"Template for directive '{0}' must have exactly one root element. {1}","selmulti":"Binding to the 'multiple' attribute is not supported. Element: {0}","tpload":"Failed to load template: {0}","iscp":"Invalid isolate scope definition for directive '{0}'. Definition: {... {1}: '{2}' ...}","ctreq":"Controller '{0}', required by directive '{1}', can't be found!","uterdir":"Unterminated attribute, found '{0}' but no matching '{1}' found."},"$injector":{"modulerr":"Failed to instantiate module {0} due to:\n{1}","unpr":"Unknown provider: {0}","itkn":"Incorrect injection token! Expected service name as string, got {0}","cdep":"Circular dependency found: {0}","nomod":"Module '{0}' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.","pget":"Provider '{0}' must define $get factory method."},"$rootScope":{"inprog":"{0} already in progress","infdig":"{0} $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: {1}"},"ngPattern":{"noregexp":"Expected {0} to be a RegExp but was {1}. Element: {2}"},"$interpolate":{"noconcat":"Error while interpolating: {0}\nStrict Contextual Escaping disallows interpolations that concatenate multiple expressions when a trusted value is required. See http://docs.angularjs.org/api/ng.$sce","interr":"Can't interpolate: {0}\n{1}"},"jqLite":{"offargs":"jqLite#off() does not support the `selector` argument","onargs":"jqLite#on() does not support the `selector` or `eventData` parameters","nosel":"Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element"},"ngOptions":{"iexp":"Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '{0}'. Element: {1}"},"ngRepeat":{"iidexp":"'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.","dupes":"Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}","iexp":"Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'."},"ng":{"areq":"Argument '{0}' is {1}","cpws":"Can't copy! Making copies of Window or Scope instances is not supported.","badname":"hasOwnProperty is not a valid {0} name","btstrpd":"App Already Bootstrapped with this Element '{0}'","cpi":"Can't copy! Source and destination are identical."},"$animate":{"notcsel":"Expecting class selector starting with '.' got '{0}'."},"ngTransclude":{"orphan":"Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found. Element: {0}"},"$parse":{"isecfld":"Referencing \"constructor\" field in Angular expressions is disallowed! Expression: {0}","syntax":"Syntax Error: Token '{0}' {1} at column {2} of the expression [{3}] starting at [{4}].","isecdom":"Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}","lexerr":"Lexer Error: {0} at column{1} in expression [{2}].","ueoe":"Unexpected end of expression: {0}","isecwindow":"Referencing the Window in Angular expressions is disallowed! Expression: {0}","isecfn":"Referencing Function in Angular expressions is disallowed! Expression: {0}"},"$httpBackend":{"noxhr":"This browser does not support XMLHttpRequest."},"$location":{"ipthprfx":"Invalid url \"{0}\", missing path prefix \"{1}\".","isrcharg":"The first argument of the `$location#search()` call must be a string or an object.","ihshprfx":"Invalid url \"{0}\", missing hash prefix \"{1}\"."},"$resource":{"badargs":"Expected up to 4 arguments [params, data, success, error], got {0} arguments","badmember":"Dotted member path \"@{0}\" is invalid.","badcfg":"Error in resource configuration. Expected response to contain an {0} but got an {1}","badname":"hasOwnProperty is not a valid parameter name."},"$sanitize":{"badparse":"The sanitizer was unable to parse the following block of html: {0}"}}} -------------------------------------------------------------------------------- /www/js/angular/version.json: -------------------------------------------------------------------------------- 1 | {"full":"1.2.4","major":"1","minor":"2","dot":"4","codename":"wormhole-baster","cdn":"1.2.3"} -------------------------------------------------------------------------------- /www/js/angular/version.txt: -------------------------------------------------------------------------------- 1 | 1.2.4 -------------------------------------------------------------------------------- /www/js/app.js: -------------------------------------------------------------------------------- 1 | // angular.module is a global place for creating, registering and retrieving Angular modules 2 | // 'starter' is the name of this angular module example (also set in a attribute in index.html) 3 | // the 2nd parameter is an array or 'requires' 4 | // 'starter.services' is found in services.js 5 | // 'starter.controllers' is found in controllers.js 6 | angular.module('starter', ['ionic', 'ngRoute', 'ngAnimate', 'starter.services', 'starter.controllers']) 7 | 8 | .config(function ($compileProvider){ 9 | // Needed for routing to work 10 | $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|tel):/); 11 | }) 12 | 13 | .config(function($routeProvider, $locationProvider) { 14 | 15 | // Set up the initial routes that our app will respond to. 16 | // These are then tied up to our nav router which animates and 17 | // updates a navigation bar 18 | $routeProvider.when('/home', { 19 | templateUrl: 'templates/app.html', 20 | controller: 'AppCtrl' 21 | }); 22 | 23 | // if the url matches something like /pet/2 then this route 24 | // will fire off the PetCtrl controller (controllers.js) 25 | $routeProvider.when('/pet/:petId', { 26 | templateUrl: 'templates/pet.html', 27 | controller: 'PetCtrl' 28 | }); 29 | 30 | // if none of the above routes are met, use this fallback 31 | // which executes the 'AppCtrl' controller (controllers.js) 32 | $routeProvider.otherwise({ 33 | redirectTo: '/home' 34 | }); 35 | 36 | }); 37 | 38 | -------------------------------------------------------------------------------- /www/js/controllers.js: -------------------------------------------------------------------------------- 1 | angular.module('starter.controllers', []) 2 | 3 | .controller('AppCtrl', function($scope) { 4 | // Main app controller, empty for the example 5 | }) 6 | 7 | // A simple controller that fetches a list of data 8 | .controller('PetsTabCtrl', function($scope, Pets) { 9 | // "Pets" is a service returning mock data (services.js) 10 | $scope.pets = Pets.all(); 11 | 12 | $scope.$on('tab.shown', function() { 13 | // Might do a load here 14 | }); 15 | $scope.$on('tab.hidden', function() { 16 | // Might recycle content here 17 | }); 18 | }) 19 | 20 | // A simple controller that shows a tapped item's data 21 | .controller('PetCtrl', function($scope, $routeParams, Pets) { 22 | // "Pets" is a service returning mock data (services.js) 23 | $scope.pet = Pets.get($routeParams.petId); 24 | }); 25 | -------------------------------------------------------------------------------- /www/js/services.js: -------------------------------------------------------------------------------- 1 | angular.module('starter.services', []) 2 | 3 | /** 4 | * A simple example service that returns some data. 5 | */ 6 | .factory('Pets', function() { 7 | // Might use a resource here that returns a JSON array 8 | 9 | // Some fake testing data 10 | var pets = [ 11 | { id: 0, title: 'Cats', description: 'Furry little creatures. Obsessed with plotting assassination, but never following through on it.' }, 12 | { id: 1, title: 'Dogs', description: 'Lovable. Loyal almost to a fault. Smarter than they let on.' }, 13 | { id: 2, title: 'Turtles', description: 'Everyone likes turtles.' }, 14 | { id: 3, title: 'Sharks', description: 'An advanced pet. Needs millions of gallons of salt water. Will happily eat you.' } 15 | ]; 16 | 17 | return { 18 | all: function() { 19 | return pets; 20 | }, 21 | get: function(petId) { 22 | // Simple index lookup 23 | return pets[petId]; 24 | } 25 | } 26 | }); 27 | -------------------------------------------------------------------------------- /www/res/icon/android/icon-36-ldpi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/android/icon-36-ldpi.png -------------------------------------------------------------------------------- /www/res/icon/android/icon-48-mdpi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/android/icon-48-mdpi.png -------------------------------------------------------------------------------- /www/res/icon/android/icon-72-hdpi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/android/icon-72-hdpi.png -------------------------------------------------------------------------------- /www/res/icon/android/icon-96-xhdpi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/android/icon-96-xhdpi.png -------------------------------------------------------------------------------- /www/res/icon/bada-wac/icon-48-type5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/bada-wac/icon-48-type5.png -------------------------------------------------------------------------------- /www/res/icon/bada-wac/icon-50-type3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/bada-wac/icon-50-type3.png -------------------------------------------------------------------------------- /www/res/icon/bada-wac/icon-80-type4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/bada-wac/icon-80-type4.png -------------------------------------------------------------------------------- /www/res/icon/bada/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/bada/icon-128.png -------------------------------------------------------------------------------- /www/res/icon/blackberry/icon-80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/blackberry/icon-80.png -------------------------------------------------------------------------------- /www/res/icon/ios/icon-57-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/ios/icon-57-2x.png -------------------------------------------------------------------------------- /www/res/icon/ios/icon-57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/ios/icon-57.png -------------------------------------------------------------------------------- /www/res/icon/ios/icon-72-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/ios/icon-72-2x.png -------------------------------------------------------------------------------- /www/res/icon/ios/icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/ios/icon-72.png -------------------------------------------------------------------------------- /www/res/icon/tizen/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/tizen/icon-128.png -------------------------------------------------------------------------------- /www/res/icon/webos/icon-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/webos/icon-64.png -------------------------------------------------------------------------------- /www/res/icon/windows-phone/icon-173-tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/windows-phone/icon-173-tile.png -------------------------------------------------------------------------------- /www/res/icon/windows-phone/icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/windows-phone/icon-48.png -------------------------------------------------------------------------------- /www/res/icon/windows-phone/icon-62-tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/icon/windows-phone/icon-62-tile.png -------------------------------------------------------------------------------- /www/res/screen/android/screen-hdpi-landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/android/screen-hdpi-landscape.png -------------------------------------------------------------------------------- /www/res/screen/android/screen-hdpi-portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/android/screen-hdpi-portrait.png -------------------------------------------------------------------------------- /www/res/screen/android/screen-ldpi-landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/android/screen-ldpi-landscape.png -------------------------------------------------------------------------------- /www/res/screen/android/screen-ldpi-portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/android/screen-ldpi-portrait.png -------------------------------------------------------------------------------- /www/res/screen/android/screen-mdpi-landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/android/screen-mdpi-landscape.png -------------------------------------------------------------------------------- /www/res/screen/android/screen-mdpi-portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/android/screen-mdpi-portrait.png -------------------------------------------------------------------------------- /www/res/screen/android/screen-xhdpi-landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/android/screen-xhdpi-landscape.png -------------------------------------------------------------------------------- /www/res/screen/android/screen-xhdpi-portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/android/screen-xhdpi-portrait.png -------------------------------------------------------------------------------- /www/res/screen/bada-wac/screen-type3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/bada-wac/screen-type3.png -------------------------------------------------------------------------------- /www/res/screen/bada-wac/screen-type4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/bada-wac/screen-type4.png -------------------------------------------------------------------------------- /www/res/screen/bada-wac/screen-type5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/bada-wac/screen-type5.png -------------------------------------------------------------------------------- /www/res/screen/bada/screen-portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/bada/screen-portrait.png -------------------------------------------------------------------------------- /www/res/screen/blackberry/screen-225.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/blackberry/screen-225.png -------------------------------------------------------------------------------- /www/res/screen/ios/screen-ipad-landscape-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/ios/screen-ipad-landscape-2x.png -------------------------------------------------------------------------------- /www/res/screen/ios/screen-ipad-landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/ios/screen-ipad-landscape.png -------------------------------------------------------------------------------- /www/res/screen/ios/screen-ipad-portrait-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/ios/screen-ipad-portrait-2x.png -------------------------------------------------------------------------------- /www/res/screen/ios/screen-ipad-portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/ios/screen-ipad-portrait.png -------------------------------------------------------------------------------- /www/res/screen/ios/screen-iphone-landscape-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/ios/screen-iphone-landscape-2x.png -------------------------------------------------------------------------------- /www/res/screen/ios/screen-iphone-landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/ios/screen-iphone-landscape.png -------------------------------------------------------------------------------- /www/res/screen/ios/screen-iphone-portrait-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/ios/screen-iphone-portrait-2x.png -------------------------------------------------------------------------------- /www/res/screen/ios/screen-iphone-portrait-568h-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/ios/screen-iphone-portrait-568h-2x.png -------------------------------------------------------------------------------- /www/res/screen/ios/screen-iphone-portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/ios/screen-iphone-portrait.png -------------------------------------------------------------------------------- /www/res/screen/tizen/README.md: -------------------------------------------------------------------------------- 1 | # Tizen Splash Screen 2 | 3 | Splash screens are unsupported on the Tizen platform. 4 | -------------------------------------------------------------------------------- /www/res/screen/webos/screen-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/webos/screen-64.png -------------------------------------------------------------------------------- /www/res/screen/windows-phone/screen-portrait.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionic-team/ionic-intro/484f0ec4da051940fb30383ded9aa7f3e6fac736/www/res/screen/windows-phone/screen-portrait.jpg -------------------------------------------------------------------------------- /www/templates/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

{{pet.title}}

16 |

{{pet.description}}

17 | 18 |
19 |
20 |
21 |
22 | 23 | 24 | 25 | 26 |
27 |

Adopt a pet today.

28 |
29 |
30 | 34 | 38 | 41 | 42 |
43 |
44 |
45 | 46 | 47 | 48 | 49 |

About this app

50 |

51 | This is a sample seed project for the Ionic Framework. Please change it to match your needs. 52 |

53 |
54 |
55 | 56 |
57 |
58 | -------------------------------------------------------------------------------- /www/templates/pet.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | {{ pet.description }} 10 | 11 | --------------------------------------------------------------------------------