diff --git a/awx/ui/static/js/controllers/Jobs.js b/awx/ui/static/js/controllers/Jobs.js index e3d196d319..ecbf8d86e5 100644 --- a/awx/ui/static/js/controllers/Jobs.js +++ b/awx/ui/static/js/controllers/Jobs.js @@ -203,6 +203,7 @@ function JobsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, J $scope.job_id = id; $scope.parseType = 'yaml'; $scope.statusSearchSpin = false; + $scope.disableParseSelection = true; function getPlaybooks(project, playbook) { if (!Empty(project)) { diff --git a/awx/ui/static/js/forms/JobTemplates.js b/awx/ui/static/js/forms/JobTemplates.js index 279f7bd980..6feb58babe 100644 --- a/awx/ui/static/js/forms/JobTemplates.js +++ b/awx/ui/static/js/forms/JobTemplates.js @@ -240,6 +240,7 @@ angular.module('JobTemplateFormDefinition', []) addRequired: false, editRequired: false, readonly: true, + ngShow: "allow_callbacks", column: 2, required: false, 'class': 'span12', diff --git a/awx/ui/static/js/lists/JobTemplates.js b/awx/ui/static/js/lists/JobTemplates.js index 9625cb30d3..62c0b1ea93 100644 --- a/awx/ui/static/js/lists/JobTemplates.js +++ b/awx/ui/static/js/lists/JobTemplates.js @@ -27,7 +27,8 @@ angular.module('JobTemplatesListDefinition', []) label: 'Name' }, description: { - label: 'Description' + label: 'Description', + columnClass: 'hidden-sm hidden-xs' } }, @@ -50,24 +51,26 @@ angular.module('JobTemplatesListDefinition', []) edit: { label: 'Edit', ngClick: "editJobTemplate(job_template.id)", - icon: 'icon-edit', awToolTip: 'Edit template', "class": 'btn-default btn-xs', dataPlacement: 'top' }, submit: { label: 'Launch', - icon: 'icon-rocket', mode: 'all', - "class": 'btn-xs btn-success', ngClick: 'submitJob(job_template.id)', awToolTip: 'Start a job using this template', dataPlacement: 'top' }, + schedule: { + label: 'Schedule', + mode: 'all', + awToolTip: 'Schedule a future job using this template', + dataPlacement: 'top' + }, "delete": { label: 'Delete', ngClick: "deleteJobTemplate(job_template.id, job_template.name)", - icon: 'icon-trash', "class": 'btn-danger btn-xs', awToolTip: 'Delete template', dataPlacement: 'top' diff --git a/awx/ui/static/js/lists/Organizations.js b/awx/ui/static/js/lists/Organizations.js index c167adceef..b34faaea30 100644 --- a/awx/ui/static/js/lists/Organizations.js +++ b/awx/ui/static/js/lists/Organizations.js @@ -25,7 +25,8 @@ angular.module('OrganizationListDefinition', []) label: 'Name' }, description: { - label: 'Description' + label: 'Description', + columnClass: 'hidden-sm hidden-xs' } }, diff --git a/awx/ui/static/js/lists/Projects.js b/awx/ui/static/js/lists/Projects.js index 7e44a8ef82..9170d085bc 100644 --- a/awx/ui/static/js/lists/Projects.js +++ b/awx/ui/static/js/lists/Projects.js @@ -28,14 +28,15 @@ angular.module('ProjectsListDefinition', []) }, description: { label: 'Description', - columnClass: 'hidden-sm hidden-xs', - excludeModal: true + excludeModal: true, + columnClass: 'hidden-sm hidden-xs' }, scm_type: { label: 'Type', searchType: 'select', searchOptions: [], // will be set by Options call to projects resource excludeModal: true, + columnClass: 'hidden-sm hidden-xs', nosort: true }, status: { diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index 057a738532..32d86e129e 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -584,6 +584,7 @@ legend { /* Pagination */ .page-label { + font-size: 12px; margin-top: 0; text-align: right; } @@ -816,23 +817,19 @@ input[type="checkbox"].checkbox-no-label { .list-actions { margin: 0; } - table { + .list-wrapper { background-color: @well; padding: 10px; border-radius: 4px; border: 1px solid @well-border; } - form { - background-color: @well; - padding: 10px; - border-radius: 4px; - border: 1px solid @well-border; - margin: 10px 0; - } .ui-accordion-content { padding-left: 15px; padding-right: 15px; } + .page-label { + margin-top: 5px; + } } #home-list-actions { @@ -1586,6 +1583,10 @@ tr td button i { text-align: left; } + .list-action-label { + display: none; + } + .site-footer { height: 145px; padding-top: 5px; diff --git a/awx/ui/static/lib/angular-cookies/.bower.json b/awx/ui/static/lib/angular-cookies/.bower.json index fc1b5cf02e..60abf2f915 100644 --- a/awx/ui/static/lib/angular-cookies/.bower.json +++ b/awx/ui/static/lib/angular-cookies/.bower.json @@ -1,19 +1,18 @@ { "name": "angular-cookies", - "version": "1.2.12", + "version": "1.2.15-build.2398+sha.4bab3d8", "main": "./angular-cookies.js", "dependencies": { - "angular": "1.2.12" + "angular": "1.2.15-build.2398+sha.4bab3d8" }, "homepage": "https://github.com/angular/bower-angular-cookies", - "_release": "1.2.12", + "_release": "1.2.15-build.2398+sha.4bab3d8", "_resolution": { "type": "version", - "tag": "v1.2.12", - "commit": "5975d048a8b651b5db467f560c54bde3bfdbd1a2" + "tag": "v1.2.15-build.2398+sha.4bab3d8", + "commit": "8ca6ddfbd86f4bda921fa3d22e8d2e7d7e9b04d4" }, "_source": "git://github.com/angular/bower-angular-cookies.git", "_target": "~1.2.12", - "_originalSource": "angular-cookies", - "_direct": true + "_originalSource": "angular-cookies" } \ No newline at end of file diff --git a/awx/ui/static/lib/angular-cookies/angular-cookies.js b/awx/ui/static/lib/angular-cookies/angular-cookies.js index c4e52747e6..9d3d5a7542 100644 --- a/awx/ui/static/lib/angular-cookies/angular-cookies.js +++ b/awx/ui/static/lib/angular-cookies/angular-cookies.js @@ -1,20 +1,19 @@ /** - * @license AngularJS v1.2.12 + * @license AngularJS v1.2.15-build.2398+sha.4bab3d8 * (c) 2010-2014 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; /** - * @ngdoc overview + * @ngdoc module * @name ngCookies * @description * * # ngCookies * - * The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies. + * The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies. * - * {@installModule cookies} * *
* @@ -25,9 +24,8 @@ angular.module('ngCookies', ['ng']). /** - * @ngdoc object - * @name ngCookies.$cookies - * @requires $browser + * @ngdoc service + * @name $cookies * * @description * Provides read/write access to browser's cookies. @@ -38,8 +36,8 @@ angular.module('ngCookies', ['ng']). * Requires the {@link ngCookies `ngCookies`} module to be installed. * * @example - - + + - - + + */ factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) { var cookies = {}, @@ -134,8 +132,8 @@ angular.module('ngCookies', ['ng']). /** - * @ngdoc object - * @name ngCookies.$cookieStore + * @ngdoc service + * @name $cookieStore * @requires $cookies * * @description @@ -152,8 +150,7 @@ angular.module('ngCookies', ['ng']). return { /** * @ngdoc method - * @name ngCookies.$cookieStore#get - * @methodOf ngCookies.$cookieStore + * @name $cookieStore#get * * @description * Returns the value of given cookie key @@ -168,8 +165,7 @@ angular.module('ngCookies', ['ng']). /** * @ngdoc method - * @name ngCookies.$cookieStore#put - * @methodOf ngCookies.$cookieStore + * @name $cookieStore#put * * @description * Sets a value for given cookie key @@ -183,8 +179,7 @@ angular.module('ngCookies', ['ng']). /** * @ngdoc method - * @name ngCookies.$cookieStore#remove - * @methodOf ngCookies.$cookieStore + * @name $cookieStore#remove * * @description * Remove given cookie diff --git a/awx/ui/static/lib/angular-cookies/angular-cookies.min.js b/awx/ui/static/lib/angular-cookies/angular-cookies.min.js index 6e61b65d93..824ae4fbf2 100644 --- a/awx/ui/static/lib/angular-cookies/angular-cookies.min.js +++ b/awx/ui/static/lib/angular-cookies/angular-cookies.min.js @@ -1,5 +1,5 @@ /* - AngularJS v1.2.12 + AngularJS v1.2.15-build.2398+sha.4bab3d8 (c) 2010-2014 Google, Inc. http://angularjs.org License: MIT */ diff --git a/awx/ui/static/lib/angular-cookies/angular-cookies.min.js.map b/awx/ui/static/lib/angular-cookies/angular-cookies.min.js.map index a7fd1e9caa..6a04717c18 100644 --- a/awx/ui/static/lib/angular-cookies/angular-cookies.min.js.map +++ b/awx/ui/static/lib/angular-cookies/angular-cookies.min.js.map @@ -2,7 +2,7 @@ "version":3, "file":"angular-cookies.min.js", "lineCount":7, -"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;", +"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CAmBtCD,CAAAE,OAAA,CAAe,WAAf,CAA4B,CAAC,IAAD,CAA5B,CAAAC,QAAA,CA2BW,UA3BX,CA2BuB,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,CA3BvB,CAAAH,QAAA,CA2HW,cA3HX,CA2H2B,CAAC,UAAD,CAAa,QAAQ,CAACoB,CAAD,CAAW,CAErD,MAAO,KAWAC,QAAQ,CAACC,CAAD,CAAM,CAEjB,MAAO,CADHP,CACG,CADKK,CAAA,CAASE,CAAT,CACL,EAAQzB,CAAA0B,SAAA,CAAiBR,CAAjB,CAAR,CAAkCA,CAFxB,CAXd,KA0BAS,QAAQ,CAACF,CAAD,CAAMP,CAAN,CAAa,CACxBK,CAAA,CAASE,CAAT,CAAA,CAAgBzB,CAAA4B,OAAA,CAAeV,CAAf,CADQ,CA1BrB,QAuCGW,QAAQ,CAACJ,CAAD,CAAM,CACpB,OAAOF,CAAA,CAASE,CAAT,CADa,CAvCjB,CAF8C,CAAhC,CA3H3B,CAnBsC,CAArC,CAAA,CA+LE1B,MA/LF,CA+LUA,MAAAC,QA/LV;", "sources":["angular-cookies.js"], "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"] } diff --git a/awx/ui/static/lib/angular-cookies/bower.json b/awx/ui/static/lib/angular-cookies/bower.json index 4835a52c87..6356d244ff 100644 --- a/awx/ui/static/lib/angular-cookies/bower.json +++ b/awx/ui/static/lib/angular-cookies/bower.json @@ -1,8 +1,8 @@ { "name": "angular-cookies", - "version": "1.2.12", + "version": "1.2.15-build.2398+sha.4bab3d8", "main": "./angular-cookies.js", "dependencies": { - "angular": "1.2.12" + "angular": "1.2.15-build.2398+sha.4bab3d8" } } diff --git a/awx/ui/static/lib/angular-filters/.bower.json b/awx/ui/static/lib/angular-filters/.bower.json new file mode 100644 index 0000000000..18dcf52fcc --- /dev/null +++ b/awx/ui/static/lib/angular-filters/.bower.json @@ -0,0 +1,30 @@ +{ + "author": "Francesco Pontillo", + "name": "angular-filters", + "description": "A collection of filters for AngularJS.", + "version": "1.1.0", + "homepage": "https://github.com/frapontillo/angular-filters", + "repository": { + "type": "git", + "url": "git://github.com/frapontillo/angular-filters.git" + }, + "main": "./dist/angular-filters.min.js", + "dependencies": { + "angular": "1.2.10" + }, + "devDependencies": { + "angular-mocks": "1.2.10" + }, + "resolutions": { + "angular": "1.2.10" + }, + "_release": "1.1.0", + "_resolution": { + "type": "version", + "tag": "1.1.0", + "commit": "ecd468b898f99786e90c4631835e83ef93a2d743" + }, + "_source": "git://github.com/frapontillo/angular-filters.git", + "_target": "*", + "_originalSource": "angular-filters" +} \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/.gitignore b/awx/ui/static/lib/angular-filters/.gitignore new file mode 100644 index 0000000000..2de9d958d6 --- /dev/null +++ b/awx/ui/static/lib/angular-filters/.gitignore @@ -0,0 +1,3 @@ +.idea +node_modules +bower_components \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/.jshintrc b/awx/ui/static/lib/angular-filters/.jshintrc new file mode 100644 index 0000000000..861a058c3c --- /dev/null +++ b/awx/ui/static/lib/angular-filters/.jshintrc @@ -0,0 +1,26 @@ +{ + "node": true, + "browser": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "indent": 2, + "latedef": true, + "newcap": true, + "noarg": true, + "quotmark": "single", + "regexp": true, + "undef": true, + "unused": true, + "strict": true, + "trailing": true, + "smarttabs": true, + "globals": { + "angular": false, + "$": false, + "jQuery": false + } +} diff --git a/awx/ui/static/lib/angular-filters/.travis.yml b/awx/ui/static/lib/angular-filters/.travis.yml new file mode 100644 index 0000000000..f4eba0d61e --- /dev/null +++ b/awx/ui/static/lib/angular-filters/.travis.yml @@ -0,0 +1,12 @@ + language: node_js + node_js: + - "0.10.15" + + before_install: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + - npm install -g grunt-cli karma bower + - npm install + - bower install + + script: "grunt" \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/CHANGELOG.md b/awx/ui/static/lib/angular-filters/CHANGELOG.md new file mode 100644 index 0000000000..3a84d5bfd3 --- /dev/null +++ b/awx/ui/static/lib/angular-filters/CHANGELOG.md @@ -0,0 +1,32 @@ +CHANGELOG +========= + +#### v1.1.0 + +- Added `property` filter +- Added `join` filter +- Updated to angular 1.2.10 + +#### v1.0.1 + +- Improved tests and stability +- Rewritten build process + +#### v1.0.0 + +- Main module renamed to `frapontillo.ex.filters` in order to adhere with the [Angular Component Specification draft](https://github.com/PascalPrecht/angular-component-spec). +- Added `bool` filter. +- Upgraded bower information, node packages and Karma test runner. + +#### v0.0.2 + +- Added `firstNotNull`, `lastNotNull`, `max`, `min`. +- Test set complete. +- TravisCI is working. + +#### v0.0.1 + +- First release. +- `default` filter is the only filter at the moment. +- Unit testing with grunt, testacular and gruntacular configured. +- `defaultSpec` test written. \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/Gruntfile.js b/awx/ui/static/lib/angular-filters/Gruntfile.js new file mode 100644 index 0000000000..f6f51ba3bb --- /dev/null +++ b/awx/ui/static/lib/angular-filters/Gruntfile.js @@ -0,0 +1,109 @@ +'use strict'; + +module.exports = function(grunt) { + require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); + + // configurable paths + var yeomanConfig = { + src: 'src', + dist: 'dist', + test: 'test' + }; + + grunt.initConfig({ + yeoman: yeomanConfig, + pkg: grunt.file.readJSON('package.json'), + dev: { + reporters: 'dots' + }, + karma : { + options: { + configFile: 'karma.conf.js', + singleRun: true + }, + travis: { + browsers: ['PhantomJS'] + }, + local: { + browsers: ['Chrome'] + }, + dev: { + singleRun: false + } + }, + jshint: { + options: { + jshintrc: '.jshintrc' + }, + src: [ + 'Gruntfile.js', + '<%= yeoman.src %>/**/*.js' + ], + test: { + src: ['<%= yeoman.test %>/**/*.js'], + options: { + jshintrc: 'test/.jshintrc' + } + } + }, + meta: { + banner: '/**\n' + ' * <%= pkg.description %>\n' + + ' * @version v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' + + ' * @author <%= pkg.author.name %>\n' + + ' * @link <%= pkg.homepage %>\n' + + ' * @license <%= _.pluck(pkg.licenses, "type").join(", ") %>\n**/\n\n' + }, + clean: { + dist: { + files: [{ + dot: true, + src: [ + '<%= yeoman.dist %>/*', + '!<%= yeoman.dist %>/.git*' + ] + }] + }, + temp: { + src: ['<%= yeoman.dist %>/.temp'] + } + }, + ngmin: { + dist: { + expand: true, + cwd: '<%= yeoman.src %>', + src: ['**/*.js'], + dest: '<%= yeoman.dist %>/.temp' + } + }, + concat: { + options: { + banner: '<%= meta.banner %>\'use strict\';\n', + process: function(src, filepath) { + return '// Source: ' + filepath + '\n' + + src.replace(/(^|\n)[ \t]*('use strict'|"use strict");?\s*/g, '$1'); + } + }, + build: { + src: ['common/*.js', '<%= yeoman.dist %>/.temp/**/*.js'], + dest: '<%= yeoman.dist %>/<%= pkg.name %>.js' + } + }, + uglify: { + options: { + banner: '<%= meta.banner %>' + }, + build: { + src: ['<%= yeoman.dist %>/<%= pkg.name %>.js'], + dest: '<%= yeoman.dist %>/<%= pkg.name %>.min.js' + } + } + }); + + grunt.registerTask('test', ['jshint', 'karma:unit']); + grunt.registerTask('test-travis', ['jshint', 'karma:travis']); + + grunt.registerTask('build', ['clean', 'ngmin', 'concat', 'uglify', 'clean:temp']); + grunt.registerTask('travis', ['test-travis', 'build']); + grunt.registerTask('default', ['test-travis', 'build']); + +}; \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/LICENSE b/awx/ui/static/lib/angular-filters/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/awx/ui/static/lib/angular-filters/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/awx/ui/static/lib/angular-filters/README.md b/awx/ui/static/lib/angular-filters/README.md new file mode 100644 index 0000000000..c0dc78db9c --- /dev/null +++ b/awx/ui/static/lib/angular-filters/README.md @@ -0,0 +1,200 @@ +angular-filters [![Build Status](https://travis-ci.org/frapontillo/angular-filters.png?branch=master)](https://travis-ci.org/frapontillo/angular-filters) +=============== + +A collection of useful filters for [AngularJS](http://angularjs.org/). + +You can install the latest version of `angular-filters` with `bower`: + +```bash +$ bower install angular-filters +``` + +Then, simply include `./dist/angular-filters.js` or `./dist/angular-filters.min.js` in your Web app and inject the module `frapontillo.ex.filters` in your application. + +## Filters specs + +The included filters are: + +- [`bool:trueValue:falseValue`](#bool) +- [`default:defaultValue`](#default) +- [`firstNotNull`](#firstnotnull) +- [`lastNotNull`](#lastnotnull) +- [`max`](#max) +- [`min`](#min) +- [`property`](#property) +- [`join`](#join) + +### bool + +The `bool` filter allows to **specify true and false values** to show depending on the input value. The second parameter will be returned if and only if the first parameter is `true`; the third parameter will be returned if and only if the first parameter is `false`. + +This filter can be used to print a specific message depending on a boolean value. + +Use it as follows: + +```html +

{{ someBoolValue | bool:'Candies!':'No candies :(' }}

+``` + +```javascript + $scope.returnValue = $filter('bool')($scope.someBoolValue, 'Candies!', 'No candies :('); +``` + +### default + +The `default` filter allows to **specify a default fallback value** if an object is one of the following: + +- `null` +- `undefined` +- empty string, `''` + +Please notice that if a value equals to `0`, the default value won't be returned, as `0` is accepted. + +This filter is useful when another filter return is not safe and when you want to display a fallback value. + +Use it as follows: + +```html +

{{ someValue | number:2 | default:'No value is available.' }}

+``` + +```javascript + $scope.returnValue = $filter('default') + ($filter('number')($scope.someValue, 2), 'No value is available.'); +``` + +### firstNotNull + +The `firstNotNull` filter returns the **first element from an array** that is neither `null` or `undefined`. This means it returns all numbers and strings, even if empty. It returns `undefined` if all values aren't set or if the array is empty. + +Use it as follows: + +```html +

{{ myValues | firstNotNull }}

+``` + +```javascript + $scope.firstValue = $filter('firstNotNull')($scope.myValues); +``` + +### lastNotNull + +The `lastNotNull` filter returns the **last element from an array** that is neither `null` or `undefined`. This means it returns all numbers and strings, even if empty. It returns `undefined` if all values aren't set or if the array is empty. + +Use it as follows: + +```html +

{{ myValues | lastNotNull }}

+``` + +```javascript + $scope.firstValue = $filter('lastNotNull')($scope.myValues); +``` + +### max + +The `max` filter returns the **maximum value from an array** that is neither `null` or `undefined`. It returns `undefined` if all values aren't set or if the array is empty. + +Use it as follows: + +```html +

{{ myValues | max }}

+``` + +```javascript + $scope.maxValue = $filter('max')($scope.myValues); +``` + +### min + +The `min` filter returns the **minimum value from an array** that is neither `null` or `undefined`. It returns `undefined` if all values aren't set or if the array is empty. + +Use it as follows: + +```html +

{{ myValues | min }}

+``` + +```javascript + $scope.minValue = $filter('min')($scope.myValues); +``` + +### property + +The `property` filter returns an **array with only the specified property from the original objects**, not altering the `null` or `undefined` values. + +Use it as follows: + +```html +

{{ myObjects | property:'myText' }}

+``` + +```javascript + $scope.allTheTexts = $filter('property')($scope.myObjects, 'myText'); +``` + +### join + +The `join` filter returns **the original array as a string, with its elements joined with the specified separator**, if any, otherwise defaulting to the comma `,`. + +Use it as follows: + +```html +

{{ myValues | join:', ' }}

+``` + +```javascript + $scope.joinedValues = $filter('join')($scope.myValues, ', '); +``` + +## Development + +### Test and build + +To test and build the distribution files yourself, do the following: + +```shell +npm install -g grunt-cli karma bower +npm install +bower install +grunt +``` + +These are the available grunt task: + +* `karma:travis`, run karma tests once, on PhantomJS +* `karma:local`, run karma tests once, on Chrome +* `karma:dev`, run karma tests indefinitely after every file change, on Chrome +* `jshint:src`, run jshint on every source file +* `jshint:test`, run jshint on every test file +* `clean:dist`, clean the distribution directory +* `clean:temp`, clean the temporary directory +* `ngmin`, prepares every angular file into the `dist/.temp` directory +* `concat`, concatenates the module declaration and the `ngmin`-ified file from the `dist/.temp` into the `dist` directory, adding the banner +* `uglify`, minifies the output file in the `dist` directory, adding the banner +* `build`, builds the regular and minified file +* `test-travis`, runs `jshint` and `karma:travis` + +Use the default task by calling `grunt` to run tests on PhantomJS and builds the regular and minified file. + +### Contribute + +To contribute, please follow the generic [AngularJS Contributing Guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md), with the only exception to send the PR to the `develop` branch instead of `master`. + +## License + +``` + Copyright 2014 Francesco Pontillo + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +``` \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/bower.json b/awx/ui/static/lib/angular-filters/bower.json new file mode 100644 index 0000000000..51426c2e12 --- /dev/null +++ b/awx/ui/static/lib/angular-filters/bower.json @@ -0,0 +1,21 @@ +{ + "author": "Francesco Pontillo", + "name": "angular-filters", + "description": "A collection of filters for AngularJS.", + "version": "1.1.0", + "homepage": "https://github.com/frapontillo/angular-filters", + "repository": { + "type": "git", + "url": "git://github.com/frapontillo/angular-filters.git" + }, + "main": "./dist/angular-filters.min.js", + "dependencies": { + "angular": "1.2.10" + }, + "devDependencies": { + "angular-mocks": "1.2.10" + }, + "resolutions": { + "angular": "1.2.10" + } +} diff --git a/awx/ui/static/lib/angular-filters/common/module.js b/awx/ui/static/lib/angular-filters/common/module.js new file mode 100644 index 0000000000..4a284259ee --- /dev/null +++ b/awx/ui/static/lib/angular-filters/common/module.js @@ -0,0 +1,2 @@ +angular.module('frapontillo.ex.filters', []); +angular.module('frapontillo', ['ex.filters']); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/dist/angular-filters.js b/awx/ui/static/lib/angular-filters/dist/angular-filters.js new file mode 100644 index 0000000000..b6a6e7f663 --- /dev/null +++ b/awx/ui/static/lib/angular-filters/dist/angular-filters.js @@ -0,0 +1,101 @@ +/** + * A collection of filters for AngularJS. + * @version v1.1.0 - 2014-01-30 + * @author Francesco Pontillo + * @link https://github.com/frapontillo/angular-filters + * @license Apache License 2.0 +**/ + +'use strict'; +// Source: common/module.js +angular.module('frapontillo.ex.filters', []); +angular.module('frapontillo', ['ex.filters']); +// Source: dist/.temp/filters/bool/bool.js +angular.module('frapontillo.ex.filters').filter('bool', function () { + return function (input, valueTrue, valueFalse) { + return input !== true ? valueFalse : valueTrue; + }; +}); +// Source: dist/.temp/filters/default/default.js +angular.module('frapontillo.ex.filters').filter('default', function () { + return function (input, value) { + if (input !== null && input !== undefined && (input !== '' || angular.isNumber(input))) { + return input; + } + return value || ''; + }; +}); +// Source: dist/.temp/filters/firstNotNull/firstNotNull.js +angular.module('frapontillo.ex.filters').filter('firstNotNull', function () { + return function (input) { + if (input) { + var l = input.length - 1; + for (var i = 0; i <= l; i++) { + if (input[i] !== undefined && input[i] !== null) { + return input[i]; + } + } + } + }; +}); +// Source: dist/.temp/filters/join/join.js +angular.module('frapontillo.ex.filters').filter('join', function () { + return function (array, separator) { + if (!array) { + return ''; + } + return array.join(separator); + }; +}); +// Source: dist/.temp/filters/lastNotNull/lastNotNull.js +angular.module('frapontillo.ex.filters').filter('lastNotNull', function () { + return function (input) { + if (input) { + var l = input.length - 1; + for (var i = l; i >= 0; i--) { + if (input[i] !== undefined) { + return input[i]; + } + } + } + }; +}); +// Source: dist/.temp/filters/max/max.js +angular.module('frapontillo.ex.filters').filter('max', function () { + return function (input) { + var out; + if (input) { + for (var i in input) { + if (input[i] > out || out === undefined || out === null) { + out = input[i]; + } + } + } + return out; + }; +}); +// Source: dist/.temp/filters/min/min.js +angular.module('frapontillo.ex.filters').filter('min', function () { + return function (input) { + var out; + if (input) { + for (var i in input) { + if (input[i] < out || out === undefined || out === null) { + out = input[i]; + } + } + } + return out; + }; +}); +// Source: dist/.temp/filters/property/property.js +angular.module('frapontillo.ex.filters').filter('property', function () { + return function (array, property) { + var newArray = []; + angular.forEach(array, function (element) { + var evalProperty = element[property]; + newArray.push(evalProperty); + }); + return newArray; + }; +}); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/dist/angular-filters.min.js b/awx/ui/static/lib/angular-filters/dist/angular-filters.min.js new file mode 100644 index 0000000000..a4c177364b --- /dev/null +++ b/awx/ui/static/lib/angular-filters/dist/angular-filters.min.js @@ -0,0 +1,9 @@ +/** + * A collection of filters for AngularJS. + * @version v1.1.0 - 2014-01-30 + * @author Francesco Pontillo + * @link https://github.com/frapontillo/angular-filters + * @license Apache License 2.0 +**/ + +"use strict";angular.module("frapontillo.ex.filters",[]),angular.module("frapontillo",["ex.filters"]),angular.module("frapontillo.ex.filters").filter("bool",function(){return function(a,b,c){return a!==!0?c:b}}),angular.module("frapontillo.ex.filters").filter("default",function(){return function(a,b){return null===a||void 0===a||""===a&&!angular.isNumber(a)?b||"":a}}),angular.module("frapontillo.ex.filters").filter("firstNotNull",function(){return function(a){if(a)for(var b=a.length-1,c=0;b>=c;c++)if(void 0!==a[c]&&null!==a[c])return a[c]}}),angular.module("frapontillo.ex.filters").filter("join",function(){return function(a,b){return a?a.join(b):""}}),angular.module("frapontillo.ex.filters").filter("lastNotNull",function(){return function(a){if(a)for(var b=a.length-1,c=b;c>=0;c--)if(void 0!==a[c])return a[c]}}),angular.module("frapontillo.ex.filters").filter("max",function(){return function(a){var b;if(a)for(var c in a)(a[c]>b||void 0===b||null===b)&&(b=a[c]);return b}}),angular.module("frapontillo.ex.filters").filter("min",function(){return function(a){var b;if(a)for(var c in a)(a[c]= 0; i--) { + if (input[i] !== undefined) { + return input[i]; + } + } + } + }; + } +); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/src/filters/max/max.js b/awx/ui/static/lib/angular-filters/src/filters/max/max.js new file mode 100644 index 0000000000..435d4f6d6b --- /dev/null +++ b/awx/ui/static/lib/angular-filters/src/filters/max/max.js @@ -0,0 +1,17 @@ +'use strict'; + +angular.module('frapontillo.ex.filters') + .filter('max', function() { + return function(input) { + var out; + if (input) { + for (var i in input) { + if (input[i] > out || out === undefined || out === null) { + out = input[i]; + } + } + } + return out; + }; + } +); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/src/filters/min/min.js b/awx/ui/static/lib/angular-filters/src/filters/min/min.js new file mode 100644 index 0000000000..bfbae9ef8c --- /dev/null +++ b/awx/ui/static/lib/angular-filters/src/filters/min/min.js @@ -0,0 +1,17 @@ +'use strict'; + +angular.module('frapontillo.ex.filters') + .filter('min', function() { + return function(input) { + var out; + if (input) { + for (var i in input) { + if (input[i] < out || out === undefined || out === null) { + out = input[i]; + } + } + } + return out; + }; + } +); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/src/filters/property/property.js b/awx/ui/static/lib/angular-filters/src/filters/property/property.js new file mode 100644 index 0000000000..5f1c1bdc15 --- /dev/null +++ b/awx/ui/static/lib/angular-filters/src/filters/property/property.js @@ -0,0 +1,15 @@ +'use strict'; + +angular.module('frapontillo.ex.filters') + .filter('property', function() { + return function(array, property) { + var newArray = []; + // for each object in the array + angular.forEach(array, function(element) { + var evalProperty = element[property]; + newArray.push(evalProperty); + }); + return newArray; + }; + } +); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/test/.jshintrc b/awx/ui/static/lib/angular-filters/test/.jshintrc new file mode 100644 index 0000000000..aa37e7a4d0 --- /dev/null +++ b/awx/ui/static/lib/angular-filters/test/.jshintrc @@ -0,0 +1,35 @@ +{ + "node": true, + "browser": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "indent": 2, + "latedef": true, + "newcap": true, + "noarg": true, + "quotmark": "single", + "regexp": true, + "undef": true, + "unused": true, + "strict": true, + "trailing": true, + "smarttabs": true, + "globals": { + "after": false, + "afterEach": false, + "angular": false, + "before": false, + "beforeEach": false, + "browser": false, + "describe": false, + "expect": false, + "inject": false, + "it": false, + "spyOn": false + } +} + diff --git a/awx/ui/static/lib/angular-filters/test/bool/boolSpec.js b/awx/ui/static/lib/angular-filters/test/bool/boolSpec.js new file mode 100644 index 0000000000..5a3807636f --- /dev/null +++ b/awx/ui/static/lib/angular-filters/test/bool/boolSpec.js @@ -0,0 +1,34 @@ +'use strict'; + +describe('bool', function () { + var boolFilter; + + beforeEach(module('frapontillo.ex.filters')); + beforeEach(inject(function ($filter) { + boolFilter = $filter('bool'); + })); + + it('should match the true value', function () { + expect(boolFilter(true, 1, 0)).toEqual(1); + }); + + it('should match the false value', function () { + expect(boolFilter(false, 1, 0)).toEqual(0); + }); + + it('should match a string to the false value', function () { + expect(boolFilter('true', 1, 0)).toEqual(0); + }); + + it('should match the empty string to the false value', function () { + expect(boolFilter('', 1, 0)).toEqual(0); + }); + + it('should match undefined to the false value', function () { + expect(boolFilter(undefined, 1, 0)).toEqual(0); + }); + + it('should match null to the false value', function () { + expect(boolFilter(null, 1, 0)).toEqual(0); + }); +}); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/test/default/defaultSpec.js b/awx/ui/static/lib/angular-filters/test/default/defaultSpec.js new file mode 100644 index 0000000000..3ac2e6d032 --- /dev/null +++ b/awx/ui/static/lib/angular-filters/test/default/defaultSpec.js @@ -0,0 +1,47 @@ +'use strict'; + +describe('default', function () { + var defaultFilter; + var numberFilter; + + beforeEach(module('frapontillo.ex.filters')); + beforeEach(inject(function ($filter) { + defaultFilter = $filter('default'); + numberFilter = $filter('number'); + })); + + it('should return the number 1337', function () { + var inputVal = 1337; + expect(defaultFilter(inputVal)).toEqual(1337); + }); + + it('should return a "default" string', function () { + var inputVal; + var defaultVal = 'default'; + expect(defaultFilter(inputVal, defaultVal)).toEqual('default'); + }); + + it('should return a "default" string', function () { + var inputVal = null; + var defaultVal = 'default'; + expect(defaultFilter(inputVal, defaultVal)).toEqual('default'); + }); + + it('should return the number 0', function () { + var inputVal = 0; + var defaultVal = 'default'; + expect(defaultFilter(inputVal, defaultVal)).toEqual(0); + }); + + it('should return the string "13.37"', function () { + var inputVal = '13.3678787'; + var defaultVal = 'N.A.'; + expect(defaultFilter(numberFilter(inputVal, 2), defaultVal)).toEqual('13.37'); + }); + + it('should return a "N.A." string', function () { + var inputVal; + var defaultVal = 'N.A.'; + expect(defaultFilter(numberFilter(inputVal, 2), defaultVal)).toEqual(defaultVal); + }); +}); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/test/firstNotNull/firstNotNullSpec.js b/awx/ui/static/lib/angular-filters/test/firstNotNull/firstNotNullSpec.js new file mode 100644 index 0000000000..6c91e274b3 --- /dev/null +++ b/awx/ui/static/lib/angular-filters/test/firstNotNull/firstNotNullSpec.js @@ -0,0 +1,28 @@ +'use strict'; + +describe('firstNotNull', function () { + var firstNotNullFilter; + + beforeEach(module('frapontillo.ex.filters')); + beforeEach(inject(function ($filter) { + firstNotNullFilter = $filter('firstNotNull'); + })); + + it('should return the number 1337', function () { + expect(firstNotNullFilter([ + null, undefined, 1337, 0 + ])).toEqual(1337); + }); + + it('should return the number 0', function () { + expect(firstNotNullFilter([ + null, 0, undefined, 3 + ])).toEqual(0); + }); + + it('should return undefined', function () { + expect(firstNotNullFilter([ + null, undefined + ])).toEqual(undefined); + }); +}); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/test/join/joinSpec.js b/awx/ui/static/lib/angular-filters/test/join/joinSpec.js new file mode 100644 index 0000000000..558713c0ee --- /dev/null +++ b/awx/ui/static/lib/angular-filters/test/join/joinSpec.js @@ -0,0 +1,30 @@ +'use strict'; + +describe('join', function () { + var joinFilter; + + beforeEach(module('frapontillo.ex.filters')); + beforeEach(inject(function ($filter) { + joinFilter = $filter('join'); + })); + + it('should return \'this is a simple test\'', function () { + expect(joinFilter(['this', 'is', 'a', 'simple', 'test'], ' ')).toEqual('this is a simple test'); + }); + + it('should return the empty string for an undefined array', function () { + expect(joinFilter(undefined, '')).toEqual(''); + }); + + it('should return the empty string for an empty array', function () { + expect(joinFilter([], '')).toEqual(''); + }); + + it('should return \'0123456789\'', function () { + expect(joinFilter([0,1,2,3,4,5,6,7,8,9], '')).toEqual('0123456789'); + }); + + it('should default to the comma separator and return \'0,1,2,3,4,5,6,7,8,9\'', function () { + expect(joinFilter([0,1,2,3,4,5,6,7,8,9])).toEqual('0,1,2,3,4,5,6,7,8,9'); + }); +}); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/test/lastNotNull/lastNotNullSpec.js b/awx/ui/static/lib/angular-filters/test/lastNotNull/lastNotNullSpec.js new file mode 100644 index 0000000000..1bb60e7c3e --- /dev/null +++ b/awx/ui/static/lib/angular-filters/test/lastNotNull/lastNotNullSpec.js @@ -0,0 +1,28 @@ +'use strict'; + +describe('lastNotNull', function () { + var lastNotNullFilter; + + beforeEach(module('frapontillo.ex.filters')); + beforeEach(inject(function ($filter) { + lastNotNullFilter = $filter('lastNotNull'); + })); + + it('should return the number 0', function () { + expect(lastNotNullFilter([ + null, undefined, 1337, 0 + ])).toEqual(0); + }); + + it('should return the number 1337', function () { + expect(lastNotNullFilter([ + null, 0, 1337, undefined + ])).toEqual(1337); + }); + + it('should return undefined', function () { + expect(lastNotNullFilter([ + null, undefined + ])).toEqual(undefined); + }); +}); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/test/max/maxSpec.js b/awx/ui/static/lib/angular-filters/test/max/maxSpec.js new file mode 100644 index 0000000000..1924bb4b87 --- /dev/null +++ b/awx/ui/static/lib/angular-filters/test/max/maxSpec.js @@ -0,0 +1,28 @@ +'use strict'; + +describe('max', function () { + var maxFilter; + + beforeEach(module('frapontillo.ex.filters')); + beforeEach(inject(function ($filter) { + maxFilter = $filter('max'); + })); + + it('should return the number 1337', function () { + expect(maxFilter([ + null, undefined, 1337, 0 + ])).toEqual(1337); + }); + + it('should return the number 1337', function () { + expect(maxFilter([ + null, 0, 1337, undefined + ])).toEqual(1337); + }); + + it('should return undefined', function () { + expect(maxFilter([ + null, undefined + ])).toEqual(undefined); + }); +}); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/test/min/minSpec.js b/awx/ui/static/lib/angular-filters/test/min/minSpec.js new file mode 100644 index 0000000000..b357834153 --- /dev/null +++ b/awx/ui/static/lib/angular-filters/test/min/minSpec.js @@ -0,0 +1,28 @@ +'use strict'; + +describe('min', function () { + var minFilter; + + beforeEach(module('frapontillo.ex.filters')); + beforeEach(inject(function ($filter) { + minFilter = $filter('min'); + })); + + it('should return the number 0', function () { + expect(minFilter([ + null, undefined, 1337, 0 + ])).toEqual(0); + }); + + it('should return the number 1', function () { + expect(minFilter([ + null, 1, 1337, undefined + ])).toEqual(1); + }); + + it('should return undefined', function () { + expect(minFilter([ + null, undefined + ])).toEqual(undefined); + }); +}); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-filters/test/property/propertySpec.js b/awx/ui/static/lib/angular-filters/test/property/propertySpec.js new file mode 100644 index 0000000000..da80421f42 --- /dev/null +++ b/awx/ui/static/lib/angular-filters/test/property/propertySpec.js @@ -0,0 +1,42 @@ +'use strict'; + +describe('property', function () { + var propertyFilter; + + var testArray = [ + {id:0, text:'zero'}, + {id:1, text:'one'}, + {id:2, text:'two'}, + {id:3, text:'three'}, + {id:4, text:'four'}, + {id:5, text:'five'}, + {id:6, text:'six'} + ]; + + var makeArray = function() { + return angular.copy(testArray); + }; + + beforeEach(module('frapontillo.ex.filters')); + beforeEach(inject(function ($filter) { + propertyFilter = $filter('property'); + })); + + it('should return the \'id\' properties', function () { + var filteredArray = propertyFilter(makeArray(), 'id'); + expect(filteredArray[0]).toEqual(0); + expect(filteredArray.length).toEqual(7); + }); + + it('should return elements with only the \'text\' property', function () { + var filteredArray = propertyFilter(makeArray(), 'text'); + expect(filteredArray[0]).toEqual('zero'); + expect(filteredArray.length).toEqual(7); + }); + + it('should return empty elements', function () { + var filteredArray = propertyFilter(makeArray(), 'something else'); + expect(filteredArray[0]).toEqual(undefined); + expect(filteredArray.length).toEqual(7); + }); +}); \ No newline at end of file diff --git a/awx/ui/static/lib/angular-resource/.bower.json b/awx/ui/static/lib/angular-resource/.bower.json index 7af7ddcdc3..dbf41c64b7 100644 --- a/awx/ui/static/lib/angular-resource/.bower.json +++ b/awx/ui/static/lib/angular-resource/.bower.json @@ -1,19 +1,18 @@ { "name": "angular-resource", - "version": "1.2.12", + "version": "1.2.15-build.2398+sha.4bab3d8", "main": "./angular-resource.js", "dependencies": { - "angular": "1.2.12" + "angular": "1.2.15-build.2398+sha.4bab3d8" }, "homepage": "https://github.com/angular/bower-angular-resource", - "_release": "1.2.12", + "_release": "1.2.15-build.2398+sha.4bab3d8", "_resolution": { "type": "version", - "tag": "v1.2.12", - "commit": "4d368199bfbab887f1c1622bb47d4d0924d6a8ed" + "tag": "v1.2.15-build.2398+sha.4bab3d8", + "commit": "c20e7f87b0f788322c1c1920f1646a116389fa8d" }, "_source": "git://github.com/angular/bower-angular-resource.git", "_target": "~1.2.12", - "_originalSource": "angular-resource", - "_direct": true + "_originalSource": "angular-resource" } \ No newline at end of file diff --git a/awx/ui/static/lib/angular-resource/angular-resource.js b/awx/ui/static/lib/angular-resource/angular-resource.js index 4988910c84..73a31070f3 100644 --- a/awx/ui/static/lib/angular-resource/angular-resource.js +++ b/awx/ui/static/lib/angular-resource/angular-resource.js @@ -1,5 +1,5 @@ /** - * @license AngularJS v1.2.12 + * @license AngularJS v1.2.15-build.2398+sha.4bab3d8 * (c) 2010-2014 Google, Inc. http://angularjs.org * License: MIT */ @@ -49,7 +49,7 @@ function shallowClearAndCopy(src, dst) { } /** - * @ngdoc overview + * @ngdoc module * @name ngResource * @description * @@ -58,7 +58,6 @@ function shallowClearAndCopy(src, dst) { * The `ngResource` module provides interaction support with RESTful services * via the $resource service. * - * {@installModule resource} * *
* @@ -66,8 +65,8 @@ function shallowClearAndCopy(src, dst) { */ /** - * @ngdoc object - * @name ngResource.$resource + * @ngdoc service + * @name $resource * @requires $http * * @description @@ -103,8 +102,8 @@ function shallowClearAndCopy(src, dst) { * If the parameter value is prefixed with `@` then the value of that parameter is extracted from * the data object (useful for non-GET operations). * - * @param {Object.=} actions Hash with declaration of custom action that should extend the - * default set of resource actions. The declaration should be created in the format of {@link + * @param {Object.=} actions Hash with declaration of custom action that should extend + * the default set of resource actions. The declaration should be created in the format of {@link * ng.$http#usage_parameters $http.config}: * * {action1: {method:?, params:?, isArray:?, headers:?, ...}, @@ -139,35 +138,37 @@ function shallowClearAndCopy(src, dst) { * - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that * should abort the request when resolved. * - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the - * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5 - * requests with credentials} for more information. - * - **`responseType`** - `{string}` - see {@link - * https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}. + * XHR object. See + * [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5) + * for more information. + * - **`responseType`** - `{string}` - see + * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType). * - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods - * `response` and `responseError`. Both `response` and `responseError` interceptors get called * with `http response` object. See {@link ng.$http $http interceptors}. * * @returns {Object} A resource "class" object with methods for the default set of resource actions * optionally extended with custom `actions`. The default set contains these actions: - * - * { 'get': {method:'GET'}, - * 'save': {method:'POST'}, - * 'query': {method:'GET', isArray:true}, - * 'remove': {method:'DELETE'}, - * 'delete': {method:'DELETE'} }; + * ```js + * { 'get': {method:'GET'}, + * 'save': {method:'POST'}, + * 'query': {method:'GET', isArray:true}, + * 'remove': {method:'DELETE'}, + * 'delete': {method:'DELETE'} }; + * ``` * * Calling these methods invoke an {@link ng.$http} with the specified http method, * destination and parameters. When the data is returned from the server then the object is an * instance of the resource class. The actions `save`, `remove` and `delete` are available on it * as methods with the `$` prefix. This allows you to easily perform CRUD operations (create, * read, update, delete) on server-side data like this: - *
-        var User = $resource('/user/:userId', {userId:'@id'});
-        var user = User.get({userId:123}, function() {
-          user.abc = true;
-          user.$save();
-        });
-     
+ * ```js + * var User = $resource('/user/:userId', {userId:'@id'}); + * var user = User.get({userId:123}, function() { + * user.abc = true; + * user.$save(); + * }); + * ``` * * It is important to realize that invoking a $resource object method immediately returns an * empty reference (object or array depending on `isArray`). Once the data is returned from the @@ -211,7 +212,7 @@ function shallowClearAndCopy(src, dst) { * * # Credit card resource * - *
+ * ```js
      // Define CreditCard class
      var CreditCard = $resource('/user/:userId/card/:cardId',
       {userId:123, cardId:'@id'}, {
@@ -244,7 +245,7 @@ function shallowClearAndCopy(src, dst) {
      // POST: /user/123/card {number:'0123', name:'Mike Smith'}
      // server returns: {id:789, number:'0123', name: 'Mike Smith'};
      expect(newCard.id).toEqual(789);
- * 
+ * ``` * * The object returned from this function execution is a resource "class" which has "static" method * for each action in the definition. @@ -255,19 +256,19 @@ function shallowClearAndCopy(src, dst) { * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD * operations (create, read, update, delete) on server-side data. -
+   ```js
      var User = $resource('/user/:userId', {userId:'@id'});
      var user = User.get({userId:123}, function() {
        user.abc = true;
        user.$save();
      });
-   
+ ``` * * It's worth noting that the success callback for `get`, `query` and other methods gets passed * in the response that came from the server as well as $http header getter function, so one * could rewrite the above example and get access to http headers as: * -
+   ```js
      var User = $resource('/user/:userId', {userId:'@id'});
      User.get({userId:123}, function(u, getResponseHeaders){
        u.abc = true;
@@ -276,15 +277,15 @@ function shallowClearAndCopy(src, dst) {
          //putResponseHeaders => $http header getter
        });
      });
-   
+ ``` * # Creating a custom 'PUT' request * In this example we create a custom method on our resource to make a PUT request - *
+ * ```js
  *		var app = angular.module('app', ['ngResource', 'ngRoute']);
  *
  *		// Some APIs expect a PUT request in the format URL/object/ID
- *		// Here we are creating an 'update' method 
+ *		// Here we are creating an 'update' method
  *		app.factory('Notes', ['$resource', function($resource) {
  *    return $resource('/notes/:id', null,
  *        {
@@ -305,7 +306,7 @@ function shallowClearAndCopy(src, dst) {
  *
  *    // This will PUT /notes/ID with the note object in the request payload
  *		}]);
- * 
+ * ``` */ angular.module('ngResource', ['ng']). factory('$resource', ['$http', '$q', function($http, $q) { diff --git a/awx/ui/static/lib/angular-resource/angular-resource.min.js b/awx/ui/static/lib/angular-resource/angular-resource.min.js index 359e2ff94a..ead7f3d97e 100644 --- a/awx/ui/static/lib/angular-resource/angular-resource.min.js +++ b/awx/ui/static/lib/angular-resource/angular-resource.min.js @@ -1,5 +1,5 @@ /* - AngularJS v1.2.12 + AngularJS v1.2.15-build.2398+sha.4bab3d8 (c) 2010-2014 Google, Inc. http://angularjs.org License: MIT */ diff --git a/awx/ui/static/lib/angular-resource/angular-resource.min.js.map b/awx/ui/static/lib/angular-resource/angular-resource.min.js.map index 90492df88b..56eaa7b327 100644 --- a/awx/ui/static/lib/angular-resource/angular-resource.min.js.map +++ b/awx/ui/static/lib/angular-resource/angular-resource.min.js.map @@ -2,7 +2,7 @@ "version":3, "file":"angular-resource.min.js", "lineCount":12, -"mappings":"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", +"mappings":"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", "sources":["angular-resource.js"], "names":["window","angular","undefined","shallowClearAndCopy","src","dst","forEach","value","key","hasOwnProperty","charAt","$resourceMinErr","$$minErr","MEMBER_NAME_REGEX","module","factory","$http","$q","Route","template","defaults","urlParams","resourceFactory","url","paramDefaults","actions","extractParams","data","actionParams","ids","extend","isFunction","path","test","keys","split","i","ii","length","obj","defaultResponseInterceptor","response","resource","Resource","route","DEFAULT_ACTIONS","action","name","hasBody","method","a1","a2","a3","a4","params","success","error","arguments","isInstanceCall","isArray","httpConfig","responseInterceptor","interceptor","responseErrorInterceptor","responseError","copy","setUrlParams","promise","then","$promise","item","push","$resolved","noop","reject","headers","prototype","result","call","bind","Resource.bind","additionalParamDefaults","config","actionUrl","self","val","encodedVal","param","RegExp","replace","_","urlParam","isDefined","encodeURIComponent","match","p1","leadingSlashes","tail"] } diff --git a/awx/ui/static/lib/angular-resource/bower.json b/awx/ui/static/lib/angular-resource/bower.json index 2061db19ca..6c893c9fe8 100644 --- a/awx/ui/static/lib/angular-resource/bower.json +++ b/awx/ui/static/lib/angular-resource/bower.json @@ -1,8 +1,8 @@ { "name": "angular-resource", - "version": "1.2.12", + "version": "1.2.15-build.2398+sha.4bab3d8", "main": "./angular-resource.js", "dependencies": { - "angular": "1.2.12" + "angular": "1.2.15-build.2398+sha.4bab3d8" } } diff --git a/awx/ui/static/lib/angular-route/.bower.json b/awx/ui/static/lib/angular-route/.bower.json index ef3f69b674..8f853c420b 100644 --- a/awx/ui/static/lib/angular-route/.bower.json +++ b/awx/ui/static/lib/angular-route/.bower.json @@ -1,16 +1,16 @@ { "name": "angular-route", - "version": "1.2.13", + "version": "1.2.14", "main": "./angular-route.js", "dependencies": { - "angular": "1.2.13" + "angular": "1.2.14" }, "homepage": "https://github.com/angular/bower-angular-route", - "_release": "1.2.13", + "_release": "1.2.14", "_resolution": { "type": "version", - "tag": "v1.2.13", - "commit": "fed5c1c5f17cb2f358f78371fd5b03232f398a91" + "tag": "v1.2.14", + "commit": "2a998317521fb468b8b69a4a29e6be2d19bc6a3e" }, "_source": "git://github.com/angular/bower-angular-route.git", "_target": "*", diff --git a/awx/ui/static/lib/angular-route/angular-route.js b/awx/ui/static/lib/angular-route/angular-route.js index 9bb5af108e..774e7c3e65 100644 --- a/awx/ui/static/lib/angular-route/angular-route.js +++ b/awx/ui/static/lib/angular-route/angular-route.js @@ -1,12 +1,12 @@ /** - * @license AngularJS v1.2.13 + * @license AngularJS v1.2.14 * (c) 2010-2014 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; /** - * @ngdoc overview + * @ngdoc module * @name ngRoute * @description * @@ -16,8 +16,7 @@ * * ## Example * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`. - * - * {@installModule route} + * * *
*/ @@ -26,14 +25,14 @@ var ngRouteModule = angular.module('ngRoute', ['ng']). provider('$route', $RouteProvider); /** - * @ngdoc object - * @name ngRoute.$routeProvider + * @ngdoc provider + * @name $routeProvider * @function * * @description * * Used for configuring routes. - * + * * ## Example * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`. * @@ -49,27 +48,26 @@ function $RouteProvider(){ /** * @ngdoc method - * @name ngRoute.$routeProvider#when - * @methodOf ngRoute.$routeProvider + * @name $routeProvider#when * * @param {string} path Route path (matched against `$location.path`). If `$location.path` * contains redundant trailing slash or is missing one, the route will still match and the * `$location.path` will be updated to add or drop the trailing slash to exactly match the * route definition. * - * * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up + * * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up * to the next slash are matched and stored in `$routeParams` under the given `name` * when the route matches. - * * `path` can contain named groups starting with a colon and ending with a star: + * * `path` can contain named groups starting with a colon and ending with a star: * e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name` * when the route matches. - * * `path` can contain optional named groups with a question mark: e.g.`:name?`. + * * `path` can contain optional named groups with a question mark: e.g.`:name?`. * * For example, routes like `/color/:color/largecode/:largecode*\/edit` will match - * `/color/brown/largecode/code/with/slashs/edit` and extract: + * `/color/brown/largecode/code/with/slashes/edit` and extract: * - * * `color: brown` - * * `largecode: code/with/slashs`. + * * `color: brown` + * * `largecode: code/with/slashes`. * * * @param {Object} route Mapping information to be assigned to `$route.current` on route @@ -89,7 +87,7 @@ function $RouteProvider(){ * * If `template` is a function, it will be called with the following parameters: * - * - `{Array.}` - route parameters extracted from the current + * - `{Array.<Object>}` - route parameters extracted from the current * `$location.path()` by applying the current route * * - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html @@ -97,7 +95,7 @@ function $RouteProvider(){ * * If `templateUrl` is a function, it will be called with the following parameters: * - * - `{Array.}` - route parameters extracted from the current + * - `{Array.<Object>}` - route parameters extracted from the current * `$location.path()` by applying the current route * * - `resolve` - `{Object.=}` - An optional map of dependencies which should @@ -112,7 +110,7 @@ function $RouteProvider(){ * * - `key` – `{string}`: a name of a dependency to be injected into the controller. * - `factory` - `{string|function}`: If `string` then it is an alias for a service. - * Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected} + * Otherwise if function, then it is {@link auto.$injector#invoke injected} * and the return value is treated as the dependency. If the result is a promise, it is * resolved before its value is injected into the controller. Be aware that * `ngRoute.$routeParams` will still refer to the previous route within these resolve @@ -212,8 +210,7 @@ function $RouteProvider(){ /** * @ngdoc method - * @name ngRoute.$routeProvider#otherwise - * @methodOf ngRoute.$routeProvider + * @name $routeProvider#otherwise * * @description * Sets route definition that will be used on route change when no other route definition @@ -239,8 +236,8 @@ function $RouteProvider(){ function($rootScope, $location, $routeParams, $q, $injector, $http, $templateCache, $sce) { /** - * @ngdoc object - * @name ngRoute.$route + * @ngdoc service + * @name $route * @requires $location * @requires $routeParams * @@ -255,7 +252,7 @@ function $RouteProvider(){ * - `$scope` - The current route scope. * - `$template` - The current route template HTML. * - * @property {Array.} routes Array of all configured routes. + * @property {Array.<Object>} routes Array of all configured routes. * * @description * `$route` is used for deep-linking URLs to controllers and views (HTML partials). @@ -276,7 +273,7 @@ function $RouteProvider(){ Note that this example is using {@link ng.directive:script inlined templates} to get it working on jsfiddle as well. - +
Choose: @@ -309,7 +306,7 @@ function $RouteProvider(){ - angular.module('ngViewExample', ['ngRoute']) + angular.module('ngRouteExample', ['ngRoute']) .config(function($routeProvider, $locationProvider) { $routeProvider.when('/Book/:bookId', { @@ -350,17 +347,17 @@ function $RouteProvider(){ } - + it('should load and compile correct template', function() { element(by.linkText('Moby: Ch1')).click(); - var content = element(by.css('.doc-example-live [ng-view]')).getText(); + var content = element(by.css('[ng-view]')).getText(); expect(content).toMatch(/controller\: ChapterCntl/); expect(content).toMatch(/Book Id\: Moby/); expect(content).toMatch(/Chapter Id\: 1/); element(by.partialLinkText('Scarlet')).click(); - content = element(by.css('.doc-example-live [ng-view]')).getText(); + content = element(by.css('[ng-view]')).getText(); expect(content).toMatch(/controller\: BookCntl/); expect(content).toMatch(/Book Id\: Scarlet/); }); @@ -370,8 +367,7 @@ function $RouteProvider(){ /** * @ngdoc event - * @name ngRoute.$route#$routeChangeStart - * @eventOf ngRoute.$route + * @name $route#$routeChangeStart * @eventType broadcast on root scope * @description * Broadcasted before a route change. At this point the route services starts @@ -387,8 +383,7 @@ function $RouteProvider(){ /** * @ngdoc event - * @name ngRoute.$route#$routeChangeSuccess - * @eventOf ngRoute.$route + * @name $route#$routeChangeSuccess * @eventType broadcast on root scope * @description * Broadcasted after a route dependencies are resolved. @@ -403,8 +398,7 @@ function $RouteProvider(){ /** * @ngdoc event - * @name ngRoute.$route#$routeChangeError - * @eventOf ngRoute.$route + * @name $route#$routeChangeError * @eventType broadcast on root scope * @description * Broadcasted if any of the resolve promises are rejected. @@ -417,8 +411,7 @@ function $RouteProvider(){ /** * @ngdoc event - * @name ngRoute.$route#$routeUpdate - * @eventOf ngRoute.$route + * @name $route#$routeUpdate * @eventType broadcast on root scope * @description * @@ -432,8 +425,7 @@ function $RouteProvider(){ /** * @ngdoc method - * @name ngRoute.$route#reload - * @methodOf ngRoute.$route + * @name $route#reload * * @description * Causes `$route` service to reload the current route even if @@ -565,7 +557,7 @@ function $RouteProvider(){ /** - * @returns the current active route, by matching it against the URL + * @returns {Object} the current active route, by matching it against the URL */ function parseRoute() { // Match a route @@ -583,7 +575,7 @@ function $RouteProvider(){ } /** - * @returns interpolation of the redirect path with the parameters + * @returns {string} interpolation of the redirect path with the parameters */ function interpolate(string, params) { var result = []; @@ -607,8 +599,8 @@ ngRouteModule.provider('$routeParams', $RouteParamsProvider); /** - * @ngdoc object - * @name ngRoute.$routeParams + * @ngdoc service + * @name $routeParams * @requires $route * * @description @@ -617,7 +609,7 @@ ngRouteModule.provider('$routeParams', $RouteParamsProvider); * Requires the {@link ngRoute `ngRoute`} module to be installed. * * The route parameters are a combination of {@link ng.$location `$location`}'s - * {@link ng.$location#methods_search `search()`} and {@link ng.$location#methods_path `path()`}. + * {@link ng.$location#search `search()`} and {@link ng.$location#path `path()`}. * The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched. * * In case of parameter name collision, `path` params take precedence over `search` params. @@ -630,14 +622,14 @@ ngRouteModule.provider('$routeParams', $RouteParamsProvider); * Instead you can use `$route.current.params` to access the new route's parameters. * * @example - *
+ * ```js
  *  // Given:
  *  // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
  *  // Route: /Chapter/:chapterId/Section/:sectionId
  *  //
  *  // Then
  *  $routeParams ==> {chapterId:1, sectionId:2, search:'moby'}
- * 
+ * ``` */ function $RouteParamsProvider() { this.$get = function() { return {}; }; @@ -649,7 +641,7 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory); /** * @ngdoc directive - * @name ngRoute.directive:ngView + * @name ngView * @restrict ECA * * @description @@ -679,7 +671,9 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory); * - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated * as an expression yields a truthy value. * @example - +
Choose: @@ -794,17 +788,17 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory); } - + it('should load and compile correct template', function() { element(by.linkText('Moby: Ch1')).click(); - var content = element(by.css('.doc-example-live [ng-view]')).getText(); + var content = element(by.css('[ng-view]')).getText(); expect(content).toMatch(/controller\: ChapterCntl/); expect(content).toMatch(/Book Id\: Moby/); expect(content).toMatch(/Chapter Id\: 1/); element(by.partialLinkText('Scarlet')).click(); - content = element(by.css('.doc-example-live [ng-view]')).getText(); + content = element(by.css('[ng-view]')).getText(); expect(content).toMatch(/controller\: BookCntl/); expect(content).toMatch(/Book Id\: Scarlet/); }); @@ -815,8 +809,7 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory); /** * @ngdoc event - * @name ngRoute.directive:ngView#$viewContentLoaded - * @eventOf ngRoute.directive:ngView + * @name ngView#$viewContentLoaded * @eventType emit on the current ngView scope * @description * Emitted every time the ngView content is reloaded. @@ -831,6 +824,7 @@ function ngViewFactory( $route, $anchorScroll, $animate) { link: function(scope, $element, attr, ctrl, $transclude) { var currentScope, currentElement, + previousElement, autoScrollExp = attr.autoscroll, onloadExp = attr.onload || ''; @@ -838,12 +832,19 @@ function ngViewFactory( $route, $anchorScroll, $animate) { update(); function cleanupLastView() { - if (currentScope) { + if(previousElement) { + previousElement.remove(); + previousElement = null; + } + if(currentScope) { currentScope.$destroy(); currentScope = null; } if(currentElement) { - $animate.leave(currentElement); + $animate.leave(currentElement, function() { + previousElement = null; + }); + previousElement = currentElement; currentElement = null; } } diff --git a/awx/ui/static/lib/angular-route/angular-route.min.js b/awx/ui/static/lib/angular-route/angular-route.min.js index 8f8065cabe..52b3fb3c8f 100644 --- a/awx/ui/static/lib/angular-route/angular-route.min.js +++ b/awx/ui/static/lib/angular-route/angular-route.min.js @@ -1,14 +1,14 @@ /* - AngularJS v1.2.13 + AngularJS v1.2.14 (c) 2010-2014 Google, Inc. http://angularjs.org License: MIT */ -(function(h,e,A){'use strict';function u(w,q,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,n){function y(){l&&(l.$destroy(),l=null);g&&(k.leave(g),g=null)}function v(){var b=w.current&&w.current.locals;if(e.isDefined(b&&b.$template)){var b=a.$new(),f=w.current;g=n(b,function(d){k.enter(d,null,g||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||q()});y()});l=f.scope=b;l.$emit("$viewContentLoaded");l.$eval(h)}else y()}var l,g,t=b.autoscroll,h=b.onload||""; -a.$on("$routeChangeSuccess",v);v()}}}function z(e,h,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var n=e(c.contents());b.controller&&(f.$scope=a,f=h(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));n(a)}}}h=e.module("ngRoute",["ng"]).provider("$route",function(){function h(a,c){return e.extend(new (e.extend(function(){},{prototype:a})),c)}function q(a, -e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},h=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;h.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var k={};this.when=function(a,c){k[a]=e.extend({reloadOnSearch:!0},c,a&&q(a,c));if(a){var b="/"==a[a.length-1]?a.substr(0,a.length- -1):a+"/";k[b]=e.extend({redirectTo:a},q(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,n,q,v,l){function g(){var d=t(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!x)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)x=!1,a.$broadcast("$routeChangeStart",d,m),(r.current= -d)&&d.redirectTo&&(e.isString(d.redirectTo)?c.path(u(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?n.get(d):n.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=l.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl=b,c=q.get(b, -{cache:v}).then(function(a){return a.data})));e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function t(){var a,b;e.forEach(k,function(f,k){var p;if(p=!b){var s=c.path();p=f.keys;var l={};if(f.regexp)if(s=f.regexp.exec(s)){for(var g=1,q=s.length;g
* @@ -42,7 +41,7 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize'); /** * @ngdoc service - * @name ngSanitize.$sanitize + * @name $sanitize * @function * * @description @@ -58,8 +57,8 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize'); * @returns {string} Sanitized html. * * @example - - + + + + + + + + + + + + + + + + + + + + + diff --git a/awx/ui/static/lib/angular-scheduler/app/js/sampleApp.js b/awx/ui/static/lib/angular-scheduler/app/js/sampleApp.js new file mode 100644 index 0000000000..027da262db --- /dev/null +++ b/awx/ui/static/lib/angular-scheduler/app/js/sampleApp.js @@ -0,0 +1,81 @@ +/********************************************** + * sampleApp.js + * + * Copyright (c) 2013-2014 Ansible, Inc. + * + */ + +'use strict'; + +angular.module('sampleApp', ['ngRoute', 'AngularScheduler', 'Timezones']) + + .config(['$routeProvider', function($routeProvider) { + $routeProvider + .when('/', { + templateUrl: 'partials/main.html', + controller: 'sampleController' + }) + .otherwise({ + redirectTo: '/' + }); + }]) + + .constant('AngularScheduler.partial', '/lib/angular-scheduler.html') + .constant('AngularScheduler.useTimezone', false) + .constant('AngularScheduler.showUTCField', false) + .constant('$timezones.definitions.location', '/bower_components/angular-tz-extensions/tz/data') + + .controller('sampleController', ['$scope', '$filter', 'SchedulerInit', function($scope, $filter, SchedulerInit) { + + var scheduler = SchedulerInit({ scope: $scope }); + + scheduler.inject('form-container', true); + + console.log('User timezone: '); + console.log(scheduler.getUserTimezone()); + + $scope.setRRule = function() { + $scope.inputRRuleMsg = ''; + $scope.inputRRuleMsg = scheduler.setRRule($scope.inputRRule); + }; + + $scope.resetForm = function() { scheduler.clear(); }; + + $scope.saveForm = function() { + if (scheduler.isValid()) { + var schedule = scheduler.getValue(), + html = + "
\n" + + "
\n" + + "\n" + + "\n" + + "
\n" + + "
\n", + wheight = $(window).height(), + wwidth = $(window).width(), + w, h; + + w = (600 > wwidth) ? wwidth : 600; + h = (400 > wheight) ? wheight : 400; + + $('#message').html(html) + .dialog({ + title: schedule.name, + modal: true, + width: w, + height: h, + position: 'center', + buttons: { OK: function() { $(this).dialog('close');} }, + open: function () { + // fix the close button + $('.ui-dialog[aria-describedby="message"]').find('.ui-dialog-titlebar button') + .empty().attr({ 'class': 'close' }).text('x'); + // fix the OK button + $('.ui-dialog[aria-describedby="message"]').find('.ui-dialog-buttonset button:first') + .attr({ 'class': 'btn btn-primary', 'id': 'modal-ok-button' }); + } + }); + } + }; + + }]); diff --git a/awx/ui/static/lib/angular-scheduler/app/partials/main.html b/awx/ui/static/lib/angular-scheduler/app/partials/main.html new file mode 100644 index 0000000000..cf41b55a07 --- /dev/null +++ b/awx/ui/static/lib/angular-scheduler/app/partials/main.html @@ -0,0 +1,68 @@ + +
+
+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Scope VariableValue
schedulerName{{ schedulerName }}
schedulerStartDt{{ schedulerStartDt }}
schedulerStartHour{{ schedulerStartHour }}
schedulerStartMinute{{ schedulerStartMinute }}
schedulerStartSecond{{ schedulerStartSecond }}
schedulerTimeZone.name{{ schedulerTimeZone.name }}
schedulerUTCTime{{ schedulerUTCTime }}
schedulerFrequency.value{{ schedulerFrequency.value }}
schedulerInterval{{ schedulerInterval }}
monthlyRepeatOption{{ monthlyRepeatOption }}
monthDay{{ monthDay }}
monthlyOccurrence.value{{ monthlyOccurrence.value }}
monthlyWeekDay.value{{ monthlyWeekDay.value }}
yearlyRepeatOption{{ yearlyRepeatOption }}
yearlyMonth.value{{ yearlyMonth.value }}
yearlyMonthDay{{ yearlyMonthDay }}
yearlyOccurrence.value{{ yearlyOccurrence.value }}
yearlyWeekDay.value{{ yearlyWeekDay.value }}
yearlyOtherMonth.value{{ yearlyOtherMonth.value }}
weekDays.value{{ weekDays }}
schedulerEnd.value{{ schedulerEnd.value }}
schedulerOccurrenceCount{{ schedulerOccurrenceCount }}
schedulerEndDt{{ schedulerEndDt }}
+
+
+ +
+
+
+
+

RRule Demo

+

Enter an RRule to display in the form above. For RRule syntax refer to examples at https://github.com/jkbr/rrule. Click Show Me to see the form change.

+
+
+ + +
+
+
+
+ +
+
+
+
+ + +
\ No newline at end of file diff --git a/awx/ui/static/lib/angular-scheduler/bower.json b/awx/ui/static/lib/angular-scheduler/bower.json new file mode 100644 index 0000000000..2d51b9f160 --- /dev/null +++ b/awx/ui/static/lib/angular-scheduler/bower.json @@ -0,0 +1,39 @@ +{ + "name": "angular-scheduler", + "version": "0.0.1", + "authors": [ + "Chris Houseknecht " + ], + "description": "Angular based UI widget for creating repeat schedule entries.", + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "devDependencies": { + "angular-route": "*", + "components-font-awesome": "*", + "jquery": "*", + "jqueryui": "*", + "less": "*", + "angular-mocks": "~1.2.13" + }, + "dependencies": { + "angular": "~1.2.14", + "underscore": "*", + "twitter": "*", + "rrule": "*", + "timezone-js": "*", + "angular-tz-extensions":"*" + }, + "homepage": "https://github.com/chouseknecht/angular-scheduler", + "main": "git@github.com:chouseknecht/angular-scheduler.git", + "keywords": [ + "schedule", + "rrule", + "calendar" + ] +} diff --git a/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.css b/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.css new file mode 100644 index 0000000000..40b67dc329 --- /dev/null +++ b/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.css @@ -0,0 +1,93 @@ +/*************************************************************************** + * angular-scheruler.css + * + * Copyright (c) 2014 Ansible, Inc. + * + * Maintainers: + * + * Chris Houseknecht + * @chouseknecht + * chouse@ansible.com + * + */ +.ui-widget input { + font-size: 12px; + font-weight: normal; + text-align: center; +} +.ui-spinner.ui-widget-content { + border-bottom-color: #ccc; + border-top-color: #ccc; + border-left-color: #ccc; + border-right-color: #ccc; +} +.ui-spinner-button { + border-left-color: #ccc; + border-left-style: solid; + border-left-width: 1px; +} +.scheduler-time-spinner { + width: 40px; + height: 24px; +} +.scheduler-spinner { + width: 50px; + height: 24px; +} +.fmt-help { + font-size: 12px; + font-weight: normal; + color: #999; + padding-left: 10px; +} +.error { + color: #dd1b16; + font-size: 12px; + margin-bottom: 0; + margin-top: 0; + padding-top: 3px; +} +.pull-up { + margin-top: -15px; + margin-bottom: 10px; +} +.red-text { + color: #dd1b16; +} +input.ng-dirty.ng-invalid, select.ng-dirty.ng-invalid, textarea.ng-dirty.ng-invalid { + border: 1px solid red; + outline: none; +} +.help-text { + font-size: 12px; + font-weight: normal; + color: #999; + margin-top: 5px; +} +.inline-label { + margin-left: 10px; +} +#scheduler-buttons { + margin-top: 20px; +} +.no-label { + padding-top: 25px; +} +.padding-top-slim { + padding-top: 5px; +} +.option-pad-left { + padding-left: 15px; +} +.option-pad-top { + padding-top: 15px; +} +.option-pad-bottom { + padding-bottom: 15px; +} +#monthlyOccurrence, #monthlyWeekDay { + margin-top: 5px; +} +select { + width: 100%; +} \ No newline at end of file diff --git a/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.html b/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.html new file mode 100644 index 0000000000..f87af43cb6 --- /dev/null +++ b/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.html @@ -0,0 +1,229 @@ + + +
+
+ +
+
+
+
+ + +
Schedule name is required
+
+
+
+ +
+
+
+ +
+ + + + +
+
+
+
+
+ +
+ + : + : +
+
+
+
+ +
+
+
+
+
+ +
+
+
+ + +
+
+
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+
+ + + +
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+ +
+
+ + + + + + + +
+
+
Select one or more days
+
+ +
+
+
+ +
+ +
+
+
+
+
+
+ + +
+
+
+
+
+
+ + + + +
+
Provide a valid date
+
+
+
+
+ + + +
+
\ No newline at end of file diff --git a/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.js b/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.js new file mode 100644 index 0000000000..42cfc8348d --- /dev/null +++ b/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.js @@ -0,0 +1,870 @@ +/*************************************************************************** + * angular-scheruler.js + * + * Copyright (c) 2014 Ansible, Inc. + * + * Maintainers: + * + * Chris Houseknecht + * @chouseknecht + * chouse@ansible.com + * + */ + +/* global RRule */ + +'use strict'; + + +angular.module('underscore',[]) + .factory('_', [ function() { + return window._; + }]); + + +angular.module('AngularScheduler', ['underscore']) + + .constant('AngularScheduler.partial', '/lib/angular-scheduler.html') + .constant('AngularScheduler.useTimezone', false) + .constant('AngularScheduler.showUTCField', false) + + // Initialize supporting scope variables and functions. Returns a scheduler object with getString(), + // setString() and inject() methods. + .factory('SchedulerInit', ['$log', '$filter', '$timezones', 'LoadLookupValues', 'SetDefaults', 'CreateObject', '_', + 'AngularScheduler.useTimezone', 'AngularScheduler.showUTCField', + function($log, $filter, $timezones, LoadLookupValues, SetDefaults, CreateObject, _, useTimezone, showUTCField) { + return function(params) { + + var scope = params.scope; + + scope.schedulerShowTimeZone = useTimezone; + scope.schedulerShowUTCStartTime = showUTCField; + + scope.setDefaults = function() { + if (useTimezone) { + scope.current_timezone = $timezones.getLocal(); + if ($.isEmptyObject(scope.current_timezone) || !scope.current_timezone.name) { + $log.error('Failed to find local timezone. Defaulting to America/New_York.'); + scope.current_timezone = { name: 'America/New_York' }; + } + // Set the element options + $timezones.getZoneList(scope); + } + else { + scope.setDefaults(); + } + + return CreateObject(scope); + + }; + }]) + + /** + Return an AngularScheduler object we can use to get the RRule result from user input, check if + user input is valid, reset the form, etc. All the things we need to access and manipulate the + scheduler widget + */ + .factory('CreateObject', ['AngularScheduler.useTimezone', '$filter', 'GetRule', 'Inject', 'SetDefaults', '$timezones', 'SetRule', + function(useTimezone, $filter, GetRule, Inject, SetDefaults, $timezones, SetRule) { + return function(scope) { + var fn = function() { + + this.scope = scope; + this.useTimezone = useTimezone; + + // Evaluate user intput and build options for passing to rrule + this.getOptions = function() { + var options = {}; + options.startDate = this.scope.schedulerUTCTime; + options.frequency = this.scope.schedulerFrequency.value; + options.interval = this.scope.schedulerInterval; + if (this.scope.schedulerEnd.value === 'after') { + options.occurrenceCount = this.scope.schedulerOccurrenceCount; + } + if (this.scope.schedulerEnd.value === 'on') { + options.endDate = scope.schedulerEndDt + this.scope.schedulerUTCTime.replace(/^\d{4}-\d{2}-\d{2}/,''); + } + if (this.scope.schedulerFrequency.value === 'weekly') { + options.weekDays = this.scope.weekDays; + } + else if (this.scope.schedulerFrequency.value === 'yearly') { + if (this.scope.yearlyRepeatOption === 'month') { + options.month = this.scope.yearlyMonth.value; + options.monthDay = this.scope.yearlyMonthDay; + } + else { + options.setOccurrence = this.scope.yearlyOccurrence.value; + options.weekDays = this.scope.yearlyWeekDay.value; + options.month = this.scope.yearlyOtherMonth.value; + } + } + else if (this.scope.schedulerFrequency.value === 'monthly') { + if (this.scope.monthlyRepeatOption === 'day') { + options.monthDay = this.scope.monthDay; + } + else { + options.setOccurrence = this.scope.monthlyOccurrence.value; + options.weekDays = this.scope.monthlyWeekDay.value; + } + } + return options; + }; + + // Clear custom field errors + this.clearErrors = function() { + this.scope.scheduler_weekDays_error = false; + this.scope.scheduler_endDt_error = false; + this.scope.resetStartDate(); + this.scope.scheduler_endDt_error = false; + this.scope.scheduler_form.schedulerEndDt.$setValidity('custom-error', true); + this.scope.scheduler_form.schedulerEndDt.$setPristine(); + this.scope.scheduler_form.$setPristine(); + }; + + // Check the input form for errors + this.isValid = function() { + var startDt, now, dateStr, adjNow, timeNow, timeFuture, validity = true; + this.clearErrors(); + + if (this.scope.schedulerFrequency.value === 'weekly' && scope.weekDays.length === 0) { + this.scope.scheduler_weekDays_error = true; + validity = false; + } + if (!this.scope.scheduler_form.schedulerName.$valid) { + // Make sure schedulerName requird error shows up + this.scope.scheduler_form.schedulerName.$dirty = true; + $('#schedulerName').addClass('ng-dirty'); + validity = false; + } + if (this.scope.schedulerEnd.value === 'on') { + if (!/^\d{4}-\d{2}-\d{2}$/.test(this.scope.schedulerEndDt)) { + this.scope.scheduler_form.schedulerEndDt.$pristine = false; + this.scope.scheduler_form.schedulerEndDt.$dirty = true; + $('#schedulerEndDt').removeClass('ng-pristine').removeClass('ng-valid').removeClass('ng-valid-custom-error') + .addClass('ng-dirty').addClass('ng-invalid').addClass('ng-invalid-custom-error'); + this.scope.scheduler_endDt_error = true; + validity = false; + } + } + if (this.scope.schedulerUTCTime) { + try { + startDt = new Date(this.scope.schedulerUTCTime); + if (!isNaN(startDt)) { + timeFuture = startDt.getTime(); + now = new Date(); + if (this.useTimezone) { + dateStr = now.getFullYear() + '-' + + $filter('schZeroPad')(now.getMonth() + 1, 2)+ '-' + + $filter('schZeroPad')(now.getDate(),2) + 'T' + + $filter('schZeroPad')(now.getHours(),2) + ':' + + $filter('schZeroPad')(now.getMinutes(),2) + ':' + + $filter('schZeroPad')(now.getSeconds(),2) + '.000Z'; + adjNow = $timezones.toUTC(dateStr, this.scope.schedulerTimeZone.name); //Adjust to the selected TZ + timeNow = adjNow.getTime(); + } + else { + timeNow = now.getTime(); + } + if (timeNow >= timeFuture) { + this.scope.startDateError("Start date and time must be in the future"); + validity = false; + } + } + else { + this.scope.startDateError("Invalid start date and time"); + validity = false; + } + } + catch(e) { + this.scope.startDateError("Invalid start date and time"); + validity = false; + } + } + else { + scope.startDateError("Provide a valid start date and time"); + validity = false; + } + return validity; + }; + + // Returns an rrule object + this.getRule = function() { + var options = this.getOptions(); + return GetRule(options); + }; + + // Return object containing schedule name, string representation of rrule per iCalendar RFC, + // and options used to create rrule + this.getValue = function() { + var rule = this.getRule(), + options = this.getOptions(); + return { + name: scope.schedulerName, + rrule: rule.toString(), + options: options + }; + }; + + this.setRRule = function(rule) { + this.clear(); + return SetRule(rule, this.scope); + }; + + // Read in the HTML partial, compile and inject it into the DOM. + // Pass in the target element's id attribute value or an angular.element() + // object. + this.inject = function(element, showButtons) { + return Inject({ scope: this.scope, target: element, buttons: showButtons }); + }; + + // Clear the form, returning all elements to a default state + this.clear = function() { + this.clearErrors(); + this.scope.scheduler_form.schedulerName.$setPristine(); + this.scope.setDefaults(); + }; + + // Get the user's local timezone + this.getUserTimezone = function() { + return $timezones.getLocal(); + } + }; + return new fn(); + }; + }]) + + .factory('Inject', ['AngularScheduler.partial', '$compile', '$http', '$log', function(scheduler_partial, $compile, $http, $log) { + return function(params) { + + var scope = params.scope, + target = params.target, + buttons = params.buttons; + + if (scope.removeHtmlReady) { + scope.removeHtmlReady(); + } + scope.removeHtmlReady = scope.$on('htmlReady', function(e, data) { + var element = (angular.isObject(target)) ? target : angular.element(document.getElementById(target)); + element.html(data); + $compile(element)(scope); + if (buttons) { + $('#scheduler-buttons').show(); + } + }); + + $http({ method: 'GET', url: scheduler_partial }) + .success( function(data) { + scope.$emit('htmlReady', data); + }) + .error( function(data, status) { + throw('Error reading ' + scheduler_partial + '. ' + status); + //$log.error('Error calling ' + scheduler_partial + '. ' + status); + }); + }; + }]) + + .factory('GetRule', ['$log', function($log) { + return function(params) { + // Convert user inputs to an rrule. Returns rrule object using https://github.com/jkbr/rrule + // **list of 'valid values' found below in LoadLookupValues + + var startDate = params.startDate, // date object or string in yyyy-MM-ddTHH:mm:ss.sssZ format + frequency = params.frequency, // string, optional, valid value from frequencyOptions + interval = params.interval, // integer, optional + occurrenceCount = params.occurrenceCount, //integer, optional + endDate = params.endDate, // date object or string in yyyy-MM-dd format, optional + // ignored if occurrenceCount provided + month = params.month, // integer, optional, valid value from months + monthDay = params.monthDay, // integer, optional, between 1 and 31 + weekDays = params.weekDays, // integer, optional, valid value from weekdays + setOccurrence = params.setOccurrence, // integer, optional, valid value from occurrences + options = {}, i; + + if (angular.isDate(startDate)) { + options.dtstart = startDate; + } + else { + try { + options.dtstart = new Date(startDate); + } + catch(e) { + $log.error('Date conversion failed. Attempted to convert ' + startDate + ' to Date. ' + e.message); + } + } + + if (frequency && frequency !== 'none') { + options.freq = RRule[frequency.toUpperCase()]; + options.interval = interval; + + if (weekDays && typeof weekDays === 'string') { + options.byweekday = RRule[weekDays.toUpperCase()]; + } + + if (weekDays && angular.isArray(weekDays)) { + options.byweekday = []; + for (i=0; i < weekDays.length; i++) { + options.byweekday.push(RRule[weekDays[i].toUpperCase()]); + } + } + + if (setOccurrence !== undefined && setOccurrence !== null) { + options.bysetpos = setOccurrence; + } + + if (month) { + options.bymonth = month; + } + + if (monthDay) { + options.bymonthday = monthDay; + } + + if (occurrenceCount) { + options.count = occurrenceCount; + } + else if (endDate) { + if (angular.isDate(endDate)) { + options.until = endDate; + } + else { + try { + options.until = new Date(endDate); + } + catch(e) { + $log.error('Date conversion failed. Attempted to convert ' + endDate + ' to Date. ' + e.message); + } + } + } + } + else { + // We only want to run 1x + options.freq = RRule.DAILY; + options.interval = 1; + options.count = 1; + } + return new RRule(options); + }; + }]) + + .factory('SetRule', ['AngularScheduler.useTimezone', '_', '$log', '$timezones', '$filter', + function(useTimezone, _, $log, $timezones, $filter) { + return function(rule, scope) { + var set, result = '', i, + setStartDate = false; + + // Search the set of RRule keys for a particular key, returning its value + function getValue(set, key) { + var pair = _.find(set, function(x) { + var k = x.split(/=/)[0].toUpperCase(); + return (k === key); + }); + if (pair) { + return pair.split(/=/)[1].toUpperCase(); + } + return null; + } + + function toWeekDays(days) { + var darray = days.toLowerCase().split(/,/), + match = _.find(scope.weekdays, function(x) { + var warray = (angular.isArray(x.value)) ? x.value : [x.value], + diffA = _.difference(warray, darray), + diffB = _.difference(darray, warray); + return (diffA.length === 0 && diffB.length === 0); + }); + return match; + } + + function setValue(pair, set) { + var key = pair.split(/=/)[0].toUpperCase(), + value = pair.split(/=/)[1], + days, l, j, dt, month, day, timeString; + + if (key === 'NAME') { + //name is not actually part of RRule, but we can handle it just the same + scope.schedulerName = value; + } + + if (key === 'FREQ') { + l = value.toLowerCase(); + scope.schedulerFrequency = _.find(scope.frequencyOptions, function(opt) { + return opt.value === l; + }); + if (!scope.schedulerFrequency || !scope.schedulerFrequency.name) { + result = 'FREQ not found in list of valid options'; + } + } + if (key === 'INTERVAL') { + if (parseInt(value,10)) { + scope.schedulerInterval = parseInt(value,10); + scope.schedulerShowInterval = true; + } + else { + result = 'INTERVAL must contain an integer > 0'; + } + } + if (key === 'BYDAY') { + if (getValue(set, 'FREQ') === 'WEEKLY') { + days = value.split(/,/); + scope.weekDays = []; + for (j=0; j < days.length; j++) { + if (_.contains(['SU','MO','TU','WE','TH','FR','SA'], days[j])) { + scope.weekDays.push(days[j].toLowerCase()); + scope['weekDay' + days[j].toUpperCase() + 'Class'] = 'active'; //activate related button + } + else { + result = 'BYDAY contains unrecognized day value(s)'; + } + } + } + else if (getValue(set, 'FREQ') === 'MONTHLY') { + scope.monthlyRepeatOption = 'other'; + scope.monthlyWeekDay = toWeekDays(value); + if (!scope.monthlyWeekDay) { + result = 'BYDAY contains unrecognized day value(s)'; + } + } + else { + scope.yearlyRepeatOption = 'other'; + scope.yearlyWeekDay = toWeekDays(value); + if (!scope.yearlyWeekDay) { + result = 'BYDAY contains unrecognized day value(s)'; + } + } + } + if (key === 'BYMONTHDAY') { + if (parseInt(value,10) && parseInt(value,10) > 0 && parseInt(value,10) < 32) { + scope.monthDay = parseInt(value,10); + scope.monhthlyRepeatOption = 'day'; + } + else { + result = 'BYMONTHDAY must contain an integer between 1 and 31'; + } + } + if (key === 'DTSTART') { + // The form has been reset to the local zone + setStartDate = true; + if (/\d{8}T\d{6}Z/.test(value)) { + // date may come in without separators. add them so new Date constructor will work + value = value.replace(/(\d{4})(\d{2})(\d{2}T)(\d{2})(\d{2})(\d{2}Z)/, + function(match, p1, p2, p3, p4,p5,p6) { + return p1 + '-' + p2 + '-' + p3 + p4 + ':' + p5 + ':' + p6; + }); + } + if (useTimezone) { + dt = new Date(value); // date adjusted to local zone automatically + month = $filter('schZeroPad')(dt.getMonth() + 1, 2); + day = $filter('schZeroPad')(dt.getDate(), 2); + scope.schedulerStartDt = dt.getFullYear() + '-' + month + '-' + day; + scope.schedulerStartHour = $filter('schZeroPad')(dt.getHours(),2); + scope.schedulerStartMinute = $filter('schZeroPad')(dt.getMinutes(),2); + scope.schedulerStartSecond = $filter('schZeroPad')(dt.getSeconds(),2); + scope.scheduleTimeChange(); // calc UTC + } + else { + timeString = value.replace(/^.*T/,''); + scope.schedulerStartDt = value.replace(/T.*$/,''); + scope.schedulerStartHour = timeString.substr(0,2); + scope.schedulerStartMinute = timeString.substr(3,2); + scope.schedulerStartMinute = timeString.substr(6,2); + } + scope.scheduleTimeChange(); + } + if (key === 'BYSETPOS') { + if (getValue(set, 'FREQ') === 'YEARLY') { + scope.yearlRepeatOption = 'other'; + scope.yearlyOccurrence = _.find(scope.occurrences, function(x) { + return (x.value === parseInt(value,10)); + }); + if (!scope.yearlyOccurrence || !scope.yearlyOccurrence.name) { + result = 'BYSETPOS was not in the set of 1,2,3,4,-1'; + } + } + else { + scope.monthlyOccurrence = _.find(scope.occurrences, function(x) { + return (x.value === parseInt(value,10)); + }); + if (!scope.monthlyOccurrence || !scope.monthlyOccurrence.name) { + result = 'BYSETPOS was not in the set of 1,2,3,4,-1'; + } + } + } + + if (key === 'COUNT') { + if (parseInt(value,10)) { + scope.schedulerEnd = scope.endOptions[1]; + scope.schedulerOccurrenceCount = parseInt(value,10); + } + else { + result = "COUNT must be a valid integer > 0"; + } + } + + if (key === 'UNTIL') { + if (/\d{8}T\d{6}Z/.test(value)) { + // date may come in without separators. add them so new Date constructor will work + value = value.replace(/(\d{4})(\d{2})(\d{2}T)(\d{2})(\d{2})(\d{2}Z)/, + function(match, p1, p2, p3, p4,p5,p6) { + return p1 + '-' + p2 + '-' + p3 + p4 + ':' + p5 + ':' + p6; + }); + } + scope.schedulerEnd = scope.endOptions[2]; + if (useTimezone) { + dt = new Date(value); // date adjusted to local zone automatically + month = $filter('schZeroPad')(dt.getMonth() + 1, 2); + day = $filter('schZeroPad')(dt.getDate(), 2); + scope.schedulerEndDt = dt.getFullYear() + '-' + month + '-' + day; + } + else { + scope.schedulerEndDt = value.replace(/T.*$/,''); + } + } + + if (key === 'BYMONTH') { + if (getValue(set, 'FREQ') === 'YEARLY' && getValue(set, 'BYDAY')) { + scope.yearlRepeatOption = 'other'; + scope.yearlyOtherMonth = _.find(scope.months, function(x) { + return x.value === parseInt(value,10); + }); + if (!scope.yearlyOtherMonth || !scope.yearlyOtherMonth.name) { + result = 'BYMONTH must be an integer between 1 and 12'; + } + } + else { + scope.yearlyOption = 'month'; + scope.yearlyMonth = _.find(scope.months, function(x) { + return x.value === parseInt(value,10); + }); + if (!scope.yearlyMonth || !scope.yearlyMonth.name) { + result = 'BYMONTH must be an integer between 1 and 12'; + } + } + } + + if (key === 'BYMONTHDAY') { + if (parseInt(value,10)) { + scope.yearlyMonthDay = parseInt(value,10); + } + else { + result = 'BYMONTHDAY must be an integer between 1 and 31'; + } + } + } + + function isValid() { + // Check what was put into scope vars, and see if anything is + // missing or not quite right. + if (scope.schedulerFrequency.name === 'weekly' && scope.weekDays.length === 0) { + result = 'Frequency is weekly, but BYDAYS value is missing.'; + } + if (!setStartDate) { + result = 'Warning: start date was not provided'; + } + } + + if (rule) { + set = rule.split(/;/); + if (angular.isArray(set)) { + for (i=0; i < set.length; i++) { + setValue(set[i], set); + if (result) { + break; + } + } + if (!result) { + isValid(); + } + } + else { + result = 'No rule entered. Provide a valid RRule string.'; + } + } + else { + result = 'No rule entered. Provide a valid RRule string.'; + } + if (result) { + $log.error(result); + } + return result; + }; + }]) + + .factory('SetDefaults', ['$filter', function($filter) { + return function(scope) { + // Set default values + var defaultDate = new Date(), + defaultMonth = $filter('schZeroPad')(defaultDate.getMonth() + 1, 2), + defaultDay = $filter('schZeroPad')(defaultDate.getDate(), 2), + defaultDateStr = defaultDate.getFullYear() + '-' + defaultMonth + '-' + defaultDay; + scope.schedulerName = ''; + scope.weekDays = []; + scope.schedulerStartHour = '00'; + scope.schedulerStartMinute = '00'; + scope.schedulerStartSecond = '00'; + scope.schedulerStartDt = defaultDateStr; + scope.schedulerFrequency = scope.frequencyOptions[0]; + scope.schedulerShowEvery = false; + scope.schedulerEnd = scope.endOptions[0]; + scope.schedulerInterval = 1; + scope.schedulerOccurrenceCount = 1; + scope.monthlyRepeatOption = 'day'; + scope.monthDay = 1; + scope.monthlyOccurrence = scope.occurrences[0]; + scope.monthlyWeekDay = scope.weekdays[0]; + scope.yearlyRepeatOption = 'month'; + scope.yearlyMonth = scope.months[0]; + scope.yearlyMonthDay = 1; + scope.yearlyWeekDay = scope.weekdays[0]; + scope.yearlyOtherMonth = scope.months[0]; + scope.yearlyOccurrence = scope.occurrences[0]; + scope.weekDayMOClass = ''; + scope.weekDayTUClass = ''; + scope.weekDayWEClass = ''; + scope.weekDayTHClass = ''; + scope.weekDayFRClass = ''; + scope.weekDaySAClass = ''; + scope.weekDaySUClass = ''; + }; + }]) + + .factory('LoadLookupValues', [ function() { + return function(scope) { + + scope.frequencyOptions = [ + { name: 'None (run once)', value: 'none', intervalLabel: '' }, + { name: 'Minutely', value: 'minutely', intervalLabel: 'minutes' }, + { name: 'Hourly', value: 'hourly', intervalLabel: 'hours' }, + { name: 'Daily', value: 'daily', intervalLabel: 'days' }, + { name: 'Weekly', value: 'weekly', intervalLabel: 'weeks' }, + { name: 'Monthly', value: 'monthly', intervalLabel: 'months' }, + { name: 'Yearly', value: 'yearly', intervalLabel: 'years' } + ]; + + scope.endOptions = [ + { name: 'Never', value: 'never' }, + { name: 'After', value: 'after' }, + { name: 'On Date', value: 'on' } + ]; + + scope.occurrences = [ + { name: 'first', value: 1 }, + { name: 'second', value: 2 }, + { name: 'third', value: 3 }, + { name: 'fourth', value: 4 }, + { name: 'last', value: -1 } + ]; + + scope.weekdays = [ + { name: 'Sunday', value: 'su' }, + { name: 'Monday', value: 'mo' }, + { name: 'Tueday', value: 'tu' }, + { name: 'Wednesday', value: 'we' }, + { name: 'Thursday', value: 'th' }, + { name: 'Friday', value: 'fr' }, + { name: 'Saturday', value: 'sa' }, + { name: 'Day', value: ['mo', 'tu', 'we', 'th', 'fr', 'sa', 'su'] }, + { name: 'Weekday', value: ['mo', 'tu', 'we', 'th', 'fr'] }, + { name: 'Weekend day', value: ['sa', 'su'] } + ]; + + scope.months = [ + { name: 'January', value: 1 }, + { name: 'February', value: 2 }, + { name: 'March', value: 3 }, + { name: 'April', value: 4 }, + { name: 'May', value: 5 }, + { name: 'June', value: 6 }, + { name: 'July', value: 7 }, + { name: 'August', value: 8 }, + { name: 'September', value: 9 }, + { name: 'October', value: 10 }, + { name: 'November', value: 11 }, + { name: 'December', value: 12 } + ]; + + }; + }]) + + // $filter('afZeroPad')(n, pad) -- or -- {{ n | afZeroPad:pad }} + .filter('schZeroPad', [ function() { + return function (n, pad) { + var str = (Math.pow(10,pad) + '').replace(/^1/,'') + (n + '').trim(); + return str.substr(str.length - pad); + }; + }]) + + .directive('schTooltip', [ function() { + return { + link: function(scope, element, attrs) { + var placement = (attrs.placement) ? attrs.placement : 'top'; + $(element).tooltip({ + html: true, + placement: placement, + title: attrs.afTooltip, + trigger: 'hover', + container: 'body' + }); + } + }; + }]) + + .directive('schDatePicker', [ function() { + return { + require: 'ngModel', + link: function(scope, element, attrs) { + var options = {}, + variable = attrs.ngModel, + defaultDate = new Date(); + options.dateFormat = attrs.dateFormat || 'yy-mm-dd'; + options.defaultDate = scope[variable]; + options.minDate = (attrs.minToday) ? defaultDate : null; + options.maxDate = (attrs.maxDate) ? new Date(attrs('maxDate')) : null; + options.changeMonth = (attrs.changeMonth === "false") ? false : true; + options.changeYear = (attrs.changeYear === "false") ? false : true; + $(element).datepicker(options); + } + }; + }]) + + // Custom directives + .directive('schSpinner', ['$filter', function($filter) { + return { + require: 'ngModel', + link: function(scope, element, attr, ctrl) { + // Add jquerui spinner to 'spinner' type input + var form = attr.schSpinner, + zeroPad = attr.zeroPad; + $(element).spinner({ + stop: function() { + if (zeroPad) { + scope[attr.ngModel] = $filter('schZeroPad')($(this).val(),zeroPad); + $(this).val(scope[attr.ngModel]); + } + else { + scope[attr.ngModel] = $(this).spinner('value'); + } + if (attr.ngChange) { + scope.$apply(scope[attr.ngChange]); + } + }, + spin: function() { + scope[form].$setDirty(); + ctrl.$dirty = true; + ctrl.$pristine = false; + if (!scope.$$phase) { + scope.$digest(); + } + } + }); + } + }; + }]); diff --git a/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.min.css b/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.min.css new file mode 100644 index 0000000000..b8e12ff829 --- /dev/null +++ b/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.min.css @@ -0,0 +1 @@ +.ui-widget input{font-size:12px;font-weight:400;text-align:center}.ui-spinner.ui-widget-content{border-bottom-color:#ccc;border-top-color:#ccc;border-left-color:#ccc;border-right-color:#ccc}.ui-spinner-button{border-left-color:#ccc;border-left-style:solid;border-left-width:1px}.scheduler-time-spinner{width:40px;height:24px}.scheduler-spinner{width:50px;height:24px}.fmt-help{font-size:12px;font-weight:400;color:#999;padding-left:10px}.error{color:#dd1b16;font-size:12px;margin-bottom:0;margin-top:0;padding-top:3px}.pull-up{margin-top:-15px;margin-bottom:10px}.red-text{color:#dd1b16}input.ng-dirty.ng-invalid,select.ng-dirty.ng-invalid,textarea.ng-dirty.ng-invalid{border:1px solid red;outline:0}.help-text{font-size:12px;font-weight:400;color:#999;margin-top:5px}.inline-label{margin-left:10px}#scheduler-buttons{margin-top:20px}.no-label{padding-top:25px}.padding-top-slim{padding-top:5px}.option-pad-left{padding-left:15px}.option-pad-top{padding-top:15px}.option-pad-bottom{padding-bottom:15px}#monthlyOccurrence,#monthlyWeekDay{margin-top:5px}select{width:100%} \ No newline at end of file diff --git a/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.min.js b/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.min.js new file mode 100644 index 0000000000..d4c0e90a37 --- /dev/null +++ b/awx/ui/static/lib/angular-scheduler/lib/angular-scheduler.min.js @@ -0,0 +1 @@ +/*! angular-schedule.js - v0.0.1 - 2014-02-26 */"use strict";angular.module("AngularScheduler",["Timezones"]).constant("$timezones.definitions.location","/bower_components/angular-timezones/tz/data").constant("scheduler_partial","/lib/angular-scheduler.html").factory("SchedulerInit",["$filter","$timezones","LoadLookupValues","SetDefaults","CreateObject",function(a,b,c,d,e){return function(a){var f=a.scope;return f.removeZonesReady&&f.removeZonesReady(),f.removeZonesReady=f.$on("zonesReady",function(){var a;if(f.timeZones=JSON.parse(localStorage.zones),f.current_timezone=b.getLocal(),!$.isEmptyObject(f.current_timezone)&&f.current_timezone.name)for(a=0;a=0?f.weekDays.splice(a,1):f.weekDays.push(a)},f.startDateError=function(a){f.scheduler_form&&(f.scheduler_form_schedulerStartDt_error=a,f.scheduler_form.schedulerStartDt.$pristine=!1,f.scheduler_form.schedulerStartDt.$dirty=!0,$("#schedulerStartDt").removeClass("ng-pristine").removeClass("ng-valid").removeClass("ng-valid-custom-error").addClass("ng-dirty").addClass("ng-invalid").addClass("ng-invalid-custom-error"))},f.resetStartDate=function(){f.scheduler_form&&(f.scheduler_form_schedulerStartDt_error="",f.scheduler_form.schedulerStartDt.$setValidity("custom-error",!0),f.scheduler_form.schedulerStartDt.$setPristine())},c(f),d(f),f.scheduleTimeChange(),e(f)}}]).factory("CreateObject",["$filter","GetRule","Inject","SetDefaults","$timezones",function(a,b,c,d,e){return function(f){var g=function(){this.scope=f,this.getOptions=function(){var a={};return a.startDate=this.scope.schedulerUTCTime,a.frequency=this.scope.schedulerFrequency.value,a.interval=this.scope.schedulerInterval,"after"===this.scope.schedulerEnd.value&&(a.occurrenceCount=this.scope.schedulerOccurrenceCount),"on"===this.scope.schedulerEnd.value&&(a.endDate=this.scope.schedulerEndDt),"weekly"===this.scope.schedulerFrequency.value?a.weekDays=this.scope.weekDays:"yearly"===this.scope.schedulerFrequency.value?"month"===this.scope.yearlyRepeatOption?(a.month=this.scope.yearlyMonth.value,a.monthDay=this.scope.yearlyMonthDay):(a.setOccurrence=this.scope.yearlyOccurrence.value,a.weekDays=this.scope.yearlyWeekDay.value,a.month=this.scope.yearlyOtherMonth.value):"monthly"===this.scope.schedulerFrequency.value&&("day"===this.scope.monthlyRepeatOption?a.monthDay=this.scope.monthDay:(a.setOccurrence=this.scope.monthlyOccurrence.value,a.weekDays=this.scope.monthlyWeekDay.value)),a},this.clearErrors=function(){this.scope.scheduler_weekDays_error=!1,this.scope.scheduler_endDt_error=!1,this.scope.resetStartDate(),this.scope.scheduler_endDt_error=!1,this.scope.scheduler_form.schedulerEndDt.$setValidity("custom-error",!0),this.scope.scheduler_form.schedulerEndDt.$setPristine(),this.scope.scheduler_form.$setPristine()},this.isValid=function(){var b,c,d,g,h=!0;return this.clearErrors(),"weekly"===this.scope.schedulerFrequency.value&&0===f.weekDays.length&&(this.scope.scheduler_weekDays_error=!0,h=!1),this.scope.scheduler_form.scheduleName.$valid||(this.scope.scheduler_form.scheduleName.$dirty=!0,$("#scheduleName").addClass("ng-dirty"),h=!1),"on"===this.scope.schedulerEnd.value&&(/^\d{4}-\d{2}-\d{2}$/.test(this.scope.schedulerEndDt)||(this.scope.scheduler_form.schedulerEndDt.$pristine=!1,this.scope.scheduler_form.schedulerEndDt.$dirty=!0,$("#schedulerEndDt").removeClass("ng-pristine").removeClass("ng-valid").removeClass("ng-valid-custom-error").addClass("ng-dirty").addClass("ng-invalid").addClass("ng-invalid-custom-error"),this.scope.scheduler_endDt_error=!0,h=!1)),this.scope.schedulerUTCTime?(b=new Date(this.scope.schedulerUTCTime),c=new Date,d=c.getFullYear()+"-"+a("schZeroPad")(c.getMonth()+1,2)+"-"+a("schZeroPad")(c.getDate(),2)+"T"+a("schZeroPad")(c.getHours(),2)+":"+a("schZeroPad")(c.getMinutes(),2)+":"+a("schZeroPad")(c.getSeconds(),2)+".000Z",g=e.toUTC(d,this.scope.schedulerTimeZone.name),g.getTime()>=b.getTime()&&(h=!1,this.scope.startDateError("Start date and time must be in the future"))):(f.startDateError("Provide a valid start date and time"),h=!1),h},this.getRule=function(){var a=this.getOptions();return b(a)},this.getValue=function(){var a=this.getRule(),b=this.getOptions();return{name:f.scheduleName,rrule:a.toString(),options:b}},this.inject=function(a,b){return c({scope:this.scope,target:a,buttons:b})},this.clear=function(){this.clearErrors(),this.scope.scheduler_form.scheduleName.$setPristine(),d(this.scope)}};return new g}}]).factory("Inject",["scheduler_partial","$compile","$http","$log",function(a,b,c,d){return function(e){var f=e.scope,g=e.target,h=e.buttons;f.removeHtmlReady&&f.removeHtmlReady(),f.removeHtmlReady=f.$on("htmlReady",function(a,c){var d=angular.isObject(g)?g:angular.element(document.getElementById(g));d.html(c),b(d)(f),h&&$("#scheduler-buttons").show()}),c({method:"GET",url:a}).success(function(a){f.$emit("htmlReady",a)}).error(function(b,c){d.error("Error calling "+a+". "+c)})}}]).factory("GetRule",["$log",function(a){return function(b){var c,d=b.startDate,e=b.frequency,f=b.interval,g=b.occurrenceCount,h=b.endDate,i=b.month,j=b.monthDay,k=b.weekDays,l=b.setOccurrence,m={};if(angular.isDate(d))m.dtstart=d;else try{m.dtstart=new Date(d)}catch(n){a.error("Date conversion failed. Attempted to convert "+d+" to Date. "+n.message)}if(e&&"none"!==e){if(m.freq=RRule[e.toUpperCase()],m.interval=f,k&&"string"==typeof k&&(m.byweekday=RRule[k.toUpperCase()]),k&&angular.isArray(k))for(m.byweekday=[],c=0;c', '>'). + replace('"', '"'); +} + +function createServlet(Class) { + var servlet = new Class(); + return servlet.handleRequest.bind(servlet); +} + +/** + * An Http server implementation that uses a map of methods to decide + * action routing. + * + * @param {Object} Map of method => Handler function + */ +function HttpServer(handlers) { + this.handlers = handlers; + this.server = http.createServer(this.handleRequest_.bind(this)); +} + +HttpServer.prototype.start = function(port) { + this.port = port; + this.server.listen(port); + util.puts('Http Server running at http://localhost:' + port + '/'); +}; + +HttpServer.prototype.parseUrl_ = function(urlString) { + var parsed = url.parse(urlString); + parsed.pathname = url.resolve('/', parsed.pathname); + return url.parse(url.format(parsed), true); +}; + +HttpServer.prototype.handleRequest_ = function(req, res) { + var logEntry = req.method + ' ' + req.url; + if (req.headers['user-agent']) { + logEntry += ' ' + req.headers['user-agent']; + } + util.puts(logEntry); + req.url = this.parseUrl_(req.url); + var handler = this.handlers[req.method]; + if (!handler) { + res.writeHead(501); + res.end(); + } else { + handler.call(this, req, res); + } +}; + +/** + * Handles static content. + */ +function StaticServlet() {} + +StaticServlet.MimeMap = { + 'txt': 'text/plain', + 'html': 'text/html', + 'css': 'text/css', + 'xml': 'application/xml', + 'json': 'application/json', + 'js': 'application/javascript', + 'jpg': 'image/jpeg', + 'jpeg': 'image/jpeg', + 'gif': 'image/gif', + 'png': 'image/png', +  'svg': 'image/svg+xml' +}; + +StaticServlet.prototype.handleRequest = function(req, res) { + var self = this; + var path = ('./' + req.url.pathname).replace('//','/').replace(/%(..)/g, function(match, hex){ + return String.fromCharCode(parseInt(hex, 16)); + }); + var parts = path.split('/'); + if (parts[parts.length-1].charAt(0) === '.') + return self.sendForbidden_(req, res, path); + fs.stat(path, function(err, stat) { + if (err) + return self.sendMissing_(req, res, path); + if (stat.isDirectory()) + return self.sendDirectory_(req, res, path); + return self.sendFile_(req, res, path); + }); +} + +StaticServlet.prototype.sendError_ = function(req, res, error) { + res.writeHead(500, { + 'Content-Type': 'text/html' + }); + res.write('\n'); + res.write('Internal Server Error\n'); + res.write('

Internal Server Error

'); + res.write('
' + escapeHtml(util.inspect(error)) + '
'); + util.puts('500 Internal Server Error'); + util.puts(util.inspect(error)); +}; + +StaticServlet.prototype.sendMissing_ = function(req, res, path) { + path = path.substring(1); + res.writeHead(404, { + 'Content-Type': 'text/html' + }); + res.write('\n'); + res.write('404 Not Found\n'); + res.write('

Not Found

'); + res.write( + '

The requested URL ' + + escapeHtml(path) + + ' was not found on this server.

' + ); + res.end(); + util.puts('404 Not Found: ' + path); +}; + +StaticServlet.prototype.sendForbidden_ = function(req, res, path) { + path = path.substring(1); + res.writeHead(403, { + 'Content-Type': 'text/html' + }); + res.write('\n'); + res.write('403 Forbidden\n'); + res.write('

Forbidden

'); + res.write( + '

You do not have permission to access ' + + escapeHtml(path) + ' on this server.

' + ); + res.end(); + util.puts('403 Forbidden: ' + path); +}; + +StaticServlet.prototype.sendRedirect_ = function(req, res, redirectUrl) { + res.writeHead(301, { + 'Content-Type': 'text/html', + 'Location': redirectUrl + }); + res.write('\n'); + res.write('301 Moved Permanently\n'); + res.write('

Moved Permanently

'); + res.write( + '

The document has moved here.

' + ); + res.end(); + util.puts('301 Moved Permanently: ' + redirectUrl); +}; + +StaticServlet.prototype.sendFile_ = function(req, res, path) { + var self = this; + var file = fs.createReadStream(path); + res.writeHead(200, { + 'Content-Type': StaticServlet. + MimeMap[path.split('.').pop()] || 'text/plain' + }); + if (req.method === 'HEAD') { + res.end(); + } else { + file.on('data', res.write.bind(res)); + file.on('close', function() { + res.end(); + }); + file.on('error', function(error) { + self.sendError_(req, res, error); + }); + } +}; + +StaticServlet.prototype.sendDirectory_ = function(req, res, path) { + var self = this; + if (path.match(/[^\/]$/)) { + req.url.pathname += '/'; + var redirectUrl = url.format(url.parse(url.format(req.url))); + return self.sendRedirect_(req, res, redirectUrl); + } + fs.readdir(path, function(err, files) { + if (err) + return self.sendError_(req, res, error); + + if (!files.length) + return self.writeDirectoryIndex_(req, res, path, []); + + var remaining = files.length; + files.forEach(function(fileName, index) { + fs.stat(path + '/' + fileName, function(err, stat) { + if (err) + return self.sendError_(req, res, err); + if (stat.isDirectory()) { + files[index] = fileName + '/'; + } + if (!(--remaining)) + return self.writeDirectoryIndex_(req, res, path, files); + }); + }); + }); +}; + +StaticServlet.prototype.writeDirectoryIndex_ = function(req, res, path, files) { + path = path.substring(1); + res.writeHead(200, { + 'Content-Type': 'text/html' + }); + if (req.method === 'HEAD') { + res.end(); + return; + } + res.write('\n'); + res.write('' + escapeHtml(path) + '\n'); + res.write('\n'); + res.write('

Directory: ' + escapeHtml(path) + '

'); + res.write('
    '); + files.forEach(function(fileName) { + if (fileName.charAt(0) !== '.') { + res.write('
  1. ' + + escapeHtml(fileName) + '
  2. '); + } + }); + res.write('
'); + res.end(); +}; + +// Must be last, +main(process.argv); diff --git a/awx/ui/static/lib/angular-tz-extensions/.bower.json b/awx/ui/static/lib/angular-tz-extensions/.bower.json new file mode 100644 index 0000000000..7eeae678b9 --- /dev/null +++ b/awx/ui/static/lib/angular-tz-extensions/.bower.json @@ -0,0 +1,46 @@ +{ + "name": "angular-tz-extensions", + "version": "0.3.9", + "main": "js/angular-timezones.js", + "ignore": [ + ".bowerrc", + ".idea", + ".gitignore", + ".travis.yml", + "index.html", + "js/demo.js", + "package.json", + "test", + "**/.*", + "node_modules", + "bower_components", + "tests" + ], + "dependencies": { + "angular": "*", + "jquery": "*", + "angular-filters": "*", + "timezone-js": "git@github.com:mde/timezone-js.git#v0.4.4" + }, + "homepage": "https://github.com/chouseknecht/angular-tz-extensions", + "description": "Add timezone information to a js date object, get local browser timezone info, and get a list of available timezones from the iana tz database.", + "keywords": [ + "timezone", + "date", + "iana", + "tzdata" + ], + "authors": [ + "Chris Houseknecht" + ], + "license": "MIT", + "_release": "0.3.9", + "_resolution": { + "type": "version", + "tag": "0.3.9", + "commit": "dded062e72274e2fc5379bb251c476d152ecc1a1" + }, + "_source": "git://github.com/chouseknecht/angular-tz-extensions.git", + "_target": "*", + "_originalSource": "angular-tz-extensions" +} \ No newline at end of file diff --git a/awx/ui/static/lib/angular-tz-extensions/Gruntfile.js b/awx/ui/static/lib/angular-tz-extensions/Gruntfile.js new file mode 100644 index 0000000000..df7e5bc8cf --- /dev/null +++ b/awx/ui/static/lib/angular-tz-extensions/Gruntfile.js @@ -0,0 +1,32 @@ +module.exports = function(grunt) { + + grunt.initConfig({ + + pkg: grunt.file.readJSON('./package.json'), + + jshint: { + options: { + jshintrc: '.jshintrc' + }, + uses_defaults: ['lib/angular-tz-extensions.js'] + }, + + uglify: { + options: { + banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' + + '<%= grunt.template.today("yyyy-mm-dd") %> */' + }, + my_target: { + files: { + 'lib/angular-tz-extensions.min.js': ['lib/angular-tz-extensions.js'] + } + } + } + + }); + + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + + grunt.registerTask('default', ['jshint', 'uglify']); +} diff --git a/awx/ui/static/lib/angular-tz-extensions/LICENSE.md b/awx/ui/static/lib/angular-tz-extensions/LICENSE.md new file mode 100644 index 0000000000..8877abd126 --- /dev/null +++ b/awx/ui/static/lib/angular-tz-extensions/LICENSE.md @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Michael Ahlers + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/awx/ui/static/lib/angular-tz-extensions/README.md b/awx/ui/static/lib/angular-tz-extensions/README.md new file mode 100644 index 0000000000..205c275740 --- /dev/null +++ b/awx/ui/static/lib/angular-tz-extensions/README.md @@ -0,0 +1,137 @@ +# Angular TZ Extensions + +Javascript is good at creating dates in the local timezone, and it provides a reasonable set of methods for returning date and time information within the local timezone and UTC. But what if you want a date object aligned to a timezone other than the local one? What if you need to present the user with a list of timezone choices? What if you need to know the offset or abbreviation for a particular timezone? Angular TZ Extensions provides the solution. + +Originally forked from https://github.com/michaelahlers/angular-timezones. +Depends on https://github.com/mde/timezone-js, http://pellepim.bitbucket.org/jstz/ and [AngularJS](http://angularjs.org). + +## Install + +Install using [Bower](https://github.com/bower/bower): + + bower install angular-tz-extensions + +Once installed include the follwing scripts in your app: + + + + +If you want to detect the local timezone, include the jstimezonedetect. You can use the package found in this repo: + + + +Or, pull it from a CDN: + + + +## Usage + +After including `angular-timezones.js`, add this package to your application. + + var yourApplication = angular.module('your-application', ['Timezones']) + +### Configuration + +This package provides the [IANA timezone data](http://iana.org/time-zones), but you may have this resource served from a different location or you may wish to provide your own data. To change that location, set the `$timezones.definitions.location` property to the appropriate path or URL. + + yourApplication.constant('$timezones.definitions.location', '/custom/path/to/tz/data') + +This is done by the unit tests and illustrated in the included sample app (see Examples below). + +### Align date to a given timezone + +Use `$timezones.align(timezone, date)` to align a date object to a timezone represeneted as an Olsan timezone string value. The getFullYear, getMonth, getDate, getHours, getMinutes, getSeconds and getTimezone methods of the returned date object will present values in the requested timezone. + +Below is an example comparing a date object aligned to the local timezone (America/New_York) with a date object created using the align method a timezone of 'America/Los_Angeles': + + var rightNow = new Date(); + console.log(rightNow.getTimezoneOffset()); + console.log(rightNow.getHours()); + console.log($filter('date')(rightNow,"yyyy-MM-dd HH:mm:ss Z")); + + var test = $timezones.align(rightNow, 'America/Los_Angeles'); + console.log(test.timezone); + console.log(test.getTimezoneOffset()); + console.log(test.getHours()); + console.log($filter('date')(test,"yyyy-MM-dd HH:mm:ss Z")); + +Results in: + + 300 + 14 + 2014-03-03 14:40:33 -0500 + + America/Los_Angeles + 480 + 11 + 2014-03-03 11:40:33 -0800 + +Note that TimezoneJS (timezone-js/src/date.js) adds additional properties and methods to the date object. Here we're accessing the timezone property. There is also a getTimezoneInfo() method. See TimezoneJS documentation for more details. + +Alignment can also be accomplished at the view level using the provided tzAlign filter: + + {{ someDate|tzAlign:'America/Los_Angeles'|date:"yyyy-MM-dd HH:mm:ss Z" }} + +### Resolve a timezone + +The `$timezones.resolve(timezone, reference)` function will, using the reference `Date` provided, look up complete details about the timezone—including the abbreviation, offset, and decomposed region and locality. This is useful for avoiding clever tricks to extract abbreviations from `Date.toString` (which is not particularly portable or robust). Additionally, resulting values are derived from the authoritative IANA timezone data. + + var scope.timezone = $timezone.resolve('America/New_York', new Date()); + console.log(scope.timezone); + +Returns: + + { + abbreviation: 'EST', + locality: 'New York', + name: 'America/New_York', + offset: 300, + region: 'America' + } + +### Detect local timezone + +If [jsTimezoneDetect](https://bitbucket.org/pellepim/jstimezonedetect) is included, the `$timezones.getLocal()` function will detect the browser's local timezone and provide a complete definition that's resolved against the IANA database. For convenience, jsTimezoneDetect is included in packages/jstimezonedetect. You may want to pull the latest version in from bitbucket. + + + +### Get a list of available timezones + +You can retrieve an array of all available timezones- perfect for populating a select element. Use the `$timezone.getZoneList($scope)` method, passing in a scope instance. The method reads the zone.tab tab file, which is part of tzdata. When the data is ready, the method emits 'zonesReady'. Retrieve the data inside `$scope.$on('zonesReady', callback)`. The data will be available in local storage and can be accessed using: `JSON.parse(localStorage.zones)`. Here's an example taken from the included sample app: + + if ($scope.removeZonesReady) { + $scope.removeZonesReady(); + } + $scope.removeZonesReady = $scope.$on('zonesReady', function() { + var i; + $scope.zones = JSON.parse(localStorage.zones); + $scope.current_timezone = $timezones.getLocal(); + for (i=0; i < $scope.zones.length; i++) { + if ($scope.zones[i].name === $scope.current_timezone.name) { + $scope.selectedZone = $scope.zones[i]; + break; + } + } + }); + + $timezones.getZoneList($scope); + +## Examples + +A sample application is included. Run it locally using [Node](http://nodejs.org): + + node ./scripts/web-server.js + +Once running, point your browser to http://localhost:8000/app/filters.html + +## Developers + +_Timezones for Angular_ is tested with [Karma](http://karma-runner.github.io/) and [PhantomJS](http://phantomjs.org/) + +With [NPM](http://npmjs.com/) installed, you can test your modifications with the following. + + npm install + npm test + +To run the tests you will need to have phantomjs in your PATH. Install it globally using `npm install -g phantomjs` or manually add it to your path using something like `export PATH=$PATH:./node_modules/phantomjs/bin/phantomjs` + diff --git a/awx/ui/static/lib/angular-tz-extensions/app/filters.html b/awx/ui/static/lib/angular-tz-extensions/app/filters.html new file mode 100644 index 0000000000..11cdcf77a2 --- /dev/null +++ b/awx/ui/static/lib/angular-tz-extensions/app/filters.html @@ -0,0 +1,92 @@ + + + + + + Filters - Timezones for AngularJS + + + + + + + + + + + + + + + + +
+ +

Available Time Zones

+ + + + + + + + + + + + + + + + + + + + + + +
AbbreviationLocalityNameOffsetRegion
{{ current_timezone.abbreviation }}{{ current_timezone.locality }}{{ current_timezone.name }}{{ current_timezone.offset }}{{ current_timezone.region }}
+ +
+

Filters

+ +

tzDate

+ +

+ The local time, {{now|date:"yyyy-MM-dd HH:mm:ss Z"}}, shown around the world. +

+ + + + + + + + + + + + + + +
TimezoneTime
{{example.timezone}}{{example.reference|tzAlign:example.timezone|date:"yyyy-MM-dd HH:mm:ss Z"}}
+
+ +
+ + + + diff --git a/awx/ui/static/lib/angular-tz-extensions/app/js/filters.js b/awx/ui/static/lib/angular-tz-extensions/app/js/filters.js new file mode 100644 index 0000000000..72afc97ee8 --- /dev/null +++ b/awx/ui/static/lib/angular-tz-extensions/app/js/filters.js @@ -0,0 +1,63 @@ +(function (angular) { + + var application = angular.module('application', ['Timezones']); + + application.constant('$timezones.definitions.location', '/tz/data'); + + application.controller('World', ['$scope', '$timezones', '$filter', + function ($scope, $timezones, $filter) { + + var now = $scope.now = Date.now(); + + if ($scope.removeZonesReady) { + $scope.removeZonesReady(); + } + $scope.removeZonesReady = $scope.$on('zonesReady', function() { + var i; + $scope.zones = JSON.parse(localStorage.zones); + $scope.current_timezone = $timezones.getLocal(); + for (i=0; i < $scope.zones.length; i++) { + if ($scope.zones[i].name === $scope.current_timezone.name) { + $scope.selectedZone = $scope.zones[i]; + break; + } + } + }); + + $scope.zoneChange = function() { + var date = new Date(); + $scope.current_timezone = $timezones.resolve($scope.selectedZone.name, date); + }; + + $timezones.getZoneList($scope); + + $scope.examples = [{ + timezone: 'Pacific/Honolulu', + reference: now + }, { + timezone: 'America/Los_Angeles', + reference: now + }, { + timezone: 'America/Chicago', + reference: now + }, { + timezone: 'America/New_York', + reference: now + }, { + timezone: 'Europe/Berlin', + reference: now + }, { + timezone: 'Asia/Tokyo', + reference: now + }, { + timezone: 'Australia/Sydney', + reference: now + }, { + timezone: 'Etc/GMT+12', + reference: now + }]; + + } + ]); + +})(angular); diff --git a/awx/ui/static/lib/angular-tz-extensions/bower.json b/awx/ui/static/lib/angular-tz-extensions/bower.json new file mode 100644 index 0000000000..980b6e49d0 --- /dev/null +++ b/awx/ui/static/lib/angular-tz-extensions/bower.json @@ -0,0 +1,37 @@ +{ + "name": "angular-tz-extensions", + "version": "0.3.9", + "main": "js/angular-timezones.js", + "ignore": [ + ".bowerrc", + ".idea", + ".gitignore", + ".travis.yml", + "index.html", + "js/demo.js", + "package.json", + "test", + "**/.*", + "node_modules", + "bower_components", + "tests" + ], + "dependencies": { + "angular": "*", + "jquery": "*", + "angular-filters": "*", + "timezone-js": "git@github.com:mde/timezone-js.git#v0.4.4" + }, + "homepage": "https://github.com/chouseknecht/angular-tz-extensions", + "description": "Add timezone information to a js date object, get local browser timezone info, and get a list of available timezones from the iana tz database.", + "keywords": [ + "timezone", + "date", + "iana", + "tzdata" + ], + "authors": [ + "Chris Houseknecht" + ], + "license": "MIT" +} diff --git a/awx/ui/static/lib/angular-tz-extensions/lib/angular-tz-extensions.js b/awx/ui/static/lib/angular-tz-extensions/lib/angular-tz-extensions.js new file mode 100644 index 0000000000..03b2b76023 --- /dev/null +++ b/awx/ui/static/lib/angular-tz-extensions/lib/angular-tz-extensions.js @@ -0,0 +1,283 @@ +/** + * angular-tz-extensions.js + * + * Copyright (c) 2014 Ansible, Inc. + * + * Distributed under The MIT License (MIT). + * + */ + +(function (root) { + + var angular = root.angular, + timezoneJS = root.timezoneJS, + jstz = root.jstz, + + toExtendedNative = function (wrapped) { + /* Tricks the isDate method in Angular into treating these objects like it + * would any other Date. May be horribly slow. */ + var key, native = new Date(); + for (key in wrapped) { + native[key] = wrapped[key]; + } + return native; + }, + + module = angular.module('Timezones', []); + + module.config(function () { + timezoneJS.fromLocalString = function (str, tz) { + // https://github.com/csnover/js-iso8601/blob/master/iso8601.js – MIT license + + //var minutesOffset = 0, + var struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(str), + numericKeys = [1, 4, 5, 6, 7, 10, 11], + i, k; + // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC + for (i = 0;(k = numericKeys[i]); ++i) { + struct[k] = +struct[k] || 0; + } + + // allow undefined days and months + struct[2] = (+struct[2] || 1) - 1; + struct[3] = +struct[3] || 1; + + return toExtendedNative(new timezoneJS.Date(struct[1], struct[2], struct[3], struct[4], struct[5], struct[6], struct[7], tz)); + }; + }); + + module.constant('$timezones.definitions.location', '/tz/data'); + + module.run(['$timezones.definitions.location', + function (location) { + timezoneJS.timezone.zoneFileBasePath = location; + timezoneJS.timezone.init({ async: false }); + } + ]); + + module.factory('$timezones',['$log', '$http', '$timezones.definitions.location', function ($log, $http, location) { + + var resolve = function (timezone, reference) { + var name, result; + + if ('number' === typeof (reference)) { + reference = new Date(reference); + } + + /* + * TODO: Support resolution without reference dates. + * + * For now, we must use reference dates. There's just not enough time + * to write and test code that would resolve all possible definitions + * for any given timezone. Hopefully the TimezoneJS folks will support + * that some day. + */ + + if (!angular.isDate(reference)) { + throw { + name : 'DateObjectExpected', + message : 'Expected a Date object; got "' + reference + '".' + }; + } + + + /* This is not terribly efficient, but necessary because some timezone + * specifics (like the abbreviation and offset) are temporal. */ + reference = new timezoneJS.Date(reference, timezone); + + name = reference.getTimezone(); + + result = { + name: name, + abbreviation: reference.getTimezoneAbbreviation(), + offset: reference.getTimezoneOffset(), + region: name.split('/')[0], + locality: name.split('/')[1].replace('_', ' ') + }; + + return result; + }; + + return { + + /** + * Aligns the provided Date object to the specified timezone. + * + * @param date + * Reference date. + * + * @param timezone + * An Olson name (e.g., America/New_York), or a timezone object + * (produced by the resolve function). + * + * @returns {*} A Date "aligned" to the desired timezone. + */ + align: function (date, timezone, silent) { + if (!angular.isDate(date)) { + throw { + name : 'DateObjectExpected', + message : 'Expected a Date object; got "' + date + '".' + }; + } + + // Lining up code with tests. If a bogus timezone is passed in and mode is silent, don't + // throw an error, return a date. + try { + if (angular.isObject(timezone) && timezone.name) { + return toExtendedNative(new timezoneJS.Date(date, timezone.name)); + } + + if (angular.isString(timezone)) { + return toExtendedNative(new timezoneJS.Date(date, timezone)); + } + } + catch(e) { + if (true === silent) { + return date; + } + else { + throw new Error('The timezone argument must either be an Olson name (e.g., America/New_York), ' + + 'or a timezone object (produced by the resolve function) bearing an Olson name on the name property.'); + } + } + }, + + /** + * Generate an object that defines the timezone. + * + * @param timezone + * An Olson name (e.g., America/New_York) to resolve. + * + * @param reference + * A reference date used to determine values for temporal timezone + * properties like the offset and abbreviation (which vary between + * standard and daylight times). + * + * @returns {{name: string, abbreviation: string, offset: number, region: string, locality: string}} + */ + resolve: resolve, + + /** + * If the jsTimezoneDetect library is available, use it to make an + * approximate guess at the current timezone Olson name. From there, + * perform resolution as usual (which implicitly gets the authoritative + * definitions from the IANA database). + */ + getLocal: function () { + var name, now; + + if ('undefined' === typeof(jstz) || 'function' !== typeof(jstz.determine)) { + throw { + name : 'JSTZLibraryMissing', + message : 'The jsTimezoneDetect library, available at https://bitbucket.org/pellepim/jstimezonedetect, is required to detect the local timezone.' + }; + } + + name = jstz.determine().name(); + now = new Date(); + return resolve(name, now); + }, + + /** + * Given a date object or date string (in UTC format) and an Olson name, align the date object + * and add the offset minutes to the datetime value. The getUTC*(), toUTString() and getTime() + * methods on the resulting date object will return values that include the timezone offset + * minutes. + * + * Note: Don't pass in the result of new Date(), as it automatically adjusts the time to the + * local timezone. Pass in a string or object that has NOT already been adjusted or set relative + * to a specific zone. + */ + toUTC: function(dt, tz) { + var dateObj = (angular.isDate(dt)) ? dt : new Date(dt), + dateStr, tzDate; + // Make sure the date we're using is not already adjusted to the local + // timezone + dateStr = dateObj.getUTCFullYear() + '-' + + ('00' + (dateObj.getUTCMonth() + 1)).substr(-2,2) + '-' + + ('00' + dateObj.getUTCDate()).substr(-2,2) + 'T' + + ('00' + dateObj.getUTCHours()).substr(-2,2) + ':' + + ('00' + dateObj.getUTCMinutes()).substr(-2,2) + ':' + + ('00' + dateObj.getUTCSeconds()).substr(-2,2) + '.000Z'; + tzDate = this.align(new Date(dateStr), tz); + return new Date(tzDate.getTime() + (tzDate.getTimezoneOffset() * 60000)); + }, + + /** + * Reads the zone.tab file and builds an array of objects: { name: }. + * The array contains an object for every Olsan name. Use the array for populating + *
@@ -799,8 +830,8 @@ function isLeafNode (node) { $scope.reset(); } - - + + */ function copy(source, destination){ if (isWindow(source) || isScope(source)) { @@ -864,6 +895,7 @@ function shallowCopy(src, dst) { /** * @ngdoc function * @name angular.equals + * @module ng * @function * * @description @@ -950,6 +982,7 @@ function sliceArgs(args, startIndex) { /** * @ngdoc function * @name angular.bind + * @module ng * @function * * @description @@ -1005,6 +1038,7 @@ function toJsonReplacer(key, value) { /** * @ngdoc function * @name angular.toJson + * @module ng * @function * * @description @@ -1024,13 +1058,14 @@ function toJson(obj, pretty) { /** * @ngdoc function * @name angular.fromJson + * @module ng * @function * * @description * Deserializes a JSON string. * * @param {string} json JSON string to deserialize. - * @returns {Object|Array|Date|string|number} Deserialized thingy. + * @returns {Object|Array|string|number} Deserialized thingy. */ function fromJson(json) { return isString(json) @@ -1097,7 +1132,7 @@ function tryDecodeURIComponent(value) { /** * Parses an escaped url query string into key-value pairs. - * @returns Object.<(string|boolean)> + * @returns {Object.} */ function parseKeyValue(/**string*/keyValue) { var obj = {}, key_value, key; @@ -1179,7 +1214,8 @@ function encodeUriQuery(val, pctEncodeSpaces) { /** * @ngdoc directive - * @name ng.directive:ngApp + * @name ngApp + * @module ng * * @element ANY * @param {angular.Module} ngApp an optional application @@ -1197,7 +1233,7 @@ function encodeUriQuery(val, pctEncodeSpaces) { * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other. * * You can specify an **AngularJS module** to be used as the root module for the application. This - * module will be loaded into the {@link AUTO.$injector} when the application is bootstrapped and + * module will be loaded into the {@link auto.$injector} when the application is bootstrapped and * should contain the application code needed or have dependencies on other modules that will * contain the code. See {@link angular.module} for more information. * @@ -1269,20 +1305,21 @@ function angularInit(element, bootstrap) { /** * @ngdoc function * @name angular.bootstrap + * @module ng * @description * Use this function to manually start up angular application. * * See: {@link guide/bootstrap Bootstrap} * * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually. - * They must use {@link api/ng.directive:ngApp ngApp}. + * They must use {@link ng.directive:ngApp ngApp}. * * @param {Element} element DOM element which is the root of angular application. * @param {Array=} modules an array of modules to load into the application. * Each item in the array should be the name of a predefined module or a (DI annotated) * function that will be invoked by the injector as a run block. * See: {@link angular.module modules} - * @returns {AUTO.$injector} Returns the newly created injector for this app. + * @returns {auto.$injector} Returns the newly created injector for this app. */ function bootstrap(element, modules) { var doBootstrap = function() { @@ -1391,9 +1428,9 @@ function assertNotHasOwnProperty(name, context) { /** * Return the value accessible from the object by path. Any undefined traversals are ignored * @param {Object} obj starting object - * @param {string} path path to traverse - * @param {boolean=true} bindFnToScope - * @returns value as accessible by path + * @param {String} path path to traverse + * @param {boolean} [bindFnToScope=true] + * @returns {Object} value as accessible by path */ //TODO(misko): this function needs to be removed function getter(obj, path, bindFnToScope) { @@ -1418,7 +1455,7 @@ function getter(obj, path, bindFnToScope) { /** * Return the DOM siblings between the first and last node in the given array. * @param {Array} array like object - * @returns jQlite object containing the elements + * @returns {DOMElement} object containing the elements */ function getBlockElements(nodes) { var startNode = nodes[0], @@ -1440,8 +1477,9 @@ function getBlockElements(nodes) { } /** - * @ngdoc interface + * @ngdoc type * @name angular.Module + * @module ng * @description * * Interface for configuring angular {@link angular.module modules}. @@ -1468,6 +1506,7 @@ function setupModuleLoader(window) { /** * @ngdoc function * @name angular.module + * @module ng * @description * * The `angular.module` is a global place for creating, registering and retrieving Angular @@ -1482,9 +1521,9 @@ function setupModuleLoader(window) { * # Module * * A module is a collection of services, directives, filters, and configuration information. - * `angular.module` is used to configure the {@link AUTO.$injector $injector}. + * `angular.module` is used to configure the {@link auto.$injector $injector}. * - *
+     * ```js
      * // Create a new module
      * var myModule = angular.module('myModule', []);
      *
@@ -1496,13 +1535,13 @@ function setupModuleLoader(window) {
      *   // Configure existing providers
      *   $locationProvider.hashPrefix('!');
      * });
-     * 
+ * ``` * * Then you can create an injector and load your modules like this: * - *
-     * var injector = angular.injector(['ng', 'MyModule'])
-     * 
+ * ```js + * var injector = angular.injector(['ng', 'myModule']) + * ``` * * However it's more likely that you'll just use * {@link ng.directive:ngApp ngApp} or @@ -1510,9 +1549,9 @@ function setupModuleLoader(window) { * * @param {!string} name The name of the module to create or retrieve. * @param {Array.=} requires If specified then new module is being created. If - * unspecified then the the module is being retrieved for further configuration. + * unspecified then the module is being retrieved for further configuration. * @param {Function} configFn Optional configuration function for the module. Same as - * {@link angular.Module#methods_config Module#config()}. + * {@link angular.Module#config Module#config()}. * @returns {module} new module with the {@link angular.Module} api. */ return function module(name, requires, configFn) { @@ -1550,7 +1589,7 @@ function setupModuleLoader(window) { /** * @ngdoc property * @name angular.Module#requires - * @propertyOf angular.Module + * @module ng * @returns {Array.} List of module names which must be loaded before this module. * @description * Holds the list of modules which the injector will load before the current module is @@ -1561,7 +1600,7 @@ function setupModuleLoader(window) { /** * @ngdoc property * @name angular.Module#name - * @propertyOf angular.Module + * @module ng * @returns {string} Name of the module. * @description */ @@ -1571,64 +1610,64 @@ function setupModuleLoader(window) { /** * @ngdoc method * @name angular.Module#provider - * @methodOf angular.Module + * @module ng * @param {string} name service name * @param {Function} providerType Construction function for creating new instance of the * service. * @description - * See {@link AUTO.$provide#provider $provide.provider()}. + * See {@link auto.$provide#provider $provide.provider()}. */ provider: invokeLater('$provide', 'provider'), /** * @ngdoc method * @name angular.Module#factory - * @methodOf angular.Module + * @module ng * @param {string} name service name * @param {Function} providerFunction Function for creating new instance of the service. * @description - * See {@link AUTO.$provide#factory $provide.factory()}. + * See {@link auto.$provide#factory $provide.factory()}. */ factory: invokeLater('$provide', 'factory'), /** * @ngdoc method * @name angular.Module#service - * @methodOf angular.Module + * @module ng * @param {string} name service name * @param {Function} constructor A constructor function that will be instantiated. * @description - * See {@link AUTO.$provide#service $provide.service()}. + * See {@link auto.$provide#service $provide.service()}. */ service: invokeLater('$provide', 'service'), /** * @ngdoc method * @name angular.Module#value - * @methodOf angular.Module + * @module ng * @param {string} name service name * @param {*} object Service instance object. * @description - * See {@link AUTO.$provide#value $provide.value()}. + * See {@link auto.$provide#value $provide.value()}. */ value: invokeLater('$provide', 'value'), /** * @ngdoc method * @name angular.Module#constant - * @methodOf angular.Module + * @module ng * @param {string} name constant name * @param {*} object Constant value. * @description * Because the constant are fixed, they get applied before other provide methods. - * See {@link AUTO.$provide#constant $provide.constant()}. + * See {@link auto.$provide#constant $provide.constant()}. */ constant: invokeLater('$provide', 'constant', 'unshift'), /** * @ngdoc method * @name angular.Module#animation - * @methodOf angular.Module + * @module ng * @param {string} name animation name * @param {Function} animationFactory Factory function for creating new instance of an * animation. @@ -1640,7 +1679,7 @@ function setupModuleLoader(window) { * Defines an animation hook that can be later used with * {@link ngAnimate.$animate $animate} service and directives that use this service. * - *
+           * ```js
            * module.animation('.animation-name', function($inject1, $inject2) {
            *   return {
            *     eventName : function(element, done) {
@@ -1652,7 +1691,7 @@ function setupModuleLoader(window) {
            *     }
            *   }
            * })
-           * 
+ * ``` * * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and * {@link ngAnimate ngAnimate module} for more information. @@ -1662,7 +1701,7 @@ function setupModuleLoader(window) { /** * @ngdoc method * @name angular.Module#filter - * @methodOf angular.Module + * @module ng * @param {string} name Filter name. * @param {Function} filterFactory Factory function for creating new instance of filter. * @description @@ -1673,7 +1712,7 @@ function setupModuleLoader(window) { /** * @ngdoc method * @name angular.Module#controller - * @methodOf angular.Module + * @module ng * @param {string|Object} name Controller name, or an object map of controllers where the * keys are the names and the values are the constructors. * @param {Function} constructor Controller constructor function. @@ -1685,20 +1724,20 @@ function setupModuleLoader(window) { /** * @ngdoc method * @name angular.Module#directive - * @methodOf angular.Module + * @module ng * @param {string|Object} name Directive name, or an object map of directives where the * keys are the names and the values are the factories. * @param {Function} directiveFactory Factory function for creating new instance of * directives. * @description - * See {@link ng.$compileProvider#methods_directive $compileProvider.directive()}. + * See {@link ng.$compileProvider#directive $compileProvider.directive()}. */ directive: invokeLater('$compileProvider', 'directive'), /** * @ngdoc method * @name angular.Module#config - * @methodOf angular.Module + * @module ng * @param {Function} configFn Execute this function on module load. Useful for service * configuration. * @description @@ -1709,7 +1748,7 @@ function setupModuleLoader(window) { /** * @ngdoc method * @name angular.Module#run - * @methodOf angular.Module + * @module ng * @param {Function} initializationFn Execute this function after injector creation. * Useful for application initialization. * @description @@ -1749,10 +1788,10 @@ function setupModuleLoader(window) { /* global angularModule: true, version: true, - + $LocaleProvider, $CompileProvider, - + htmlAnchorDirective, inputDirective, inputDirective, @@ -1818,13 +1857,16 @@ function setupModuleLoader(window) { $SnifferProvider, $TemplateCacheProvider, $TimeoutProvider, + $$RAFProvider, + $$AsyncCallbackProvider, $WindowProvider */ /** - * @ngdoc property + * @ngdoc object * @name angular.version + * @module ng * @description * An object that contains information about the current AngularJS version. This object has the * following properties: @@ -1836,11 +1878,11 @@ function setupModuleLoader(window) { * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". */ var version = { - full: '1.2.13', // all of these placeholder strings will be replaced by grunt's + full: '1.2.15-build.2398+sha.4bab3d8', // all of these placeholder strings will be replaced by grunt's major: 1, // package task minor: 2, - dot: 13, - codeName: 'romantic-transclusion' + dot: 15, + codeName: 'snapshot' }; @@ -1956,7 +1998,9 @@ function publishExternalAPI(angular){ $sniffer: $SnifferProvider, $templateCache: $TemplateCacheProvider, $timeout: $TimeoutProvider, - $window: $WindowProvider + $window: $WindowProvider, + $$rAF: $$RAFProvider, + $$asyncCallback : $$AsyncCallbackProvider }); } ]); @@ -1977,6 +2021,7 @@ function publishExternalAPI(angular){ /** * @ngdoc function * @name angular.element + * @module ng * @function * * @description @@ -2047,9 +2092,9 @@ function publishExternalAPI(angular){ * camelCase directive name, then the controller for this directive will be retrieved (e.g. * `'ngModel'`). * - `injector()` - retrieves the injector of the current element or its parent. - * - `scope()` - retrieves the {@link api/ng.$rootScope.Scope scope} of the current + * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current * element or its parent. - * - `isolateScope()` - retrieves an isolate {@link api/ng.$rootScope.Scope scope} if one is attached directly to the + * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the * current element. This getter should be used only on elements that contain a directive which starts a new isolate * scope. Calling `scope()` on this element always returns the original non-isolate scope. * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top @@ -2418,7 +2463,7 @@ forEach({ return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate'); }, - controller: jqLiteController , + controller: jqLiteController, injector: function(element) { return jqLiteInheritedData(element, '$injector'); @@ -2754,7 +2799,7 @@ forEach({ }, contents: function(element) { - return element.childNodes || []; + return element.contentDocument || element.childNodes || []; }, append: function(element, node) { @@ -2801,10 +2846,15 @@ forEach({ removeClass: jqLiteRemoveClass, toggleClass: function(element, selector, condition) { - if (isUndefined(condition)) { - condition = !jqLiteHasClass(element, selector); + if (selector) { + forEach(selector.split(' '), function(className){ + var classCondition = condition; + if (isUndefined(classCondition)) { + classCondition = !jqLiteHasClass(element, className); + } + (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className); + }); } - (condition ? jqLiteAddClass : jqLiteRemoveClass)(element, selector); }, parent: function(element) { @@ -2922,7 +2972,7 @@ HashMap.prototype = { /** * @param key - * @returns the value for the key + * @returns {Object} the value for the key */ get: function(key) { return this[hashKey(key)]; @@ -2941,6 +2991,7 @@ HashMap.prototype = { /** * @ngdoc function + * @module ng * @name angular.injector * @function * @@ -2951,11 +3002,11 @@ HashMap.prototype = { * @param {Array.} modules A list of module functions or their aliases. See * {@link angular.module}. The `ng` module must be explicitly added. - * @returns {function()} Injector function. See {@link AUTO.$injector $injector}. + * @returns {function()} Injector function. See {@link auto.$injector $injector}. * * @example * Typical usage - *
+ * ```js
  *   // create an injector
  *   var $injector = angular.injector(['ng']);
  *
@@ -2965,7 +3016,7 @@ HashMap.prototype = {
  *     $compile($document)($rootScope);
  *     $rootScope.$digest();
  *   });
- * 
+ * ``` * * Sometimes you want to get access to the injector of a currently running Angular app * from outside Angular. Perhaps, you want to inject and compile some markup after the @@ -2979,7 +3030,7 @@ HashMap.prototype = { * directive is added to the end of the document body by JQuery. We then compile and link * it into the current AngularJS scope. * - *
+ * ```js
  * var $div = $('
{{content.label}}
'); * $(document.body).append($div); * @@ -2987,16 +3038,16 @@ HashMap.prototype = { * var scope = angular.element($div).scope(); * $compile($div)(scope); * }); - *
+ * ``` */ /** - * @ngdoc overview - * @name AUTO + * @ngdoc module + * @name auto * @description * - * Implicit module which gets automatically added to each {@link AUTO.$injector $injector}. + * Implicit module which gets automatically added to each {@link auto.$injector $injector}. */ var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; @@ -3037,32 +3088,32 @@ function annotate(fn) { /////////////////////////////////////// /** - * @ngdoc object - * @name AUTO.$injector + * @ngdoc service + * @name $injector * @function * * @description * * `$injector` is used to retrieve object instances as defined by - * {@link AUTO.$provide provider}, instantiate types, invoke methods, + * {@link auto.$provide provider}, instantiate types, invoke methods, * and load modules. * * The following always holds true: * - *
+ * ```js
  *   var $injector = angular.injector();
  *   expect($injector.get('$injector')).toBe($injector);
  *   expect($injector.invoke(function($injector){
  *     return $injector;
  *   }).toBe($injector);
- * 
+ * ``` * * # Injection Function Annotation * * JavaScript does not have annotations, and annotations are needed for dependency injection. The * following are all valid ways of annotating function with injection arguments and are equivalent. * - *
+ * ```js
  *   // inferred (only works if code not minified/obfuscated)
  *   $injector.invoke(function(serviceA){});
  *
@@ -3073,7 +3124,7 @@ function annotate(fn) {
  *
  *   // inline
  *   $injector.invoke(['serviceA', function(serviceA){}]);
- * 
+ * ``` * * ## Inference * @@ -3090,8 +3141,7 @@ function annotate(fn) { /** * @ngdoc method - * @name AUTO.$injector#get - * @methodOf AUTO.$injector + * @name $injector#get * * @description * Return an instance of the service. @@ -3102,13 +3152,12 @@ function annotate(fn) { /** * @ngdoc method - * @name AUTO.$injector#invoke - * @methodOf AUTO.$injector + * @name $injector#invoke * * @description * Invoke the method and supply the method arguments from the `$injector`. * - * @param {!function} fn The function to invoke. Function parameters are injected according to the + * @param {!Function} fn The function to invoke. Function parameters are injected according to the * {@link guide/di $inject Annotation} rules. * @param {Object=} self The `this` for the invoked method. * @param {Object=} locals Optional object. If preset then any argument names are read from this @@ -3118,8 +3167,7 @@ function annotate(fn) { /** * @ngdoc method - * @name AUTO.$injector#has - * @methodOf AUTO.$injector + * @name $injector#has * * @description * Allows the user to query if the particular service exist. @@ -3130,14 +3178,13 @@ function annotate(fn) { /** * @ngdoc method - * @name AUTO.$injector#instantiate - * @methodOf AUTO.$injector + * @name $injector#instantiate * @description * Create a new instance of JS type. The method takes a constructor function invokes the new * operator and supplies all of the arguments to the constructor function as specified by the * constructor annotation. * - * @param {function} Type Annotated constructor function. + * @param {Function} Type Annotated constructor function. * @param {Object=} locals Optional object. If preset then any argument names are read from this * object first, before the `$injector` is consulted. * @returns {Object} new instance of `Type`. @@ -3145,8 +3192,7 @@ function annotate(fn) { /** * @ngdoc method - * @name AUTO.$injector#annotate - * @methodOf AUTO.$injector + * @name $injector#annotate * * @description * Returns an array of service names which the function is requesting for injection. This API is @@ -3159,7 +3205,7 @@ function annotate(fn) { * The simplest form is to extract the dependencies from the arguments of the function. This is done * by converting the function into a string using `toString()` method and extracting the argument * names. - *
+ * ```js
  *   // Given
  *   function MyController($scope, $route) {
  *     // ...
@@ -3167,7 +3213,7 @@ function annotate(fn) {
  *
  *   // Then
  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
- * 
+ * ``` * * This method does not work with code minification / obfuscation. For this reason the following * annotation strategies are supported. @@ -3176,7 +3222,7 @@ function annotate(fn) { * * If a function has an `$inject` property and its value is an array of strings, then the strings * represent names of services to be injected into the function. - *
+ * ```js
  *   // Given
  *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
  *     // ...
@@ -3186,7 +3232,7 @@ function annotate(fn) {
  *
  *   // Then
  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
- * 
+ * ``` * * # The array notation * @@ -3194,7 +3240,7 @@ function annotate(fn) { * is very inconvenient. In these situations using the array notation to specify the dependencies in * a way that survives minification is a better choice: * - *
+ * ```js
  *   // We wish to write this (not minification / obfuscation safe)
  *   injector.invoke(function($compile, $rootScope) {
  *     // ...
@@ -3216,9 +3262,9 @@ function annotate(fn) {
  *   expect(injector.annotate(
  *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
  *    ).toEqual(['$compile', '$rootScope']);
- * 
+ * ``` * - * @param {function|Array.} fn Function for which dependent service names need to + * @param {Function|Array.} fn Function for which dependent service names need to * be retrieved as described above. * * @returns {Array.} The names of the services which the function requires. @@ -3229,12 +3275,12 @@ function annotate(fn) { /** * @ngdoc object - * @name AUTO.$provide + * @name $provide * * @description * - * The {@link AUTO.$provide $provide} service has a number of methods for registering components - * with the {@link AUTO.$injector $injector}. Many of these functions are also exposed on + * The {@link auto.$provide $provide} service has a number of methods for registering components + * with the {@link auto.$injector $injector}. Many of these functions are also exposed on * {@link angular.Module}. * * An Angular **service** is a singleton object created by a **service factory**. These **service @@ -3242,25 +3288,25 @@ function annotate(fn) { * The **service providers** are constructor functions. When instantiated they must contain a * property called `$get`, which holds the **service factory** function. * - * When you request a service, the {@link AUTO.$injector $injector} is responsible for finding the + * When you request a service, the {@link auto.$injector $injector} is responsible for finding the * correct **service provider**, instantiating it and then calling its `$get` **service factory** * function to get the instance of the **service**. * * Often services have no configuration options and there is no need to add methods to the service * provider. The provider will be no more than a constructor function with a `$get` property. For - * these cases the {@link AUTO.$provide $provide} service has additional helper methods to register + * these cases the {@link auto.$provide $provide} service has additional helper methods to register * services without specifying a provider. * - * * {@link AUTO.$provide#methods_provider provider(provider)} - registers a **service provider** with the - * {@link AUTO.$injector $injector} - * * {@link AUTO.$provide#methods_constant constant(obj)} - registers a value/object that can be accessed by + * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the + * {@link auto.$injector $injector} + * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by * providers and services. - * * {@link AUTO.$provide#methods_value value(obj)} - registers a value/object that can only be accessed by + * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by * services, not providers. - * * {@link AUTO.$provide#methods_factory factory(fn)} - registers a service **factory function**, `fn`, + * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`, * that will be wrapped in a **service provider** object, whose `$get` property will contain the * given factory function. - * * {@link AUTO.$provide#methods_service service(class)} - registers a **constructor function**, `class` that + * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class` * that will be wrapped in a **service provider** object, whose `$get` property will instantiate * a new object using the given constructor function. * @@ -3269,11 +3315,10 @@ function annotate(fn) { /** * @ngdoc method - * @name AUTO.$provide#provider - * @methodOf AUTO.$provide + * @name $provide#provider * @description * - * Register a **provider function** with the {@link AUTO.$injector $injector}. Provider functions + * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions * are constructor functions, whose instances are responsible for "providing" a factory for a * service. * @@ -3293,18 +3338,18 @@ function annotate(fn) { * @param {(Object|function())} provider If the provider is: * * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using - * {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created. - * - `Constructor`: a new instance of the provider will be created using - * {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`. + * {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created. + * - `Constructor`: a new instance of the provider will be created using + * {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`. * * @returns {Object} registered provider instance * @example * * The following example shows how to create a simple event tracking service and register it using - * {@link AUTO.$provide#methods_provider $provide.provider()}. + * {@link auto.$provide#provider $provide.provider()}. * - *
+ * ```js
  *  // Define the eventTracker provider
  *  function EventTrackerProvider() {
  *    var trackingUrl = '/track';
@@ -3361,19 +3406,18 @@ function annotate(fn) {
  *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
  *    }));
  *  });
- * 
+ * ``` */ /** * @ngdoc method - * @name AUTO.$provide#factory - * @methodOf AUTO.$provide + * @name $provide#factory * @description * * Register a **service factory**, which will be called to return the service instance. * This is short for registering a service where its provider consists of only a `$get` property, * which is the given service factory function. - * You should use {@link AUTO.$provide#factory $provide.factory(getFn)} if you do not need to + * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to * configure your service in a provider. * * @param {string} name The name of the instance. @@ -3383,26 +3427,25 @@ function annotate(fn) { * * @example * Here is an example of registering a service - *
+ * ```js
  *   $provide.factory('ping', ['$http', function($http) {
  *     return function ping() {
  *       return $http.send('/ping');
  *     };
  *   }]);
- * 
+ * ``` * You would then inject and use this service like this: - *
+ * ```js
  *   someModule.controller('Ctrl', ['ping', function(ping) {
  *     ping();
  *   }]);
- * 
+ * ``` */ /** * @ngdoc method - * @name AUTO.$provide#service - * @methodOf AUTO.$provide + * @name $provide#service * @description * * Register a **service constructor**, which will be invoked with `new` to create the service @@ -3410,7 +3453,7 @@ function annotate(fn) { * This is short for registering a service where its provider's `$get` property is the service * constructor function that will be used to instantiate the service instance. * - * You should use {@link AUTO.$provide#methods_service $provide.service(class)} if you define your service + * You should use {@link auto.$provide#service $provide.service(class)} if you define your service * as a type/class. * * @param {string} name The name of the instance. @@ -3419,35 +3462,34 @@ function annotate(fn) { * * @example * Here is an example of registering a service using - * {@link AUTO.$provide#methods_service $provide.service(class)}. - *
+ * {@link auto.$provide#service $provide.service(class)}.
+ * ```js
  *   var Ping = function($http) {
  *     this.$http = $http;
  *   };
- * 
+ *
  *   Ping.$inject = ['$http'];
- *   
+ *
  *   Ping.prototype.send = function() {
  *     return this.$http.get('/ping');
  *   };
  *   $provide.service('ping', Ping);
- * 
+ * ``` * You would then inject and use this service like this: - *
+ * ```js
  *   someModule.controller('Ctrl', ['ping', function(ping) {
  *     ping.send();
  *   }]);
- * 
+ * ``` */ /** * @ngdoc method - * @name AUTO.$provide#value - * @methodOf AUTO.$provide + * @name $provide#value * @description * - * Register a **value service** with the {@link AUTO.$injector $injector}, such as a string, a + * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a * number, an array, an object or a function. This is short for registering a service where its * provider's `$get` property is a factory function that takes no arguments and returns the **value * service**. @@ -3455,7 +3497,7 @@ function annotate(fn) { * Value services are similar to constant services, except that they cannot be injected into a * module configuration function (see {@link angular.Module#config}) but they can be overridden by * an Angular - * {@link AUTO.$provide#decorator decorator}. + * {@link auto.$provide#decorator decorator}. * * @param {string} name The name of the instance. * @param {*} value The value. @@ -3463,7 +3505,7 @@ function annotate(fn) { * * @example * Here are some examples of creating value services. - *
+ * ```js
  *   $provide.value('ADMIN_USER', 'admin');
  *
  *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
@@ -3471,20 +3513,19 @@ function annotate(fn) {
  *   $provide.value('halfOf', function(value) {
  *     return value / 2;
  *   });
- * 
+ * ``` */ /** * @ngdoc method - * @name AUTO.$provide#constant - * @methodOf AUTO.$provide + * @name $provide#constant * @description * * Register a **constant service**, such as a string, a number, an array, an object or a function, - * with the {@link AUTO.$injector $injector}. Unlike {@link AUTO.$provide#value value} it can be + * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be * injected into a module configuration function (see {@link angular.Module#config}) and it cannot - * be overridden by an Angular {@link AUTO.$provide#decorator decorator}. + * be overridden by an Angular {@link auto.$provide#decorator decorator}. * * @param {string} name The name of the constant. * @param {*} value The constant value. @@ -3492,7 +3533,7 @@ function annotate(fn) { * * @example * Here a some examples of creating constants: - *
+ * ```js
  *   $provide.constant('SHARD_HEIGHT', 306);
  *
  *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
@@ -3500,17 +3541,16 @@ function annotate(fn) {
  *   $provide.constant('double', function(value) {
  *     return value * 2;
  *   });
- * 
+ * ``` */ /** * @ngdoc method - * @name AUTO.$provide#decorator - * @methodOf AUTO.$provide + * @name $provide#decorator * @description * - * Register a **service decorator** with the {@link AUTO.$injector $injector}. A service decorator + * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator * intercepts the creation of a service, allowing it to override or modify the behaviour of the * service. The object returned by the decorator may be the original service, or a new service * object which replaces or wraps and delegates to the original service. @@ -3518,7 +3558,7 @@ function annotate(fn) { * @param {string} name The name of the service to decorate. * @param {function()} decorator This function will be invoked when the service needs to be * instantiated and should return the decorated service instance. The function is called using - * the {@link AUTO.$injector#invoke injector.invoke} method and is therefore fully injectable. + * the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable. * Local injection arguments: * * * `$delegate` - The original service instance, which can be monkey patched, configured, @@ -3527,12 +3567,12 @@ function annotate(fn) { * @example * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting * calls to {@link ng.$log#error $log.warn()}. - *
+ * ```js
  *   $provide.decorator('$log', ['$delegate', function($delegate) {
  *     $delegate.warn = $delegate.error;
  *     return $delegate;
  *   }]);
- * 
+ * ``` */ @@ -3746,8 +3786,9 @@ function createInjector(modulesToLoad) { } /** - * @ngdoc function - * @name ng.$anchorScroll + * @ngdoc service + * @name $anchorScroll + * @kind function * @requires $window * @requires $location * @requires $rootScope @@ -3755,11 +3796,11 @@ function createInjector(modulesToLoad) { * @description * When called, it checks current value of `$location.hash()` and scroll to related element, * according to rules specified in - * {@link http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document Html5 spec}. + * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document). * * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor. * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`. - * + * * @example @@ -3774,10 +3815,10 @@ function createInjector(modulesToLoad) { // set the location.hash to the id of // the element you wish to scroll to. $location.hash('bottom'); - + // call $anchorScroll() $anchorScroll(); - } + }; } @@ -3848,8 +3889,8 @@ function $AnchorScrollProvider() { var $animateMinErr = minErr('$animate'); /** - * @ngdoc object - * @name ng.$animateProvider + * @ngdoc provider + * @name $animateProvider * * @description * Default implementation of $animate that doesn't perform any animations, instead just @@ -3862,14 +3903,13 @@ var $animateMinErr = minErr('$animate'); */ var $AnimateProvider = ['$provide', function($provide) { - + this.$$selectors = {}; /** - * @ngdoc function - * @name ng.$animateProvider#register - * @methodOf ng.$animateProvider + * @ngdoc method + * @name $animateProvider#register * * @description * Registers a new injectable animation factory function. The factory function produces the @@ -3882,7 +3922,7 @@ var $AnimateProvider = ['$provide', function($provide) { * triggered. * * - *
+   * ```js
    *   return {
      *     eventFn : function(element, done) {
      *       //code to run the animation
@@ -3892,10 +3932,10 @@ var $AnimateProvider = ['$provide', function($provide) {
      *       }
      *     }
      *   }
-   *
+ * ``` * * @param {string} name The name of the animation. - * @param {function} factory The factory function that will be executed to return the animation + * @param {Function} factory The factory function that will be executed to return the animation * object. */ this.register = function(name, factory) { @@ -3907,9 +3947,8 @@ var $AnimateProvider = ['$provide', function($provide) { }; /** - * @ngdoc function - * @name ng.$animateProvider#classNameFilter - * @methodOf ng.$animateProvider + * @ngdoc method + * @name $animateProvider#classNameFilter * * @description * Sets and/or returns the CSS class regular expression that is checked when performing @@ -3928,12 +3967,16 @@ var $AnimateProvider = ['$provide', function($provide) { return this.$$classNameFilter; }; - this.$get = ['$timeout', function($timeout) { + this.$get = ['$timeout', '$$asyncCallback', function($timeout, $$asyncCallback) { + + function async(fn) { + fn && $$asyncCallback(fn); + } /** * - * @ngdoc object - * @name ng.$animate + * @ngdoc service + * @name $animate * @description The $animate service provides rudimentary DOM manipulation functions to * insert, remove and move elements within the DOM, as well as adding and removing classes. * This service is the core service used by the ngAnimate $animator service which provides @@ -3951,18 +3994,17 @@ var $AnimateProvider = ['$provide', function($provide) { /** * - * @ngdoc function - * @name ng.$animate#enter - * @methodOf ng.$animate + * @ngdoc method + * @name $animate#enter * @function * @description Inserts the element into the DOM either after the `after` element or within * the `parent` element. Once complete, the done() callback will be fired (if provided). - * @param {jQuery/jqLite element} element the element which will be inserted into the DOM - * @param {jQuery/jqLite element} parent the parent element which will append the element as + * @param {DOMElement} element the element which will be inserted into the DOM + * @param {DOMElement} parent the parent element which will append the element as * a child (if the after element is not present) - * @param {jQuery/jqLite element} after the sibling element which will append the element + * @param {DOMElement} after the sibling element which will append the element * after itself - * @param {function=} done callback function that will be called after the element has been + * @param {Function=} done callback function that will be called after the element has been * inserted into the DOM */ enter : function(element, parent, after, done) { @@ -3974,43 +4016,41 @@ var $AnimateProvider = ['$provide', function($provide) { } parent.append(element); } - done && $timeout(done, 0, false); + async(done); }, /** * - * @ngdoc function - * @name ng.$animate#leave - * @methodOf ng.$animate + * @ngdoc method + * @name $animate#leave * @function * @description Removes the element from the DOM. Once complete, the done() callback will be * fired (if provided). - * @param {jQuery/jqLite element} element the element which will be removed from the DOM - * @param {function=} done callback function that will be called after the element has been + * @param {DOMElement} element the element which will be removed from the DOM + * @param {Function=} done callback function that will be called after the element has been * removed from the DOM */ leave : function(element, done) { element.remove(); - done && $timeout(done, 0, false); + async(done); }, /** * - * @ngdoc function - * @name ng.$animate#move - * @methodOf ng.$animate + * @ngdoc method + * @name $animate#move * @function * @description Moves the position of the provided element within the DOM to be placed * either after the `after` element or inside of the `parent` element. Once complete, the * done() callback will be fired (if provided). - * - * @param {jQuery/jqLite element} element the element which will be moved around within the + * + * @param {DOMElement} element the element which will be moved around within the * DOM - * @param {jQuery/jqLite element} parent the parent element where the element will be + * @param {DOMElement} parent the parent element where the element will be * inserted into (if the after element is not present) - * @param {jQuery/jqLite element} after the sibling element where the element will be + * @param {DOMElement} after the sibling element where the element will be * positioned next to - * @param {function=} done the callback function (if provided) that will be fired after the + * @param {Function=} done the callback function (if provided) that will be fired after the * element has been moved to its new position */ move : function(element, parent, after, done) { @@ -4021,16 +4061,15 @@ var $AnimateProvider = ['$provide', function($provide) { /** * - * @ngdoc function - * @name ng.$animate#addClass - * @methodOf ng.$animate + * @ngdoc method + * @name $animate#addClass * @function * @description Adds the provided className CSS class value to the provided element. Once * complete, the done() callback will be fired (if provided). - * @param {jQuery/jqLite element} element the element which will have the className value + * @param {DOMElement} element the element which will have the className value * added to it * @param {string} className the CSS class which will be added to the element - * @param {function=} done the callback function (if provided) that will be fired after the + * @param {Function=} done the callback function (if provided) that will be fired after the * className value has been added to the element */ addClass : function(element, className, done) { @@ -4040,21 +4079,20 @@ var $AnimateProvider = ['$provide', function($provide) { forEach(element, function (element) { jqLiteAddClass(element, className); }); - done && $timeout(done, 0, false); + async(done); }, /** * - * @ngdoc function - * @name ng.$animate#removeClass - * @methodOf ng.$animate + * @ngdoc method + * @name $animate#removeClass * @function * @description Removes the provided className CSS class value from the provided element. * Once complete, the done() callback will be fired (if provided). - * @param {jQuery/jqLite element} element the element which will have the className value + * @param {DOMElement} element the element which will have the className value * removed from it * @param {string} className the CSS class which will be removed from the element - * @param {function=} done the callback function (if provided) that will be fired after the + * @param {Function=} done the callback function (if provided) that will be fired after the * className value has been removed from the element */ removeClass : function(element, className, done) { @@ -4064,22 +4102,21 @@ var $AnimateProvider = ['$provide', function($provide) { forEach(element, function (element) { jqLiteRemoveClass(element, className); }); - done && $timeout(done, 0, false); + async(done); }, /** * - * @ngdoc function - * @name ng.$animate#setClass - * @methodOf ng.$animate + * @ngdoc method + * @name $animate#setClass * @function * @description Adds and/or removes the given CSS classes to and from the element. * Once complete, the done() callback will be fired (if provided). - * @param {jQuery/jqLite element} element the element which will it's CSS classes changed + * @param {DOMElement} element the element which will it's CSS classes changed * removed from it * @param {string} add the CSS classes which will be added to the element * @param {string} remove the CSS class which will be removed from the element - * @param {function=} done the callback function (if provided) that will be fired after the + * @param {Function=} done the callback function (if provided) that will be fired after the * CSS classes have been set on the element */ setClass : function(element, add, remove, done) { @@ -4087,7 +4124,7 @@ var $AnimateProvider = ['$provide', function($provide) { jqLiteAddClass(element, add); jqLiteRemoveClass(element, remove); }); - done && $timeout(done, 0, false); + async(done); }, enabled : noop @@ -4095,10 +4132,20 @@ var $AnimateProvider = ['$provide', function($provide) { }]; }]; +function $$AsyncCallbackProvider(){ + this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) { + return $$rAF.supported + ? function(fn) { return $$rAF(fn); } + : function(fn) { + return $timeout(fn, 0, false); + }; + }]; +} + /** * ! This is a private undocumented service ! * - * @name ng.$browser + * @name $browser * @requires $log * @description * This object has two goals: @@ -4182,8 +4229,7 @@ function Browser(window, document, $log, $sniffer) { pollTimeout; /** - * @name ng.$browser#addPollFn - * @methodOf ng.$browser + * @name $browser#addPollFn * * @param {function()} fn Poll function to add * @@ -4223,8 +4269,7 @@ function Browser(window, document, $log, $sniffer) { newLocation = null; /** - * @name ng.$browser#url - * @methodOf ng.$browser + * @name $browser#url * * @description * GETTER: @@ -4290,9 +4335,7 @@ function Browser(window, document, $log, $sniffer) { } /** - * @name ng.$browser#onUrlChange - * @methodOf ng.$browser - * @TODO(vojta): refactor to use node's syntax for events + * @name $browser#onUrlChange * * @description * Register callback function that will be called, when url changes. @@ -4313,6 +4356,7 @@ function Browser(window, document, $log, $sniffer) { * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous. */ self.onUrlChange = function(callback) { + // TODO(vojta): refactor to use node's syntax for events if (!urlChangeInit) { // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera) // don't fire popstate when user change the address bar and don't fire hashchange when url @@ -4337,14 +4381,13 @@ function Browser(window, document, $log, $sniffer) { ////////////////////////////////////////////////////////////// /** - * @name ng.$browser#baseHref - * @methodOf ng.$browser + * @name $browser#baseHref * * @description * Returns current * (always relative - without domain) * - * @returns {string=} current + * @returns {string} The current base href */ self.baseHref = function() { var href = baseElement.attr('href'); @@ -4359,8 +4402,7 @@ function Browser(window, document, $log, $sniffer) { var cookiePath = self.baseHref(); /** - * @name ng.$browser#cookies - * @methodOf ng.$browser + * @name $browser#cookies * * @param {string=} name Cookie name * @param {string=} value Cookie value @@ -4429,8 +4471,7 @@ function Browser(window, document, $log, $sniffer) { /** - * @name ng.$browser#defer - * @methodOf ng.$browser + * @name $browser#defer * @param {function()} fn A function, who's execution should be deferred. * @param {number=} [delay=0] of milliseconds to defer the function execution. * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`. @@ -4456,8 +4497,7 @@ function Browser(window, document, $log, $sniffer) { /** - * @name ng.$browser#defer.cancel - * @methodOf ng.$browser.defer + * @name $browser#defer.cancel * * @description * Cancels a deferred task identified with `deferId`. @@ -4486,14 +4526,14 @@ function $BrowserProvider(){ } /** - * @ngdoc object - * @name ng.$cacheFactory + * @ngdoc service + * @name $cacheFactory * * @description * Factory that constructs cache objects and gives access to them. - * - *
- * 
+ *
+ * ```js
+ *
  *  var cache = $cacheFactory('cacheId');
  *  expect($cacheFactory.get('cacheId')).toBe(cache);
  *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
@@ -4502,9 +4542,9 @@ function $BrowserProvider(){
  *  cache.put("another key", "another value");
  *
  *  // We've specified no options on creation
- *  expect(cache.info()).toEqual({id: 'cacheId', size: 2}); 
- * 
- * 
+ * expect(cache.info()).toEqual({id: 'cacheId', size: 2}); + * + * ``` * * * @param {string} cacheId Name or id of the newly created cache. @@ -4544,9 +4584,11 @@ function $CacheFactoryProvider() { return caches[cacheId] = { put: function(key, value) { - var lruEntry = lruHash[key] || (lruHash[key] = {key: key}); + if (capacity < Number.MAX_VALUE) { + var lruEntry = lruHash[key] || (lruHash[key] = {key: key}); - refresh(lruEntry); + refresh(lruEntry); + } if (isUndefined(value)) return; if (!(key in data)) size++; @@ -4561,26 +4603,31 @@ function $CacheFactoryProvider() { get: function(key) { - var lruEntry = lruHash[key]; + if (capacity < Number.MAX_VALUE) { + var lruEntry = lruHash[key]; - if (!lruEntry) return; + if (!lruEntry) return; - refresh(lruEntry); + refresh(lruEntry); + } return data[key]; }, remove: function(key) { - var lruEntry = lruHash[key]; + if (capacity < Number.MAX_VALUE) { + var lruEntry = lruHash[key]; - if (!lruEntry) return; + if (!lruEntry) return; - if (lruEntry == freshEnd) freshEnd = lruEntry.p; - if (lruEntry == staleEnd) staleEnd = lruEntry.n; - link(lruEntry.n,lruEntry.p); + if (lruEntry == freshEnd) freshEnd = lruEntry.p; + if (lruEntry == staleEnd) staleEnd = lruEntry.n; + link(lruEntry.n,lruEntry.p); + + delete lruHash[key]; + } - delete lruHash[key]; delete data[key]; size--; }, @@ -4641,8 +4688,7 @@ function $CacheFactoryProvider() { /** * @ngdoc method - * @name ng.$cacheFactory#info - * @methodOf ng.$cacheFactory + * @name $cacheFactory#info * * @description * Get information about all the of the caches that have been created @@ -4660,8 +4706,7 @@ function $CacheFactoryProvider() { /** * @ngdoc method - * @name ng.$cacheFactory#get - * @methodOf ng.$cacheFactory + * @name $cacheFactory#get * * @description * Get access to a cache object by the `cacheId` used when it was created. @@ -4679,16 +4724,16 @@ function $CacheFactoryProvider() { } /** - * @ngdoc object - * @name ng.$templateCache + * @ngdoc service + * @name $templateCache * * @description * The first time a template is used, it is loaded in the template cache for quick retrieval. You * can load templates directly into the cache in a `script` tag, or by consuming the * `$templateCache` service directly. - * + * * Adding via the `script` tag: - *
+ * ```html
  * 
  * 
  * 
-
-          
-
- Date format:
- Current time is: -
- Blood 1 : {{blood_1}} - Blood 2 : {{blood_2}} - - - -
-
- - - + * + * + * + * + *
+ *
+ * Date format:
+ * Current time is: + *
+ * Blood 1 : {{blood_1}} + * Blood 2 : {{blood_2}} + * + * + * + *
+ *
+ * + *
+ *
*/ function interval(fn, delay, count, invokeApply) { var setInterval = $window.setInterval, @@ -8544,14 +8568,13 @@ function $IntervalProvider() { /** - * @ngdoc function - * @name ng.$interval#cancel - * @methodOf ng.$interval + * @ngdoc method + * @name $interval#cancel * * @description * Cancels a task associated with the `promise`. * - * @param {number} promise Promise returned by the `$interval` function. + * @param {promise} promise returned by the `$interval` function. * @returns {boolean} Returns `true` if the task was successfully canceled. */ interval.cancel = function(promise) { @@ -8569,8 +8592,8 @@ function $IntervalProvider() { } /** - * @ngdoc object - * @name ng.$locale + * @ngdoc service + * @name $locale * * @description * $locale service provides localization rules for various Angular components. As of right now the @@ -8929,14 +8952,13 @@ LocationHashbangInHtml5Url.prototype = /** * @ngdoc method - * @name ng.$location#absUrl - * @methodOf ng.$location + * @name $location#absUrl * * @description * This method is getter only. * * Return full url representation with all segments encoded according to rules specified in - * {@link http://www.ietf.org/rfc/rfc3986.txt RFC 3986}. + * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt). * * @return {string} full url */ @@ -8944,8 +8966,7 @@ LocationHashbangInHtml5Url.prototype = /** * @ngdoc method - * @name ng.$location#url - * @methodOf ng.$location + * @name $location#url * * @description * This method is getter / setter. @@ -8972,8 +8993,7 @@ LocationHashbangInHtml5Url.prototype = /** * @ngdoc method - * @name ng.$location#protocol - * @methodOf ng.$location + * @name $location#protocol * * @description * This method is getter only. @@ -8986,8 +9006,7 @@ LocationHashbangInHtml5Url.prototype = /** * @ngdoc method - * @name ng.$location#host - * @methodOf ng.$location + * @name $location#host * * @description * This method is getter only. @@ -9000,8 +9019,7 @@ LocationHashbangInHtml5Url.prototype = /** * @ngdoc method - * @name ng.$location#port - * @methodOf ng.$location + * @name $location#port * * @description * This method is getter only. @@ -9014,8 +9032,7 @@ LocationHashbangInHtml5Url.prototype = /** * @ngdoc method - * @name ng.$location#path - * @methodOf ng.$location + * @name $location#path * * @description * This method is getter / setter. @@ -9036,8 +9053,7 @@ LocationHashbangInHtml5Url.prototype = /** * @ngdoc method - * @name ng.$location#search - * @methodOf ng.$location + * @name $location#search * * @description * This method is getter / setter. @@ -9084,8 +9100,7 @@ LocationHashbangInHtml5Url.prototype = /** * @ngdoc method - * @name ng.$location#hash - * @methodOf ng.$location + * @name $location#hash * * @description * This method is getter / setter. @@ -9101,8 +9116,7 @@ LocationHashbangInHtml5Url.prototype = /** * @ngdoc method - * @name ng.$location#replace - * @methodOf ng.$location + * @name $location#replace * * @description * If called, all changes to $location during current `$digest` will be replacing current history @@ -9135,16 +9149,14 @@ function locationGetterSetter(property, preprocess) { /** - * @ngdoc object - * @name ng.$location + * @ngdoc service + * @name $location * - * @requires $browser - * @requires $sniffer * @requires $rootElement * * @description * The $location service parses the URL in the browser address bar (based on the - * {@link https://developer.mozilla.org/en/window.location window.location}) and makes the URL + * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL * available to your application. Changes to the URL in the address bar are reflected into * $location service and changes to $location are reflected into the browser address bar. * @@ -9164,8 +9176,8 @@ function locationGetterSetter(property, preprocess) { */ /** - * @ngdoc object - * @name ng.$locationProvider + * @ngdoc provider + * @name $locationProvider * @description * Use the `$locationProvider` to configure how the application deep linking paths are stored. */ @@ -9175,8 +9187,7 @@ function $LocationProvider(){ /** * @ngdoc property - * @name ng.$locationProvider#hashPrefix - * @methodOf ng.$locationProvider + * @name $locationProvider#hashPrefix * @description * @param {string=} prefix Prefix for hash part (containing path and search) * @returns {*} current value if used as getter or itself (chaining) if used as setter @@ -9192,8 +9203,7 @@ function $LocationProvider(){ /** * @ngdoc property - * @name ng.$locationProvider#html5Mode - * @methodOf ng.$locationProvider + * @name $locationProvider#html5Mode * @description * @param {boolean=} mode Use HTML5 strategy if available. * @returns {*} current value if used as getter or itself (chaining) if used as setter @@ -9209,12 +9219,11 @@ function $LocationProvider(){ /** * @ngdoc event - * @name ng.$location#$locationChangeStart - * @eventOf ng.$location + * @name $location#$locationChangeStart * @eventType broadcast on root scope * @description * Broadcasted before a URL will change. This change can be prevented by calling - * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#methods_$on} for more + * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more * details about event object. Upon successful change * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired. * @@ -9225,8 +9234,7 @@ function $LocationProvider(){ /** * @ngdoc event - * @name ng.$location#$locationChangeSuccess - * @eventOf ng.$location + * @name $location#$locationChangeSuccess * @eventType broadcast on root scope * @description * Broadcasted after a URL was changed. @@ -9347,14 +9355,14 @@ function $LocationProvider(){ } /** - * @ngdoc object - * @name ng.$log + * @ngdoc service + * @name $log * @requires $window * * @description * Simple service for logging. Default implementation safely writes the message * into the browser's console (if present). - * + * * The main purpose of this service is to simplify debugging and troubleshooting. * * The default is to log `debug` messages. You can use @@ -9383,19 +9391,18 @@ function $LocationProvider(){ */ /** - * @ngdoc object - * @name ng.$logProvider + * @ngdoc provider + * @name $logProvider * @description * Use the `$logProvider` to configure how the application logs messages */ function $LogProvider(){ var debug = true, self = this; - + /** * @ngdoc property - * @name ng.$logProvider#debugEnabled - * @methodOf ng.$logProvider + * @name $logProvider#debugEnabled * @description * @param {boolean=} flag enable or disable debug level messages * @returns {*} current value if used as getter or itself (chaining) if used as setter @@ -9408,13 +9415,12 @@ function $LogProvider(){ return debug; } }; - + this.$get = ['$window', function($window){ return { /** * @ngdoc method - * @name ng.$log#log - * @methodOf ng.$log + * @name $log#log * * @description * Write a log message @@ -9423,8 +9429,7 @@ function $LogProvider(){ /** * @ngdoc method - * @name ng.$log#info - * @methodOf ng.$log + * @name $log#info * * @description * Write an information message @@ -9433,8 +9438,7 @@ function $LogProvider(){ /** * @ngdoc method - * @name ng.$log#warn - * @methodOf ng.$log + * @name $log#warn * * @description * Write a warning message @@ -9443,19 +9447,17 @@ function $LogProvider(){ /** * @ngdoc method - * @name ng.$log#error - * @methodOf ng.$log + * @name $log#error * * @description * Write an error message */ error: consoleLog('error'), - + /** * @ngdoc method - * @name ng.$log#debug - * @methodOf ng.$log - * + * @name $log#debug + * * @description * Write a debug message */ @@ -9491,7 +9493,7 @@ function $LogProvider(){ // Note: reading logFn.apply throws an error in IE11 in IE8 document mode. // The reason behind this is that console.log has type "object" in IE8... try { - hasApply = !! logFn.apply; + hasApply = !!logFn.apply; } catch (e) {} if (hasApply) { @@ -9568,7 +9570,7 @@ function ensureSafeObject(obj, fullExpression) { 'Referencing the Window in Angular expressions is disallowed! Expression: {0}', fullExpression); } else if (// isElement(obj) - obj.children && (obj.nodeName || (obj.on && obj.find))) { + obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) { throw $parseMinErr('isecdom', 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}', fullExpression); @@ -10298,6 +10300,10 @@ Parser.prototype = { var allConstant = true; if (this.peekToken().text !== ']') { do { + if (this.peek(']')) { + // Support trailing commas per ES5.1. + break; + } var elementFn = this.expression(); elementFns.push(elementFn); if (!elementFn.constant) { @@ -10324,6 +10330,10 @@ Parser.prototype = { var allConstant = true; if (this.peekToken().text !== '}') { do { + if (this.peek('}')) { + // Support trailing commas per ES5.1. + break; + } var token = this.expect(), key = token.string || token.text; this.consume(':'); @@ -10596,15 +10606,15 @@ function getterFn(path, options, fullExp) { /////////////////////////////////// /** - * @ngdoc function - * @name ng.$parse - * @function + * @ngdoc service + * @name $parse + * @kind function * * @description * * Converts Angular {@link guide/expression expression} into a function. * - *
+ * ```js
  *   var getter = $parse('user.name');
  *   var setter = getter.assign;
  *   var context = {user:{name:'angular'}};
@@ -10614,7 +10624,7 @@ function getterFn(path, options, fullExp) {
  *   setter(context, 'newValue');
  *   expect(context.user.name).toEqual('newValue');
  *   expect(getter(context, locals)).toEqual('local');
- * 
+ * ``` * * * @param {string} expression String expression to compile. @@ -10637,8 +10647,8 @@ function getterFn(path, options, fullExp) { /** - * @ngdoc object - * @name ng.$parseProvider + * @ngdoc provider + * @name $parseProvider * @function * * @description @@ -10659,8 +10669,7 @@ function $ParseProvider() { * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future. * * @ngdoc method - * @name ng.$parseProvider#unwrapPromises - * @methodOf ng.$parseProvider + * @name $parseProvider#unwrapPromises * @description * * **This feature is deprecated, see deprecation notes below for more info** @@ -10714,8 +10723,7 @@ function $ParseProvider() { * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future. * * @ngdoc method - * @name ng.$parseProvider#logPromiseWarnings - * @methodOf ng.$parseProvider + * @name $parseProvider#logPromiseWarnings * @description * * Controls whether Angular should log a warning on any encounter of a promise in an expression. @@ -10782,7 +10790,7 @@ function $ParseProvider() { /** * @ngdoc service - * @name ng.$q + * @name $q * @requires $rootScope * * @description @@ -10795,10 +10803,10 @@ function $ParseProvider() { * From the perspective of dealing with error handling, deferred and promise APIs are to * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming. * - *
+ * ```js
  *   // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
  *   // are available in the current lexical scope (they could have been injected or passed in).
- * 
+ *
  *   function asyncGreet(name) {
  *     var deferred = $q.defer();
  *
@@ -10827,7 +10835,7 @@ function $ParseProvider() {
  *   }, function(update) {
  *     alert('Got notification: ' + update);
  *   });
- * 
+ * ``` * * At first it might not be obvious why this extra complexity is worth the trouble. The payoff * comes in the way of guarantees that promise and deferred APIs make, see @@ -10899,14 +10907,14 @@ function $ParseProvider() { * Because calling the `then` method of a promise returns a new derived promise, it is easily * possible to create a chain of promises: * - *
+ * ```js
  *   promiseB = promiseA.then(function(result) {
  *     return result + 1;
  *   });
  *
  *   // promiseB will be resolved immediately after promiseA is resolved and its value
  *   // will be the result of promiseA incremented by 1
- * 
+ * ``` * * It is possible to create chains of any length and since a promise can be resolved with another * promise (which will defer its resolution further), it is possible to pause/defer resolution of @@ -10926,7 +10934,7 @@ function $ParseProvider() { * * # Testing * - *
+ *  ```js
  *    it('should simulate promise', inject(function($q, $rootScope) {
  *      var deferred = $q.defer();
  *      var promise = deferred.promise;
@@ -10946,7 +10954,7 @@ function $ParseProvider() {
  *      $rootScope.$apply();
  *      expect(resolvedValue).toEqual(123);
  *    }));
- *  
+ * ``` */ function $QProvider() { @@ -10961,7 +10969,7 @@ function $QProvider() { /** * Constructs a promise manager. * - * @param {function(function)} nextTick Function for executing functions in the next turn. + * @param {function(Function)} nextTick Function for executing functions in the next turn. * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for * debugging purposes. * @returns {object} Promise manager. @@ -10969,9 +10977,10 @@ function $QProvider() { function qFactory(nextTick, exceptionHandler) { /** - * @ngdoc - * @name ng.$q#defer - * @methodOf ng.$q + * @ngdoc method + * @name $q#defer + * @function + * * @description * Creates a `Deferred` object which represents a task which will finish in the future. * @@ -11125,9 +11134,10 @@ function qFactory(nextTick, exceptionHandler) { /** - * @ngdoc - * @name ng.$q#reject - * @methodOf ng.$q + * @ngdoc method + * @name $q#reject + * @function + * * @description * Creates a promise that is resolved as rejected with the specified `reason`. This api should be * used to forward rejection in a chain of promises. If you are dealing with the last promise in @@ -11139,7 +11149,7 @@ function qFactory(nextTick, exceptionHandler) { * current promise, you have to "rethrow" the error by returning a rejection constructed via * `reject`. * - *
+   * ```js
    *   promiseB = promiseA.then(function(result) {
    *     // success: do something and resolve promiseB
    *     //          with the old or a new result
@@ -11154,7 +11164,7 @@ function qFactory(nextTick, exceptionHandler) {
    *     }
    *     return $q.reject(reason);
    *   });
-   * 
+ * ``` * * @param {*} reason Constant, message, exception or an object representing the rejection reason. * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`. @@ -11184,9 +11194,10 @@ function qFactory(nextTick, exceptionHandler) { /** - * @ngdoc - * @name ng.$q#when - * @methodOf ng.$q + * @ngdoc method + * @name $q#when + * @function + * * @description * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. * This is useful when you are dealing with an object that might or might not be a promise, or if @@ -11255,9 +11266,10 @@ function qFactory(nextTick, exceptionHandler) { /** - * @ngdoc - * @name ng.$q#all - * @methodOf ng.$q + * @ngdoc method + * @name $q#all + * @function + * * @description * Combines multiple promises into a single promise that is resolved when all of the input * promises are resolved. @@ -11300,6 +11312,27 @@ function qFactory(nextTick, exceptionHandler) { }; } +function $$RAFProvider(){ //rAF + this.$get = ['$window', function($window) { + var requestAnimationFrame = $window.requestAnimationFrame || + $window.webkitRequestAnimationFrame; + + var cancelAnimationFrame = $window.cancelAnimationFrame || + $window.webkitCancelAnimationFrame; + + var raf = function(fn) { + var id = requestAnimationFrame(fn); + return function() { + cancelAnimationFrame(id); + }; + }; + + raf.supported = !!requestAnimationFrame; + + return raf; + }]; +} + /** * DESIGN NOTES * @@ -11327,17 +11360,16 @@ function qFactory(nextTick, exceptionHandler) { /** - * @ngdoc object - * @name ng.$rootScopeProvider + * @ngdoc provider + * @name $rootScopeProvider * @description * * Provider for the $rootScope service. */ /** - * @ngdoc function - * @name ng.$rootScopeProvider#digestTtl - * @methodOf ng.$rootScopeProvider + * @ngdoc method + * @name $rootScopeProvider#digestTtl * @description * * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and @@ -11358,8 +11390,8 @@ function qFactory(nextTick, exceptionHandler) { /** - * @ngdoc object - * @name ng.$rootScope + * @ngdoc service + * @name $rootScope * @description * * Every application has a single root {@link ng.$rootScope.Scope scope}. @@ -11384,23 +11416,23 @@ function $RootScopeProvider(){ function( $injector, $exceptionHandler, $parse, $browser) { /** - * @ngdoc function - * @name ng.$rootScope.Scope + * @ngdoc type + * @name $rootScope.Scope * * @description * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the - * {@link AUTO.$injector $injector}. Child scopes are created using the - * {@link ng.$rootScope.Scope#methods_$new $new()} method. (Most scopes are created automatically when + * {@link auto.$injector $injector}. Child scopes are created using the + * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when * compiled HTML template is executed.) * * Here is a simple scope snippet to show how you can interact with the scope. - *
+     * ```html
      * 
-     * 
+ * ``` * * # Inheritance * A scope can inherit from a parent scope, as in this example: - *
+     * ```js
          var parent = $rootScope;
          var child = parent.$new();
 
@@ -11411,7 +11443,7 @@ function $RootScopeProvider(){
          child.salutation = "Welcome";
          expect(child.salutation).toEqual('Welcome');
          expect(parent.salutation).toEqual('Hello');
-     * 
+ * ``` * * * @param {Object.=} providers Map of service factory which need to be @@ -11439,8 +11471,7 @@ function $RootScopeProvider(){ /** * @ngdoc property - * @name ng.$rootScope.Scope#$id - * @propertyOf ng.$rootScope.Scope + * @name $rootScope.Scope#$id * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for * debugging. */ @@ -11449,19 +11480,18 @@ function $RootScopeProvider(){ Scope.prototype = { constructor: Scope, /** - * @ngdoc function - * @name ng.$rootScope.Scope#$new - * @methodOf ng.$rootScope.Scope + * @ngdoc method + * @name $rootScope.Scope#$new * @function * * @description * Creates a new child {@link ng.$rootScope.Scope scope}. * - * The parent scope will propagate the {@link ng.$rootScope.Scope#methods_$digest $digest()} and - * {@link ng.$rootScope.Scope#methods_$digest $digest()} events. The scope can be removed from the - * scope hierarchy using {@link ng.$rootScope.Scope#methods_$destroy $destroy()}. + * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and + * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the + * scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}. * - * {@link ng.$rootScope.Scope#methods_$destroy $destroy()} must be called on a scope when it is + * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is * desired for the scope and its child scopes to be permanently detached from the parent and * thus stop participating in model change detection and listener notification by invoking. * @@ -11507,19 +11537,18 @@ function $RootScopeProvider(){ }, /** - * @ngdoc function - * @name ng.$rootScope.Scope#$watch - * @methodOf ng.$rootScope.Scope + * @ngdoc method + * @name $rootScope.Scope#$watch * @function * * @description * Registers a `listener` callback to be executed whenever the `watchExpression` changes. * - * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#methods_$digest + * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest * $digest()} and should return the value that will be watched. (Since - * {@link ng.$rootScope.Scope#methods_$digest $digest()} reruns when it detects changes the + * {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the * `watchExpression` can execute multiple times per - * {@link ng.$rootScope.Scope#methods_$digest $digest()} and should be idempotent.) + * {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.) * - The `listener` is called only when the value from the current `watchExpression` and the * previous call to `watchExpression` are not equal (with the exception of the initial run, * see below). The inequality is determined according to @@ -11531,13 +11560,13 @@ function $RootScopeProvider(){ * iteration limit is 10 to prevent an infinite loop deadlock. * * - * If you want to be notified whenever {@link ng.$rootScope.Scope#methods_$digest $digest} is called, + * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called, * you can register a `watchExpression` function with no `listener`. (Since `watchExpression` - * can execute multiple times per {@link ng.$rootScope.Scope#methods_$digest $digest} cycle when a + * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a * change is detected, be prepared for multiple calls to your listener.) * * After a watcher is registered with the scope, the `listener` fn is called asynchronously - * (via {@link ng.$rootScope.Scope#methods_$evalAsync $evalAsync}) to initialize the + * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the * watcher. In rare cases, this is undesirable because the listener is called when the result * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the @@ -11547,7 +11576,7 @@ function $RootScopeProvider(){ * * * # Example - *
+       * ```js
            // let's assume that scope was dependency injected as the $rootScope
            var scope = $rootScope;
            scope.name = 'misko';
@@ -11596,12 +11625,12 @@ function $RootScopeProvider(){
            scope.$digest();
            expect(scope.foodCounter).toEqual(1);
 
-       * 
+ * ``` * * * * @param {(function()|string)} watchExpression Expression that is evaluated on each - * {@link ng.$rootScope.Scope#methods_$digest $digest} cycle. A change in the return value triggers + * {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers * a call to the `listener`. * * - `string`: Evaluated as {@link guide/expression expression} @@ -11659,9 +11688,8 @@ function $RootScopeProvider(){ /** - * @ngdoc function - * @name ng.$rootScope.Scope#$watchCollection - * @methodOf ng.$rootScope.Scope + * @ngdoc method + * @name $rootScope.Scope#$watchCollection * @function * * @description @@ -11676,7 +11704,7 @@ function $RootScopeProvider(){ * * * # Example - *
+       * ```js
           $scope.names = ['igor', 'matias', 'misko', 'james'];
           $scope.dataCount = 4;
 
@@ -11695,12 +11723,12 @@ function $RootScopeProvider(){
 
           //now there's been a change
           expect($scope.dataCount).toEqual(3);
-       * 
+ * ``` * * - * @param {string|Function(scope)} obj Evaluated as {@link guide/expression expression}. The + * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The * expression value should evaluate to an object or an array which is observed on each - * {@link ng.$rootScope.Scope#methods_$digest $digest} cycle. Any shallow change within the + * {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the * collection will trigger a call to the `listener`. * * @param {function(newCollection, oldCollection, scope)} listener a callback function that is @@ -11799,33 +11827,32 @@ function $RootScopeProvider(){ }, /** - * @ngdoc function - * @name ng.$rootScope.Scope#$digest - * @methodOf ng.$rootScope.Scope + * @ngdoc method + * @name $rootScope.Scope#$digest * @function * * @description - * Processes all of the {@link ng.$rootScope.Scope#methods_$watch watchers} of the current scope and - * its children. Because a {@link ng.$rootScope.Scope#methods_$watch watcher}'s listener can change - * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#methods_$watch watchers} + * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and + * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change + * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} * until no more listeners are firing. This means that it is possible to get into an infinite * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of * iterations exceeds 10. * * Usually, you don't call `$digest()` directly in * {@link ng.directive:ngController controllers} or in - * {@link ng.$compileProvider#methods_directive directives}. - * Instead, you should call {@link ng.$rootScope.Scope#methods_$apply $apply()} (typically from within - * a {@link ng.$compileProvider#methods_directive directives}), which will force a `$digest()`. + * {@link ng.$compileProvider#directive directives}. + * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within + * a {@link ng.$compileProvider#directive directives}), which will force a `$digest()`. * * If you want to be notified whenever `$digest()` is called, * you can register a `watchExpression` function with - * {@link ng.$rootScope.Scope#methods_$watch $watch()} with no `listener`. + * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`. * * In unit tests, you may need to call `$digest()` to simulate the scope life cycle. * * # Example - *
+       * ```js
            var scope = ...;
            scope.name = 'misko';
            scope.counter = 0;
@@ -11843,7 +11870,7 @@ function $RootScopeProvider(){
            scope.name = 'adam';
            scope.$digest();
            expect(scope.counter).toEqual(1);
-       * 
+ * ``` * */ $digest: function() { @@ -11956,8 +11983,7 @@ function $RootScopeProvider(){ /** * @ngdoc event - * @name ng.$rootScope.Scope#$destroy - * @eventOf ng.$rootScope.Scope + * @name $rootScope.Scope#$destroy * @eventType broadcast on scope being destroyed * * @description @@ -11968,14 +11994,13 @@ function $RootScopeProvider(){ */ /** - * @ngdoc function - * @name ng.$rootScope.Scope#$destroy - * @methodOf ng.$rootScope.Scope + * @ngdoc method + * @name $rootScope.Scope#$destroy * @function * * @description * Removes the current scope (and all of its children) from the parent scope. Removal implies - * that calls to {@link ng.$rootScope.Scope#methods_$digest $digest()} will no longer + * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer * propagate to the current scope and its children. Removal also implies that the current * scope is eligible for garbage collection. * @@ -12013,9 +12038,8 @@ function $RootScopeProvider(){ }, /** - * @ngdoc function - * @name ng.$rootScope.Scope#$eval - * @methodOf ng.$rootScope.Scope + * @ngdoc method + * @name $rootScope.Scope#$eval * @function * * @description @@ -12024,14 +12048,14 @@ function $RootScopeProvider(){ * expressions. * * # Example - *
+       * ```js
            var scope = ng.$rootScope.Scope();
            scope.a = 1;
            scope.b = 2;
 
            expect(scope.$eval('a+b')).toEqual(3);
            expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
-       * 
+ * ``` * * @param {(string|function())=} expression An angular expression to be executed. * @@ -12046,9 +12070,8 @@ function $RootScopeProvider(){ }, /** - * @ngdoc function - * @name ng.$rootScope.Scope#$evalAsync - * @methodOf ng.$rootScope.Scope + * @ngdoc method + * @name $rootScope.Scope#$evalAsync * @function * * @description @@ -12059,7 +12082,7 @@ function $RootScopeProvider(){ * * - it will execute after the function that scheduled the evaluation (preferably before DOM * rendering). - * - at least one {@link ng.$rootScope.Scope#methods_$digest $digest cycle} will be performed after + * - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after * `expression` execution. * * Any exceptions from the execution of the expression are forwarded to the @@ -12094,9 +12117,8 @@ function $RootScopeProvider(){ }, /** - * @ngdoc function - * @name ng.$rootScope.Scope#$apply - * @methodOf ng.$rootScope.Scope + * @ngdoc method + * @name $rootScope.Scope#$apply * @function * * @description @@ -12104,12 +12126,12 @@ function $RootScopeProvider(){ * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries). * Because we are calling into the angular framework we need to perform proper scope life * cycle of {@link ng.$exceptionHandler exception handling}, - * {@link ng.$rootScope.Scope#methods_$digest executing watches}. + * {@link ng.$rootScope.Scope#$digest executing watches}. * * ## Life cycle * * # Pseudo-Code of `$apply()` - *
+       * ```js
            function $apply(expr) {
              try {
                return $eval(expr);
@@ -12119,17 +12141,17 @@ function $RootScopeProvider(){
                $root.$digest();
              }
            }
-       * 
+ * ``` * * * Scope's `$apply()` method transitions through the following stages: * * 1. The {@link guide/expression expression} is executed using the - * {@link ng.$rootScope.Scope#methods_$eval $eval()} method. + * {@link ng.$rootScope.Scope#$eval $eval()} method. * 2. Any exceptions from the execution of the expression are forwarded to the * {@link ng.$exceptionHandler $exceptionHandler} service. - * 3. The {@link ng.$rootScope.Scope#methods_$watch watch} listeners are fired immediately after the - * expression was executed using the {@link ng.$rootScope.Scope#methods_$digest $digest()} method. + * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the + * expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method. * * * @param {(string|function())=} exp An angular expression to be executed. @@ -12157,13 +12179,12 @@ function $RootScopeProvider(){ }, /** - * @ngdoc function - * @name ng.$rootScope.Scope#$on - * @methodOf ng.$rootScope.Scope + * @ngdoc method + * @name $rootScope.Scope#$on * @function * * @description - * Listens on events of a given type. See {@link ng.$rootScope.Scope#methods_$emit $emit} for + * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for * discussion of event life cycle. * * The event listener function format is: `function(event, args...)`. The `event` object @@ -12180,7 +12201,7 @@ function $RootScopeProvider(){ * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called. * * @param {string} name Event name to listen on. - * @param {function(event, args...)} listener Function to call when the event is emitted. + * @param {function(event, ...args)} listener Function to call when the event is emitted. * @returns {function()} Returns a deregistration function for this listener. */ $on: function(name, listener) { @@ -12207,27 +12228,26 @@ function $RootScopeProvider(){ /** - * @ngdoc function - * @name ng.$rootScope.Scope#$emit - * @methodOf ng.$rootScope.Scope + * @ngdoc method + * @name $rootScope.Scope#$emit * @function * * @description * Dispatches an event `name` upwards through the scope hierarchy notifying the - * registered {@link ng.$rootScope.Scope#methods_$on} listeners. + * registered {@link ng.$rootScope.Scope#$on} listeners. * * The event life cycle starts at the scope on which `$emit` was called. All - * {@link ng.$rootScope.Scope#methods_$on listeners} listening for `name` event on this scope get + * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get * notified. Afterwards, the event traverses upwards toward the root scope and calls all * registered listeners along the way. The event will stop propagating if one of the listeners * cancels it. * - * Any exception emitted from the {@link ng.$rootScope.Scope#methods_$on listeners} will be passed + * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed * onto the {@link ng.$exceptionHandler $exceptionHandler} service. * * @param {string} name Event name to emit. * @param {...*} args Optional one or more arguments which will be passed onto the event listeners. - * @return {Object} Event object (see {@link ng.$rootScope.Scope#methods_$on}). + * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}). */ $emit: function(name, args) { var empty = [], @@ -12276,26 +12296,25 @@ function $RootScopeProvider(){ /** - * @ngdoc function - * @name ng.$rootScope.Scope#$broadcast - * @methodOf ng.$rootScope.Scope + * @ngdoc method + * @name $rootScope.Scope#$broadcast * @function * * @description * Dispatches an event `name` downwards to all child scopes (and their children) notifying the - * registered {@link ng.$rootScope.Scope#methods_$on} listeners. + * registered {@link ng.$rootScope.Scope#$on} listeners. * * The event life cycle starts at the scope on which `$broadcast` was called. All - * {@link ng.$rootScope.Scope#methods_$on listeners} listening for `name` event on this scope get + * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get * notified. Afterwards, the event propagates to all direct and indirect scopes of the current * scope and calls all registered listeners along the way. The event cannot be canceled. * - * Any exception emitted from the {@link ng.$rootScope.Scope#methods_$on listeners} will be passed + * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed * onto the {@link ng.$exceptionHandler $exceptionHandler} service. * * @param {string} name Event name to broadcast. * @param {...*} args Optional one or more arguments which will be passed onto the event listeners. - * @return {Object} Event object, see {@link ng.$rootScope.Scope#methods_$on} + * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on} */ $broadcast: function(name, args) { var target = this, @@ -12526,7 +12545,7 @@ function adjustMatchers(matchers) { /** * @ngdoc service - * @name ng.$sceDelegate + * @name $sceDelegate * @function * * @description @@ -12546,21 +12565,21 @@ function adjustMatchers(matchers) { * can override it completely to change the behavior of `$sce`, the common case would * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as - * templates. Refer {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist + * templates. Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist * $sceDelegateProvider.resourceUrlWhitelist} and {@link - * ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} + * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} */ /** - * @ngdoc object - * @name ng.$sceDelegateProvider + * @ngdoc provider + * @name $sceDelegateProvider * @description * * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate * $sceDelegate} service. This allows one to get/set the whitelists and blacklists used to ensure * that the URLs used for sourcing Angular templates are safe. Refer {@link - * ng.$sceDelegateProvider#methods_resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and - * {@link ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} + * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and + * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} * * For the general details about this service in Angular, read the main page for {@link ng.$sce * Strict Contextual Escaping (SCE)}. @@ -12597,9 +12616,8 @@ function $SceDelegateProvider() { resourceUrlBlacklist = []; /** - * @ngdoc function - * @name ng.sceDelegateProvider#resourceUrlWhitelist - * @methodOf ng.$sceDelegateProvider + * @ngdoc method + * @name $sceDelegateProvider#resourceUrlWhitelist * @function * * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value @@ -12627,9 +12645,8 @@ function $SceDelegateProvider() { }; /** - * @ngdoc function - * @name ng.sceDelegateProvider#resourceUrlBlacklist - * @methodOf ng.$sceDelegateProvider + * @ngdoc method + * @name $sceDelegateProvider#resourceUrlBlacklist * @function * * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value @@ -12732,8 +12749,7 @@ function $SceDelegateProvider() { /** * @ngdoc method - * @name ng.$sceDelegate#trustAs - * @methodOf ng.$sceDelegate + * @name $sceDelegate#trustAs * * @description * Returns an object that is trusted by angular for use in specified strict @@ -12770,20 +12786,19 @@ function $SceDelegateProvider() { /** * @ngdoc method - * @name ng.$sceDelegate#valueOf - * @methodOf ng.$sceDelegate + * @name $sceDelegate#valueOf * * @description - * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#methods_trustAs + * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link - * ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}. + * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. * * If the passed parameter is not a value that had been returned by {@link - * ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}, returns it as-is. + * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is. * - * @param {*} value The result of a prior {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`} + * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} * call or anything else. - * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#methods_trustAs + * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs * `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns * `value` unchanged. */ @@ -12797,18 +12812,17 @@ function $SceDelegateProvider() { /** * @ngdoc method - * @name ng.$sceDelegate#getTrusted - * @methodOf ng.$sceDelegate + * @name $sceDelegate#getTrusted * * @description - * Takes the result of a {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`} call and + * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and * returns the originally supplied value if the queried context type is a supertype of the * created type. If this condition isn't satisfied, throws an exception. * * @param {string} type The kind of context in which this value is to be used. - * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#methods_trustAs + * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs * `$sceDelegate.trustAs`} call. - * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#methods_trustAs + * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs * `$sceDelegate.trustAs`} if valid in this context. Otherwise, throws an exception. */ function getTrusted(type, maybeTrusted) { @@ -12844,8 +12858,8 @@ function $SceDelegateProvider() { /** - * @ngdoc object - * @name ng.$sceProvider + * @ngdoc provider + * @name $sceProvider * @description * * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service. @@ -12859,7 +12873,7 @@ function $SceDelegateProvider() { /** * @ngdoc service - * @name ng.$sce + * @name $sce * @function * * @description @@ -12913,20 +12927,20 @@ function $SceDelegateProvider() { * allowing only the files in a specific directory to do this. Ensuring that the internal API * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task. * - * In the case of AngularJS' SCE service, one uses {@link ng.$sce#methods_trustAs $sce.trustAs} - * (and shorthand methods such as {@link ng.$sce#methods_trustAsHtml $sce.trustAsHtml}, etc.) to + * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs} + * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to * obtain values that will be accepted by SCE / privileged contexts. * * * ## How does it work? * - * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#methods_getTrusted + * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted * $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link - * ng.$sce#methods_parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the - * {@link ng.$sce#methods_getTrusted $sce.getTrusted} behind the scenes on non-constant literals. + * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the + * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals. * * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link - * ng.$sce#methods_parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly + * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly * simplified): * *
@@ -12945,15 +12959,15 @@ function $SceDelegateProvider() {
  * `templateUrl`'s specified by {@link guide/directive directives}.
  *
  * By default, Angular only loads templates from the same domain and protocol as the application
- * document.  This is done by calling {@link ng.$sce#methods_getTrustedResourceUrl
+ * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
  * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
- * protocols, you may either either {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelist
- * them} or {@link ng.$sce#methods_trustAsResourceUrl wrap it} into a trusted value.
+ * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
+ * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
  *
  * *Please note*:
  * The browser's
- * {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
- * Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing (CORS)}
+ * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
+ * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
  * policy apply in addition to this and may further restrict whether the template is successfully
  * loaded.  This means that without the right CORS policy, loading templates from a different domain
  * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
@@ -12968,14 +12982,14 @@ function $SceDelegateProvider() {
  * `
`) just works. * * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them - * through {@link ng.$sce#methods_getTrusted $sce.getTrusted}. SCE doesn't play a role here. + * through {@link ng.$sce#getTrusted $sce.getTrusted}. SCE doesn't play a role here. * * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load * templates in `ng-include` from your application's domain without having to even know about SCE. * It blocks loading templates from other domains or loading templates over http from an https * served document. You can change these by setting your own custom {@link - * ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelists} and {@link - * ng.$sceDelegateProvider#methods_resourceUrlBlacklist blacklists} for matching such URLs. + * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link + * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs. * * This significantly reduces the overhead. It is far easier to pay the small overhead and have an * application that's secure and can be audited to verify that with much more ease than bolting @@ -12988,11 +13002,11 @@ function $SceDelegateProvider() { * |---------------------|----------------| * | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. | * | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. | - * | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`
Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. | * | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently unused. Feel free to use it in your own directives. | * - * ## Format of items in {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#methods_resourceUrlBlacklist Blacklist}
+ * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} * * Each element in these arrays must be one of the following: * @@ -13004,10 +13018,10 @@ function $SceDelegateProvider() { * being tested (substring matches are not good enough.) * - There are exactly **two wildcard sequences** - `*` and `**`. All other characters * match themselves. - * - `*`: matches zero or more occurances of any character other than one of the following 6 + * - `*`: matches zero or more occurrences of any character other than one of the following 6 * characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'. It's a useful wildcard for use * in a whitelist. - * - `**`: matches zero or more occurances of *any* character. As such, it's not + * - `**`: matches zero or more occurrences of *any* character. As such, it's not * not appropriate to use in for a scheme, domain, etc. as it would match too much. (e.g. * http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might * not have been the intention.) It's usage at the very end of the path is ok. (e.g. @@ -13086,7 +13100,7 @@ function $SceDelegateProvider() { ] - + describe('SCE doc demo', function() { it('should sanitize untrusted values', function() { expect(element(by.css('.htmlComment')).getInnerHtml()) @@ -13129,9 +13143,8 @@ function $SceProvider() { var enabled = true; /** - * @ngdoc function - * @name ng.sceProvider#enabled - * @methodOf ng.$sceProvider + * @ngdoc method + * @name $sceProvider#enabled * @function * * @param {boolean=} value If provided, then enables/disables SCE. @@ -13208,9 +13221,8 @@ function $SceProvider() { var sce = copy(SCE_CONTEXTS); /** - * @ngdoc function - * @name ng.sce#isEnabled - * @methodOf ng.$sce + * @ngdoc method + * @name $sce#isEnabled * @function * * @return {Boolean} true if SCE is enabled, false otherwise. If you want to set the value, you @@ -13233,13 +13245,12 @@ function $SceProvider() { /** * @ngdoc method - * @name ng.$sce#parse - * @methodOf ng.$sce + * @name $sce#parse * * @description * Converts Angular {@link guide/expression expression} into a function. This is like {@link * ng.$parse $parse} and is identical when the expression is a literal constant. Otherwise, it - * wraps the expression in a call to {@link ng.$sce#methods_getTrusted $sce.getTrusted(*type*, + * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*, * *result*)} * * @param {string} type The kind of SCE context in which this result will be used. @@ -13264,11 +13275,10 @@ function $SceProvider() { /** * @ngdoc method - * @name ng.$sce#trustAs - * @methodOf ng.$sce + * @name $sce#trustAs * * @description - * Delegates to {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}. As such, + * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. As such, * returns an object that is trusted by angular for use in specified strict contextual * escaping contexts (such as ng-bind-html, ng-include, any src attribute * interpolation, any dom event binding attribute interpolation such as for onclick, etc.) @@ -13284,95 +13294,89 @@ function $SceProvider() { /** * @ngdoc method - * @name ng.$sce#trustAsHtml - * @methodOf ng.$sce + * @name $sce#trustAsHtml * * @description * Shorthand method. `$sce.trustAsHtml(value)` → - * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.HTML, value)`} + * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`} * * @param {*} value The value to trustAs. - * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedHtml + * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml * $sce.getTrustedHtml(value)} to obtain the original value. (privileged directives * only accept expressions that are either literal constants or are the - * return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.) + * return value of {@link ng.$sce#trustAs $sce.trustAs}.) */ /** * @ngdoc method - * @name ng.$sce#trustAsUrl - * @methodOf ng.$sce + * @name $sce#trustAsUrl * * @description * Shorthand method. `$sce.trustAsUrl(value)` → - * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.URL, value)`} + * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`} * * @param {*} value The value to trustAs. - * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedUrl + * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl * $sce.getTrustedUrl(value)} to obtain the original value. (privileged directives * only accept expressions that are either literal constants or are the - * return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.) + * return value of {@link ng.$sce#trustAs $sce.trustAs}.) */ /** * @ngdoc method - * @name ng.$sce#trustAsResourceUrl - * @methodOf ng.$sce + * @name $sce#trustAsResourceUrl * * @description * Shorthand method. `$sce.trustAsResourceUrl(value)` → - * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`} + * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`} * * @param {*} value The value to trustAs. - * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedResourceUrl + * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl * $sce.getTrustedResourceUrl(value)} to obtain the original value. (privileged directives * only accept expressions that are either literal constants or are the return - * value of {@link ng.$sce#methods_trustAs $sce.trustAs}.) + * value of {@link ng.$sce#trustAs $sce.trustAs}.) */ /** * @ngdoc method - * @name ng.$sce#trustAsJs - * @methodOf ng.$sce + * @name $sce#trustAsJs * * @description * Shorthand method. `$sce.trustAsJs(value)` → - * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.JS, value)`} + * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`} * * @param {*} value The value to trustAs. - * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedJs + * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs * $sce.getTrustedJs(value)} to obtain the original value. (privileged directives * only accept expressions that are either literal constants or are the - * return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.) + * return value of {@link ng.$sce#trustAs $sce.trustAs}.) */ /** * @ngdoc method - * @name ng.$sce#getTrusted - * @methodOf ng.$sce + * @name $sce#getTrusted * * @description - * Delegates to {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted`}. As such, - * takes the result of a {@link ng.$sce#methods_trustAs `$sce.trustAs`}() call and returns the + * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}. As such, + * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the * originally supplied value if the queried context type is a supertype of the created type. * If this condition isn't satisfied, throws an exception. * * @param {string} type The kind of context in which this value is to be used. - * @param {*} maybeTrusted The result of a prior {@link ng.$sce#methods_trustAs `$sce.trustAs`} + * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`} * call. * @returns {*} The value the was originally provided to - * {@link ng.$sce#methods_trustAs `$sce.trustAs`} if valid in this context. + * {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context. * Otherwise, throws an exception. */ /** * @ngdoc method - * @name ng.$sce#getTrustedHtml - * @methodOf ng.$sce + * @name $sce#getTrustedHtml * * @description * Shorthand method. `$sce.getTrustedHtml(value)` → - * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`} + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`} * * @param {*} value The value to pass to `$sce.getTrusted`. * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)` @@ -13380,12 +13384,11 @@ function $SceProvider() { /** * @ngdoc method - * @name ng.$sce#getTrustedCss - * @methodOf ng.$sce + * @name $sce#getTrustedCss * * @description * Shorthand method. `$sce.getTrustedCss(value)` → - * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`} + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`} * * @param {*} value The value to pass to `$sce.getTrusted`. * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)` @@ -13393,12 +13396,11 @@ function $SceProvider() { /** * @ngdoc method - * @name ng.$sce#getTrustedUrl - * @methodOf ng.$sce + * @name $sce#getTrustedUrl * * @description * Shorthand method. `$sce.getTrustedUrl(value)` → - * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.URL, value)`} + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`} * * @param {*} value The value to pass to `$sce.getTrusted`. * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)` @@ -13406,12 +13408,11 @@ function $SceProvider() { /** * @ngdoc method - * @name ng.$sce#getTrustedResourceUrl - * @methodOf ng.$sce + * @name $sce#getTrustedResourceUrl * * @description * Shorthand method. `$sce.getTrustedResourceUrl(value)` → - * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`} + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`} * * @param {*} value The value to pass to `$sceDelegate.getTrusted`. * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)` @@ -13419,12 +13420,11 @@ function $SceProvider() { /** * @ngdoc method - * @name ng.$sce#getTrustedJs - * @methodOf ng.$sce + * @name $sce#getTrustedJs * * @description * Shorthand method. `$sce.getTrustedJs(value)` → - * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.JS, value)`} + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`} * * @param {*} value The value to pass to `$sce.getTrusted`. * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)` @@ -13432,12 +13432,11 @@ function $SceProvider() { /** * @ngdoc method - * @name ng.$sce#parseAsHtml - * @methodOf ng.$sce + * @name $sce#parseAsHtml * * @description * Shorthand method. `$sce.parseAsHtml(expression string)` → - * {@link ng.$sce#methods_parse `$sce.parseAs($sce.HTML, value)`} + * {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`} * * @param {string} expression String expression to compile. * @returns {function(context, locals)} a function which represents the compiled expression: @@ -13450,12 +13449,11 @@ function $SceProvider() { /** * @ngdoc method - * @name ng.$sce#parseAsCss - * @methodOf ng.$sce + * @name $sce#parseAsCss * * @description * Shorthand method. `$sce.parseAsCss(value)` → - * {@link ng.$sce#methods_parse `$sce.parseAs($sce.CSS, value)`} + * {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`} * * @param {string} expression String expression to compile. * @returns {function(context, locals)} a function which represents the compiled expression: @@ -13468,12 +13466,11 @@ function $SceProvider() { /** * @ngdoc method - * @name ng.$sce#parseAsUrl - * @methodOf ng.$sce + * @name $sce#parseAsUrl * * @description * Shorthand method. `$sce.parseAsUrl(value)` → - * {@link ng.$sce#methods_parse `$sce.parseAs($sce.URL, value)`} + * {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`} * * @param {string} expression String expression to compile. * @returns {function(context, locals)} a function which represents the compiled expression: @@ -13486,12 +13483,11 @@ function $SceProvider() { /** * @ngdoc method - * @name ng.$sce#parseAsResourceUrl - * @methodOf ng.$sce + * @name $sce#parseAsResourceUrl * * @description * Shorthand method. `$sce.parseAsResourceUrl(value)` → - * {@link ng.$sce#methods_parse `$sce.parseAs($sce.RESOURCE_URL, value)`} + * {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`} * * @param {string} expression String expression to compile. * @returns {function(context, locals)} a function which represents the compiled expression: @@ -13504,12 +13500,11 @@ function $SceProvider() { /** * @ngdoc method - * @name ng.$sce#parseAsJs - * @methodOf ng.$sce + * @name $sce#parseAsJs * * @description * Shorthand method. `$sce.parseAsJs(value)` → - * {@link ng.$sce#methods_parse `$sce.parseAs($sce.JS, value)`} + * {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`} * * @param {string} expression String expression to compile. * @returns {function(context, locals)} a function which represents the compiled expression: @@ -13545,7 +13540,7 @@ function $SceProvider() { /** * !!! This is an undocumented "private" service !!! * - * @name ng.$sniffer + * @name $sniffer * @requires $window * @requires $document * @@ -13641,9 +13636,8 @@ function $TimeoutProvider() { /** - * @ngdoc function - * @name ng.$timeout - * @requires $browser + * @ngdoc service + * @name $timeout * * @description * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch @@ -13661,10 +13655,10 @@ function $TimeoutProvider() { * @param {function()} fn A function, whose execution should be delayed. * @param {number=} [delay=0] Delay in milliseconds. * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise - * will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block. + * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this * promise will be resolved with is the return value of the `fn` function. - * + * */ function timeout(fn, delay, invokeApply) { var deferred = $q.defer(), @@ -13694,9 +13688,8 @@ function $TimeoutProvider() { /** - * @ngdoc function - * @name ng.$timeout#cancel - * @methodOf ng.$timeout + * @ngdoc method + * @name $timeout#cancel * * @description * Cancels a task associated with the `promise`. As a result of this, the promise will be @@ -13823,8 +13816,8 @@ function urlIsSameOrigin(requestUrl) { } /** - * @ngdoc object - * @name ng.$window + * @ngdoc service + * @name $window * * @description * A reference to the browser's `window` object. While `window` @@ -13838,8 +13831,8 @@ function urlIsSameOrigin(requestUrl) { * expression. * * @example - - + + -
+ + userType: Required!
userType = {{userType}}
@@ -15661,8 +15731,8 @@ function FormController(element, attrs) { myForm.$valid = {{myForm.$valid}}
myForm.$error.required = {{!!myForm.$error.required}}
-
- +
+ it('should initialize to model', function() { var userType = element(by.binding('userType')); var valid = element(by.binding('myForm.input.$valid')); @@ -15682,8 +15752,11 @@ function FormController(element, attrs) { expect(userType.getText()).toEqual('userType ='); expect(valid.getText()).toContain('false'); }); - - + + + * + * @param {string=} name Name of the form. If specified, the form controller will be published into + * related scope, under this name. */ var formDirectiveFactory = function(isNgForm) { return ['$timeout', function($timeout) { @@ -15756,12 +15829,17 @@ var ngFormDirective = formDirectiveFactory(true); var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/; var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i; var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/; +var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/; +var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)$/; +var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/; +var MONTH_REGEXP = /^(\d{4})-(\d\d)$/; +var TIME_REGEXP = /^(\d\d):(\d\d)$/; var inputType = { /** - * @ngdoc inputType - * @name ng.directive:input.text + * @ngdoc input + * @name input[text] * * @description * Standard HTML text input with angular data binding. @@ -15784,8 +15862,8 @@ var inputType = { * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. * * @example - - + + +
+ Pick a date between in 2013: + + + Required! + + Not a valid date! + value = {{value | date: "yyyy-MM-dd"}}
+ myForm.input.$valid = {{myForm.input.$valid}}
+ myForm.input.$error = {{myForm.input.$error}}
+ myForm.$valid = {{myForm.$valid}}
+ myForm.$error.required = {{!!myForm.$error.required}}
+
+
+ + var value = element(by.binding('value | date: "yyyy-MM-dd"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (see https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2013-10-22'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-01-01'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
f + */ + 'date': createDateInputType('date', DATE_REGEXP, + createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']), + 'yyyy-MM-dd'), + + /** + * @ngdoc input + * @name input[dateTimeLocal] + * + * @description + * Input with datetime validation and transformation. In browsers that do not yet support + * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * local datetime format (yyyy-MM-ddTHH:mm), for example: `2010-12-28T14:57`. The model must be a Date object. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a + * valid ISO datetime format (yyyy-MM-ddTHH:mm). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be + * a valid ISO datetime format (yyyy-MM-ddTHH:mm). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
+ Pick a date between in 2013: + + + Required! + + Not a valid date! + value = {{value | date: "yyyy-MM-ddTHH:mm"}}
+ myForm.input.$valid = {{myForm.input.$valid}}
+ myForm.input.$error = {{myForm.input.$error}}
+ myForm.$valid = {{myForm.$valid}}
+ myForm.$error.required = {{!!myForm.$error.required}}
+
+
+ + var value = element(by.binding('value | date: "yyyy-MM-ddTHH:mm"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2010-12-28T14:57'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-01-01T23:59'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
+ */ + 'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP, + createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm']), + 'yyyy-MM-ddTHH:mm'), /** - * @ngdoc inputType - * @name ng.directive:input.number + * @ngdoc input + * @name input[time] + * + * @description + * Input with time validation and transformation. In browsers that do not yet support + * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * local time format (HH:mm), for example: `14:57`. Model must be a Date object. This binding will always output a + * Date object to the model of January 1, 1900, or local date `new Date(0, 0, 1, HH, mm)`. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a + * valid ISO time format (HH:mm). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be a + * valid ISO time format (HH:mm). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
+ Pick a between 8am and 5pm: + + + Required! + + Not a valid date! + value = {{value | date: "HH:mm"}}
+ myForm.input.$valid = {{myForm.input.$valid}}
+ myForm.input.$error = {{myForm.input.$error}}
+ myForm.$valid = {{myForm.$valid}}
+ myForm.$error.required = {{!!myForm.$error.required}}
+
+
+ + var value = element(by.binding('value | date: "HH:mm"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('14:57'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('23:59'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
+ */ + 'time': createDateInputType('time', TIME_REGEXP, + createDateParser(TIME_REGEXP, ['HH', 'mm']), + 'HH:mm'), + + /** + * @ngdoc input + * @name input[week] + * + * @description + * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support + * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * week format (yyyy-W##), for example: `2013-W02`. The model must always be a Date object. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a + * valid ISO week format (yyyy-W##). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be + * a valid ISO week format (yyyy-W##). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
+ Pick a date between in 2013: + + + Required! + + Not a valid date! + value = {{value | date: "yyyy-Www"}}
+ myForm.input.$valid = {{myForm.input.$valid}}
+ myForm.input.$error = {{myForm.input.$error}}
+ myForm.$valid = {{myForm.$valid}}
+ myForm.$error.required = {{!!myForm.$error.required}}
+
+
+ + var value = element(by.binding('value | date: "yyyy-Www"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2013-W01'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-W01'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
+ */ + 'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'), + + /** + * @ngdoc input + * @name input[month] + * + * @description + * Input with month validation and transformation. In browsers that do not yet support + * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * month format (yyyy-MM), for example: `2009-01`. The model must always be a Date object. In the event the model is + * not set to the first of the month, the first of that model's month is assumed. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be + * a valid ISO month format (yyyy-MM). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must + * be a valid ISO month format (yyyy-MM). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
+ Pick a month int 2013: + + + Required! + + Not a valid month! + value = {{value | date: "yyyy-MM"}}
+ myForm.input.$valid = {{myForm.input.$valid}}
+ myForm.input.$error = {{myForm.input.$error}}
+ myForm.$valid = {{myForm.$valid}}
+ myForm.$error.required = {{!!myForm.$error.required}}
+
+
+ + var value = element(by.binding('value | date: "yyyy-MM"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2013-10'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-01'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
+ */ + 'month': createDateInputType('month', MONTH_REGEXP, + createDateParser(MONTH_REGEXP, ['yyyy', 'MM']), + 'yyyy-MM'), + + /** + * @ngdoc input + * @name input[number] * * @description * Text input with number validation and transformation. Sets the `number` validation @@ -15864,8 +16361,8 @@ var inputType = { * interaction with the input element. * * @example - - + + + + Update input to see transitions when valid/invalid. + Integer is a valid value. +
+ +
+
+ *
*/ var ngModelDirective = function() { return { @@ -16996,7 +17683,7 @@ var ngModelDirective = function() { /** * @ngdoc directive - * @name ng.directive:ngChange + * @name ngChange * * @description * Evaluate the given expression when the user changes the input. @@ -17012,8 +17699,8 @@ var ngModelDirective = function() { * in input value. * * @example - * - * + * + * * Load inlined template
-
- +
+ it('should load template defined inside script tag', function() { element(by.css('#tpl-link')).click(); expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/); }); - - + + */ var scriptDirective = ['$templateCache', function($templateCache) { return { @@ -20227,7 +20958,7 @@ var scriptDirective = ['$templateCache', function($templateCache) { var ngOptionsMinErr = minErr('ngOptions'); /** * @ngdoc directive - * @name ng.directive:select + * @name select * @restrict E * * @description @@ -20245,7 +20976,7 @@ var ngOptionsMinErr = minErr('ngOptions'); * *
* **Note:** `ngModel` compares by reference, not value. This is important when binding to an - * array of objects. See an example {@link http://jsfiddle.net/qWzTb/ in this jsfiddle}. + * array of objects. See an example [in this jsfiddle](http://jsfiddle.net/qWzTb/). *
* * Optionally, a single hard-coded `